feat: add /sharelink/request endpoint

This commit is contained in:
KernelDeimos 2024-06-24 01:02:00 -04:00 committed by Eric Dubé
parent b0e067e4ae
commit 742f625309
4 changed files with 95 additions and 4 deletions

View File

@ -34,3 +34,15 @@ Comments beginning with `// track:`. See
or there's a common behavior that should happen
in between. The Sequence class is good for this so
it might be a worthy migration.
- `track: opposite condition of sibling`
A sibling class, function, method, or other construct of
source code has a boolean expression which always evaluates
to the opposite of the one below this track comment.
- `track: null check before processing`
An object could be undefined or null, additional processing
occurs after a null check, and the unprocessed object is not
relevant to the rest of the code. If the code for obtaining
the object and processing it is moved to a function outside,
then the null check should result in a early return of null;
this code with the track comment may have additional logic
for the null/undefined case.

View File

@ -462,6 +462,11 @@ module.exports = class APIError {
status: 422,
message: 'Email must be confirmed to apply a share.',
},
'no_need_to_request': {
status: 422,
message: 'This share is already valid for this user; ' +
'POST to /apply for access.'
},
'can_not_apply_to_this_user': {
status: 422,
message: 'This share can not be applied to this user.',

View File

@ -6,6 +6,7 @@ const { whatis } = require("../util/langutil");
const { Actor, UserActorType } = require("./auth/Actor");
const BaseService = require("./BaseService");
const { DB_WRITE } = require("./database/consts");
const { UsernameNotifSelector } = require("./NotificationService");
class ShareService extends BaseService {
static MODULES = {
@ -85,16 +86,16 @@ class ShareService extends BaseService {
uid: share_uid,
});
if ( ! share ) {
throw APIError.create('share_expired');
}
share.data = this.db.case({
mysql: () => share.data,
otherwise: () =>
JSON.parse(share.data ?? '{}'),
})();
if ( ! share ) {
throw APIError.create('share_expired');
}
const actor = Actor.adapt(req.actor ?? req.user);
if ( ! actor ) {
// this shouldn't happen; auth should catch it
@ -137,6 +138,74 @@ class ShareService extends BaseService {
});
}
}).attach(router);
Endpoint({
route: '/request',
methods: ['POST'],
mw: [configurable_auth()],
handler: async (req, res) => {
const share_uid = req.body.uid;
const share = await svc_share.get_share({
uid: share_uid,
});
// track: null check before processing
if ( ! share ) {
throw APIError.create('share_expired');
}
share.data = this.db.case({
mysql: () => share.data,
otherwise: () =>
JSON.parse(share.data ?? '{}'),
})();
const actor = Actor.adapt(req.actor ?? req.user);
if ( ! actor ) {
// this shouldn't happen; auth should catch it
throw new Error('actor missing');
}
// track: opposite condition of sibling
// :: sibling: /apply endpoint
if (
actor.type.user.email_confirmed &&
actor.type.user.email === share.recipient_email
) {
throw APIError.create('no_need_to_request');
}
const issuer_user = await get_user({
id: share.issuer_user_id,
});
if ( ! issuer_user ) {
throw APIError.create('share_expired');
}
const svc_notification = this.services.get('notification');
svc_notification.notify(
UsernameNotifSelector(issuer_user.username),
{
source: 'sharing',
title: `User ${actor.type.user.username} is ` +
`trying to open a share you sent to ` +
share.recipient_email,
template: 'user-requesting-share',
fields: {
username: actor.type.user.username,
intended_recipient: share.recipient_email,
permissions: share.data.permissions,
},
}
);
res.json({
$: 'api:status-report',
status: 'success',
});
}
}).attach(router);
}
async get_share ({ uid }) {

View File

@ -34,6 +34,11 @@ class DriverService extends BaseService {
this.interfaces = require('./interfaces');
this.interface_to_implementation = {};
}
_init () {
const svc_registry = this.services.get('registry');
svc_registry.register_collection('');
}
register_driver (interface_name, implementation) {
this.interface_to_implementation[interface_name] = implementation;