Skip to content

Commit

Permalink
Add RESTful API endpoints for customizing Groups
Browse files Browse the repository at this point in the history
Read-write access for group owners, read-only access for all other
members of a group, and no access for non-members.
  • Loading branch information
victorlin committed Sep 27, 2022
1 parent 01e4990 commit 8546855
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ const {
deleteNarrative,
} = endpoints.sources;

const {
getGroupLogo,
putGroupLogo,
deleteGroupLogo,
getGroupOverview,
putGroupOverview,
deleteGroupOverview,
} = endpoints.groups;

const {
CoreSource,
CoreStagingSource,
Expand Down Expand Up @@ -305,6 +314,18 @@ app.routeAsync("/groups/:groupName")
app.use("/groups/:groupName/settings",
endpoints.groups.setGroup(req => req.params.groupName));

app.routeAsync("/groups/:groupName/settings/logo")
.getAsync(getGroupLogo)
.putAsync(putGroupLogo)
.deleteAsync(deleteGroupLogo)
;

app.routeAsync("/groups/:groupName/settings/overview")
.getAsync(getGroupOverview)
.putAsync(putGroupOverview)
.deleteAsync(deleteGroupOverview)
;

app.route("/groups/:groupName/settings/*")
.all(() => { throw new NotFound(); });

Expand Down
143 changes: 143 additions & 0 deletions src/endpoints/groups.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as authz from "../authz/index.js";
import { Group } from "../groups.js";
import {contentTypesProvided, contentTypesConsumed} from "../negotiate.js";
import {deleteByUrls, proxyFromUpstream, proxyToUpstream} from "../upstream.js";


const setGroup = (nameExtractor) => (req, res, next) => {
Expand All @@ -12,6 +14,147 @@ const setGroup = (nameExtractor) => (req, res, next) => {
};


/* Group customizations
*/


/* Group logo
*/


/* GET
*/
const getGroupLogo = contentTypesProvided([
["image/png", sendGroupLogo],
]);


/* PUT
*/
const putGroupLogo = contentTypesConsumed([
["image/png", receiveGroupLogo],
]);


/* DELETE
*/
const deleteGroupLogo = async (req, res) => {
authz.assertAuthorized(req.user, authz.actions.Write, req.context.group);

const method = "DELETE";
const url = await req.context.group.source.urlFor("group-logo.png", method);
await deleteByUrls([url]);

return res.status(204).end();
};


/* Group overview
*/


/* GET
*/
const getGroupOverview = contentTypesProvided([
["text/markdown", sendGroupOverview],
["text/plain", sendGroupOverview],
]);


/* PUT
*/
const putGroupOverview = contentTypesConsumed([
["text/markdown", receiveGroupOverview],
]);


/* DELETE
*/
const deleteGroupOverview = async (req, res) => {
authz.assertAuthorized(req.user, authz.actions.Write, req.context.group);

const method = "DELETE";
const url = await req.context.group.source.urlFor("group-overview.md", method);
await deleteByUrls([url]);

return res.status(204).end();
};


/**
* An Express endpoint that sends a group overview determined by the request.
*
* @param {express.request} req - Express-style request instance
* @param {express.response} res - Express-style response instance
* @returns {expressEndpointAsync}
*/
async function sendGroupOverview(req, res) {
authz.assertAuthorized(req.user, authz.actions.Read, req.context.group);

return await proxyFromUpstream(req, res,
await req.context.group.source.urlFor("group-overview.md"),
"text/markdown"
);
}


/**
* An Express endpoint that receives a group overview determined by the request.
*
* @param {express.request} req - Express-style request instance
* @param {express.response} res - Express-style response instance
* @returns {expressEndpointAsync}
*/
async function receiveGroupOverview(req, res) {
authz.assertAuthorized(req.user, authz.actions.Write, req.context.group);

return await proxyToUpstream(req, res,
async (method, headers) => await req.context.group.source.urlFor("group-overview.md", method, headers),
"text/markdown"
);
}


/**
* An Express endpoint that sends a group logo determined by the request.
*
* @param {express.request} req - Express-style request instance
* @param {express.response} res - Express-style response instance
* @returns {expressEndpointAsync}
*/
async function sendGroupLogo(req, res) {
authz.assertAuthorized(req.user, authz.actions.Read, req.context.group);

return await proxyFromUpstream(req, res,
await req.context.group.source.urlFor("group-logo.png"),
"image/png"
);
}


/**
* An Express endpoint that receives a group logo determined by the request.
*
* @param {express.request} req - Express-style request instance
* @param {express.response} res - Express-style response instance
* @returns {expressEndpointAsync}
*/
async function receiveGroupLogo(req, res) {
authz.assertAuthorized(req.user, authz.actions.Write, req.context.group);

return await proxyToUpstream(req, res,
async (method, headers) => await req.context.group.source.urlFor("group-logo.png", method, headers),
"image/png"
);
}


export {
setGroup,
getGroupLogo,
putGroupLogo,
deleteGroupLogo,
getGroupOverview,
putGroupOverview,
deleteGroupOverview,
};

0 comments on commit 8546855

Please sign in to comment.