fix: Enhance dataset controllers with user authentication checks and improve mail configuration
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 59s

This commit is contained in:
Kaimbacher 2025-11-13 11:02:00 +01:00
commit d44d08abcd
7 changed files with 204 additions and 48 deletions

View file

@ -76,23 +76,24 @@ export default class MailSettingsController {
public async sendTestMail({ response, auth }: HttpContext) {
const user = auth.user!;
const userEmail = user.email;
// let mailManager = await app.container.make('mail.manager');
// let iwas = mailManager.use();
// let iwas = mailManager.use();
// let test = mail.config.mailers.smtp();
if (!userEmail) {
return response.badRequest({ message: 'User email is not set. Please update your profile.' });
}
try {
await mail.send((message) => {
message
// .from(Config.get('mail.from.address'))
.from('tethys@geosphere.at')
.to(userEmail)
.subject('Test Email')
.html('<p>If you received this email, the email configuration seems to be correct.</p>');
});
await mail.send(
(message) => {
message
// .from(Config.get('mail.from.address'))
.from('tethys@geosphere.at')
.to(userEmail)
.subject('Test Email')
.html('<p>If you received this email, the email configuration seems to be correct.</p>');
});
return response.json({ success: true, message: 'Test email sent successfully' });
// return response.flash('Test email sent successfully!', 'message').redirect().back();

View file

@ -188,10 +188,16 @@ export default class DatasetsController {
}
}
public async approve({ request, inertia, response }: HttpContext) {
public async approve({ request, inertia, response, auth }: HttpContext) {
const id = request.param('id');
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
// $dataset = Dataset::with('user:id,login')->findOrFail($id);
const dataset = await Dataset.findOrFail(id);
const dataset = await Dataset.query().where('id', id).where('editor_id', user.id).firstOrFail();
const validStates = ['editor_accepted', 'rejected_reviewer'];
if (!validStates.includes(dataset.server_state)) {
@ -217,7 +223,7 @@ export default class DatasetsController {
});
}
public async approveUpdate({ request, response }: HttpContext) {
public async approveUpdate({ request, response, auth }: HttpContext) {
const approveDatasetSchema = vine.object({
reviewer_id: vine.number(),
});
@ -230,7 +236,11 @@ export default class DatasetsController {
throw error;
}
const id = request.param('id');
const dataset = await Dataset.findOrFail(id);
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const dataset = await Dataset.query().where('id', id).where('editor_id', user.id).firstOrFail();
const validStates = ['editor_accepted', 'rejected_reviewer'];
if (!validStates.includes(dataset.server_state)) {
@ -261,10 +271,15 @@ export default class DatasetsController {
}
}
public async reject({ request, inertia, response }: HttpContext) {
public async reject({ request, inertia, response, auth }: HttpContext) {
const id = request.param('id');
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const dataset = await Dataset.query()
.where('id', id)
.where('editor_id', user.id) // Ensure the user is the editor of the dataset
// .preload('titles')
// .preload('descriptions')
.preload('user', (builder) => {
@ -291,10 +306,15 @@ export default class DatasetsController {
public async rejectUpdate({ request, response, auth }: HttpContext) {
const authUser = auth.user!;
if (!authUser) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const id = request.param('id');
const dataset = await Dataset.query()
.where('id', id)
.where('editor_id', authUser.id) // Ensure the user is the editor of the dataset
.preload('user', (builder) => {
builder.select('id', 'login', 'email');
})
@ -377,9 +397,14 @@ export default class DatasetsController {
public async publish({ request, inertia, response, auth }: HttpContext) {
const id = request.param('id');
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const dataset = await Dataset.query()
.where('id', id)
.where('editor_id', user.id) // Ensure the user is the editor of the dataset
.preload('titles')
.preload('authors')
// .preload('persons', (builder) => {
@ -408,7 +433,7 @@ export default class DatasetsController {
});
}
public async publishUpdate({ request, response }: HttpContext) {
public async publishUpdate({ request, response, auth }: HttpContext) {
const publishDatasetSchema = vine.object({
publisher_name: vine.string().trim(),
});
@ -420,7 +445,12 @@ export default class DatasetsController {
throw error;
}
const id = request.param('id');
const dataset = await Dataset.findOrFail(id);
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const dataset = await Dataset.query().where('id', id).where('editor_id', user.id).firstOrFail();
// let test = await Dataset.getMax('publish_id');
// const maxPublishId = await Database.from('documents').max('publish_id as max_publish_id').first();
@ -446,10 +476,16 @@ export default class DatasetsController {
}
}
public async rejectToReviewer({ request, inertia, response }: HttpContext) {
public async rejectToReviewer({ request, inertia, response, auth }: HttpContext) {
const id = request.param('id');
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const dataset = await Dataset.query()
.where('id', id)
.where('editor_id', user.id) // Ensure the user is the editor of the dataset
.preload('reviewer', (builder) => {
builder.select('id', 'login', 'email');
})
@ -475,9 +511,14 @@ export default class DatasetsController {
public async rejectToReviewerUpdate({ request, response, auth }: HttpContext) {
const authUser = auth.user!;
if (!authUser) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const id = request.param('id');
const dataset = await Dataset.query()
.where('id', id)
.where('editor_id', authUser.id) // Ensure the user is the editor of the dataset
.preload('reviewer', (builder) => {
builder.select('id', 'login', 'email');
})
@ -558,10 +599,16 @@ export default class DatasetsController {
.toRoute('editor.dataset.list');
}
public async doiCreate({ request, inertia }: HttpContext) {
public async doiCreate({ request, inertia, auth, response }: HttpContext) {
const id = request.param('id');
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const dataset = await Dataset.query()
.where('id', id)
.where('editor_id', user.id) // Ensure the user is the editor of the dataset
.preload('titles')
.preload('descriptions')
// .preload('identifier')
@ -572,11 +619,18 @@ export default class DatasetsController {
});
}
public async doiStore({ request, response }: HttpContext) {
public async doiStore({ request, response, auth }: HttpContext) {
const dataId = request.param('publish_id');
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
// Load dataset with minimal required relationships
const dataset = await Dataset.query().where('publish_id', dataId).firstOrFail();
const dataset = await Dataset.query()
.where('editor_id', user.id) // Ensure the user is the editor of the dataset
.where('publish_id', dataId)
.firstOrFail();
const prefix = process.env.DATACITE_PREFIX || '';
const base_domain = process.env.BASE_DOMAIN || '';
@ -658,9 +712,17 @@ export default class DatasetsController {
public async show({}: HttpContext) {}
public async edit({ request, inertia, response }: HttpContext) {
public async edit({ request, inertia, response, auth }: HttpContext) {
const id = request.param('id');
const datasetQuery = Dataset.query().where('id', id);
// Check if user is authenticated
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
// Prefilter by both id AND editor_id to ensure user has permission to edit
const datasetQuery = Dataset.query().where('id', id).where('editor_id', user.id);
datasetQuery
.preload('titles', (query) => query.orderBy('id', 'asc'))
.preload('descriptions', (query) => query.orderBy('id', 'asc'))
@ -677,6 +739,7 @@ export default class DatasetsController {
query.orderBy('sort_order', 'asc'); // Sort by sort_order column
});
// This will throw 404 if editor_id does not match logged in user
const dataset = await datasetQuery.firstOrFail();
const validStates = ['editor_accepted', 'rejected_reviewer'];
if (!validStates.includes(dataset.server_state)) {
@ -750,11 +813,16 @@ export default class DatasetsController {
});
}
public async update({ request, response, session }: HttpContext) {
public async update({ request, response, session, auth }: HttpContext) {
// Get the dataset id from the route parameter
const datasetId = request.param('id');
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
// Retrieve the dataset and load its existing files
const dataset = await Dataset.findOrFail(datasetId);
const dataset = await Dataset.query().where('id', datasetId).where('editor_id', user.id).firstOrFail();
await dataset.load('files');
let trx: TransactionClientContract | null = null;
@ -763,7 +831,7 @@ export default class DatasetsController {
trx = await db.transaction();
// const user = (await User.find(auth.user?.id)) as User;
// await this.createDatasetAndAssociations(user, request, trx);
const dataset = await Dataset.findOrFail(datasetId);
// const dataset = await Dataset.findOrFail(datasetId);
// save the licenses
const licenses: number[] = request.input('licenses', []);
@ -949,10 +1017,15 @@ export default class DatasetsController {
}
}
public async categorize({ inertia, request, response }: HttpContext) {
public async categorize({ inertia, request, response, auth }: HttpContext) {
const id = request.param('id');
// Check if user is authenticated
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
// Preload dataset and its "collections" relation
const dataset = await Dataset.query().where('id', id).preload('collections').firstOrFail();
const dataset = await Dataset.query().where('id', id).where('editor_id', user.id).preload('collections').firstOrFail();
const validStates = ['editor_accepted', 'rejected_reviewer'];
if (!validStates.includes(dataset.server_state)) {
// session.flash('errors', 'Invalid server state!');
@ -980,10 +1053,15 @@ export default class DatasetsController {
});
}
public async categorizeUpdate({ request, response, session }: HttpContext) {
public async categorizeUpdate({ request, response, session, auth }: HttpContext) {
// Get the dataset id from the route parameter
const id = request.param('id');
const dataset = await Dataset.query().preload('files').where('id', id).firstOrFail();
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
// Retrieve the dataset and load its existing files
const dataset = await Dataset.query().preload('files').where('id', id).where('editor_id', user.id).firstOrFail();
const validStates = ['editor_accepted', 'rejected_reviewer'];
if (!validStates.includes(dataset.server_state)) {
@ -1188,7 +1266,7 @@ export default class DatasetsController {
}
// return cache.getDomDocument();
const xmlDocument : XMLBuilder | null = await serializer.toXmlDocument();
const xmlDocument: XMLBuilder | null = await serializer.toXmlDocument();
return xmlDocument;
}
}

View file

@ -824,13 +824,20 @@ export default class DatasetController {
};
// public async release({ params, view }) {
public async release({ request, inertia, response }: HttpContext) {
public async release({ request, inertia, response, auth }: HttpContext) {
const id = request.param('id');
const user = auth.user;
// Check if user is authenticated
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const dataset = await Dataset.query()
.preload('user', (builder) => {
builder.select('id', 'login');
})
.where('account_id', user.id) // Only fetch if user owns it
.where('id', id)
.firstOrFail();
@ -851,9 +858,20 @@ export default class DatasetController {
});
}
public async releaseUpdate({ request, response }: HttpContext) {
public async releaseUpdate({ request, response, auth }: HttpContext) {
const id = request.param('id');
const dataset = await Dataset.query().preload('files').where('id', id).firstOrFail();
const user = auth.user;
// Check if user is authenticated
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
const dataset = await Dataset.query()
.preload('files')
.where('id', id)
.where('account_id', user.id) // Only fetch if user owns it
.firstOrFail();
const validStates = ['inprogress', 'rejected_editor'];
if (!validStates.includes(dataset.server_state)) {
@ -933,7 +951,15 @@ export default class DatasetController {
public async edit({ request, inertia, response, auth }: HttpContext) {
const id = request.param('id');
const datasetQuery = Dataset.query().where('id', id);
const user = auth.user;
// Check if user is authenticated
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
// Prefilter by both id AND account_id
const datasetQuery = Dataset.query().where('id', id).where('account_id', user.id); // Only fetch if user owns it
datasetQuery
.preload('titles', (query) => query.orderBy('id', 'asc'))
.preload('descriptions', (query) => query.orderBy('id', 'asc'))
@ -949,8 +975,9 @@ export default class DatasetController {
.preload('files', (query) => {
query.orderBy('sort_order', 'asc'); // Sort by sort_order column
});
// This will throw 404 if dataset doesn't exist OR user doesn't own it
const dataset = await datasetQuery.firstOrFail();
const validStates = ['inprogress', 'rejected_editor'];
if (!validStates.includes(dataset.server_state)) {
// session.flash('errors', 'Invalid server state!');
@ -1014,11 +1041,30 @@ export default class DatasetController {
});
}
public async update({ request, response, session }: HttpContext) {
public async update({ request, response, session, auth }: HttpContext) {
// Get the dataset id from the route parameter
const datasetId = request.param('id');
// Retrieve the dataset and load its existing files
const dataset = await Dataset.findOrFail(datasetId);
const user = auth.user;
// Check if user is authenticated
if (!user) {
return response.flash('You must be logged in to update a dataset.', 'error').redirect().toRoute('app.login.show');
}
// Prefilter by both id AND account_id
const dataset = await Dataset.query()
.where('id', datasetId)
.where('account_id', user.id) // Only fetch if user owns it
.firstOrFail();
// // Check if the authenticated user is the owner of the dataset
// if (dataset.account_id !== user.id) {
// return response
// .flash(`Unauthorized access. You are not the owner of dataset with id ${id}.`, 'error')
// .redirect()
// .toRoute('dataset.list');
// }
await dataset.load('files');
// Accumulate the size of the already related files
// const preExistingFileSize = dataset.files.reduce((acc, file) => acc + file.fileSize, 0);
@ -1442,16 +1488,26 @@ export default class DatasetController {
}
}
public async delete({ request, inertia, response, session }: HttpContext) {
public async delete({ request, inertia, response, session, auth }: HttpContext) {
const id = request.param('id');
const user = auth.user;
// Check if user is authenticated
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
try {
// This will throw 404 if dataset doesn't exist OR user doesn't own it
const dataset = await Dataset.query()
.preload('user', (builder) => {
builder.select('id', 'login');
})
.where('id', id)
.where('account_id', user.id) // Only fetch if user owns it
.preload('files')
.firstOrFail();
const validStates = ['inprogress', 'rejected_editor'];
if (!validStates.includes(dataset.server_state)) {
// session.flash('errors', 'Invalid server state!');
@ -1476,9 +1532,27 @@ export default class DatasetController {
}
}
public async deleteUpdate({ params, session, response }: HttpContext) {
public async deleteUpdate({ params, session, response, auth }: HttpContext) {
try {
const dataset = await Dataset.query().where('id', params.id).preload('files').firstOrFail();
const user = auth.user;
if (!user) {
return response.flash('You must be logged in to edit a dataset.', 'error').redirect().toRoute('app.login.show');
}
// This will throw 404 if dataset doesn't exist OR user doesn't own it
const dataset = await Dataset.query()
.where('id', params.id)
.where('account_id', user.id) // Only fetch if user owns it
.preload('files')
.firstOrFail();
// // Check if the authenticated user is the owner of the dataset
// if (dataset.account_id !== user.id) {
// return response
// .flash(`Unauthorized access. You are not the owner of dataset with id ${params.id}.`, 'error')
// .redirect()
// .toRoute('dataset.list');
// }
const validStates = ['inprogress', 'rejected_editor'];
if (validStates.includes(dataset.server_state)) {