Unable to load author profile
+Please report this (FIXME: Add reporting capabilities)
+diff --git a/sites/backend/src/controllers/users.mjs b/sites/backend/src/controllers/users.mjs index 133230cf663..1b006f17576 100644 --- a/sites/backend/src/controllers/users.mjs +++ b/sites/backend/src/controllers/users.mjs @@ -105,6 +105,18 @@ UsersController.prototype.updateMfa = async (req, res, tools) => { return User.sendResponse(res) } +/* + * Returns a user profile + * + * See: https://freesewing.dev/reference/backend/api + */ +UsersController.prototype.profile = async (req, res, tools) => { + const User = new UserModel(tools) + await User.profile(req) + + return User.sendResponse(res) +} + /* * Checks whether a submitted username is available * diff --git a/sites/backend/src/models/flow.mjs b/sites/backend/src/models/flow.mjs index d11e1d0576d..c225caf47cd 100644 --- a/sites/backend/src/models/flow.mjs +++ b/sites/backend/src/models/flow.mjs @@ -133,9 +133,9 @@ FlowModel.prototype.uploadImage = async function ({ body, user }) { if (Object.keys(body).length < 1) return this.setResponse(400, 'postBodyMissing') /* - * Is img set? + * Is img or url set? */ - if (!body.img) return this.setResponse(400, 'imgMissing') + if (!body.img && !body.url) return this.setResponse(400, 'imgOrUrlMissing') /* * Is type set and valid? @@ -156,21 +156,21 @@ FlowModel.prototype.uploadImage = async function ({ body, user }) { if (!body.slug) return this.setResponse(400, 'slugMissing') /* - * Upload the image + * Prepare data for uploading the image */ - const id = `${body.type}-${body.slug}${ - body.subId && body.subId !== 'main' ? '-' + body.subId : '' - }` - const b64 = body.img - const metadata = { uploadedBy: user.uid } + const data = { + id: `${body.type}-${body.slug}${body.subId && body.subId !== 'main' ? '-' + body.subId : ''}`, + metadata: { uploadedBy: user.uid }, + } + if (body.img) data.b64 = body.img + else if (body.url) data.url = body.url + /* * You need to be a curator to overwrite (replace) an image. * Regular users can only update new images, not overwrite images. * If not, any user could overwrite any showcase image. */ - const imgId = this.rbac.curator(user) - ? await replaceImage({ b64, id, metadata }) - : await ensureImage({ b64, id, metadata }) + const imgId = this.rbac.curator(user) ? await replaceImage(data) : await ensureImage(data) /* * Return 200 and the image ID diff --git a/sites/backend/src/models/user.mjs b/sites/backend/src/models/user.mjs index 6f91bde2cff..753c680cc32 100644 --- a/sites/backend/src/models/user.mjs +++ b/sites/backend/src/models/user.mjs @@ -16,6 +16,40 @@ export function UserModel(tools) { }) } +/* + * Loads a user from the database based on the where clause you pass it + * In addition prepares it for returning the account data + * This is guarded so it enforces access control and validates input + * This is an anonymous route returning limited info (profile data) + * + * @param {params} object - The request (URL) parameters + * @returns {UserModel} object - The UserModel + */ +UserModel.prototype.profile = async function ({ params }) { + /* + * Is id set? + */ + if (typeof params.id === 'undefined') return this.setResponse(403, 'idMissing') + + /* + * Try to find the record in the database + * Note that find checks lusername, ehash, and id but we + * pass it in the username value as that's what the login + * rout does + */ + await this.find({ username: params.id }) + + /* + * If it does not exist, return 404 + */ + if (!this.exists) return this.setResponse(404) + + return this.setResponse200({ + result: 'success', + profile: this.asProfile(), + }) +} + /* * Loads a user from the database based on the where clause you pass it * In addition prepares it for returning the account data @@ -1118,6 +1152,25 @@ UserModel.prototype.guardedMfaUpdate = async function ({ body, user, ip }) { return this.setResponse(400, 'invalidMfaSetting') } +/* + * Returns the database record as profile data for public consumption + * + * @return {account} object - The account data as a plain object + */ +UserModel.prototype.asProfile = function () { + /* + * Nothing to do here but construct the object to return + */ + return { + id: this.record.id, + bio: this.clear.bio, + img: this.clear.img, + patron: this.record.patron, + role: this.record.role, + username: this.record.username, + } +} + /* * Returns the database record as account data for for consumption * diff --git a/sites/backend/src/routes/users.mjs b/sites/backend/src/routes/users.mjs index 4742604a1e9..2f3c73c517d 100644 --- a/sites/backend/src/routes/users.mjs +++ b/sites/backend/src/routes/users.mjs @@ -55,6 +55,9 @@ export function usersRoutes(tools) { Users.isUsernameAvailable(req, res, tools) ) + // Load a user profile + app.get('/users/:id', (req, res) => Users.profile(req, res, tools)) + /* // Remove account diff --git a/sites/org/components/github/create-showcase.mjs b/sites/org/components/github/create-showcase.mjs index cb3a19b9c4c..0d39955ba2e 100644 --- a/sites/org/components/github/create-showcase.mjs +++ b/sites/org/components/github/create-showcase.mjs @@ -21,9 +21,10 @@ import { import { Collapse } from 'shared/components/collapse.mjs' import { Tab } from 'shared/components/account/bio.mjs' import { CodeBox } from 'shared/components/code-box.mjs' -import { PostArticle } from 'site/components/mdx/posts/article.mjs' +import { PostArticle, ns as mdxNs } from 'site/components/mdx/posts/article.mjs' +import { PageLink } from 'shared/components/page-link.mjs' -export const ns = nsMerge('account', authNs) +export const ns = nsMerge('account', 'posts', authNs, mdxNs) const Title = ({ children }) => (
To include this image in your post, use this markdown snippet:
-
+ If you configure your GitHub username{' '}
+
To include this image in your post, use this markdown snippet:
+{t('or')}
{t('or')}
+Please report this (FIXME: Add reporting capabilities)
+