From fd066c9b2b37ca6ebaa09e25f0085bcb1aa88b43 Mon Sep 17 00:00:00 2001 From: Oliver Eyton-Williams Date: Wed, 22 Nov 2023 12:28:40 +0100 Subject: [PATCH] feat: remove invited users (#342) --- .../sync/admin-role.strapi-super-admin.json | 79 +--- ...types##api##invited-user.invited-user.json | 150 -------- ...on_content_types##plugin##i18n.locale.json | 129 ------- ...types##plugin##users-permissions.role.json | 19 - .../config/sync/user-role.authenticated.json | 12 - .../config/sync/user-role.contributor.json | 3 - .../backend/config/sync/user-role.public.json | 3 - .../content-types/invited-user/lifecycles.js | 31 -- .../content-types/invited-user/schema.json | 32 -- .../invited-user/controllers/invited-user.js | 9 - .../api/invited-user/routes/invited-user.js | 9 - .../api/invited-user/services/invited-user.js | 9 - .../content-types/role/schema.json | 6 - apps/backend/src/index.js | 79 +--- apps/backend/src/seed/index.js | 32 -- apps/frontend/src/lib/invite-user.js | 116 ------ .../src/pages/api/auth/[...nextauth].js | 15 - apps/frontend/src/pages/users/index.js | 350 ------------------ 18 files changed, 6 insertions(+), 1077 deletions(-) delete mode 100644 apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##api##invited-user.invited-user.json delete mode 100644 apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##plugin##i18n.locale.json delete mode 100644 apps/backend/src/api/invited-user/content-types/invited-user/lifecycles.js delete mode 100644 apps/backend/src/api/invited-user/content-types/invited-user/schema.json delete mode 100644 apps/backend/src/api/invited-user/controllers/invited-user.js delete mode 100644 apps/backend/src/api/invited-user/routes/invited-user.js delete mode 100644 apps/backend/src/api/invited-user/services/invited-user.js delete mode 100644 apps/frontend/src/lib/invite-user.js delete mode 100644 apps/frontend/src/pages/users/index.js diff --git a/apps/backend/config/sync/admin-role.strapi-super-admin.json b/apps/backend/config/sync/admin-role.strapi-super-admin.json index bc93234e3..954adf13a 100644 --- a/apps/backend/config/sync/admin-role.strapi-super-admin.json +++ b/apps/backend/config/sync/admin-role.strapi-super-admin.json @@ -3,40 +3,6 @@ "code": "strapi-super-admin", "description": "Super Admins can access and manage all features and settings.", "permissions": [ - { - "action": "plugin::content-manager.explorer.create", - "actionParameters": {}, - "subject": "api::invited-user.invited-user", - "properties": { - "fields": ["email", "accepted", "role"] - }, - "conditions": [] - }, - { - "action": "plugin::content-manager.explorer.delete", - "actionParameters": {}, - "subject": "api::invited-user.invited-user", - "properties": {}, - "conditions": [] - }, - { - "action": "plugin::content-manager.explorer.read", - "actionParameters": {}, - "subject": "api::invited-user.invited-user", - "properties": { - "fields": ["email", "accepted", "role"] - }, - "conditions": [] - }, - { - "action": "plugin::content-manager.explorer.update", - "actionParameters": {}, - "subject": "api::invited-user.invited-user", - "properties": { - "fields": ["email", "accepted", "role"] - }, - "conditions": [] - }, { "action": "plugin::content-manager.explorer.create", "actionParameters": {}, @@ -55,8 +21,7 @@ "codeinjection_head", "codeinjection_foot", "slug_id" - ], - "locales": ["en"] + ] }, "conditions": [] }, @@ -64,18 +29,14 @@ "action": "plugin::content-manager.explorer.delete", "actionParameters": {}, "subject": "api::post.post", - "properties": { - "locales": ["en"] - }, + "properties": {}, "conditions": [] }, { "action": "plugin::content-manager.explorer.publish", "actionParameters": {}, "subject": "api::post.post", - "properties": { - "locales": ["en"] - }, + "properties": {}, "conditions": [] }, { @@ -96,8 +57,7 @@ "codeinjection_head", "codeinjection_foot", "slug_id" - ], - "locales": ["en"] + ] }, "conditions": [] }, @@ -119,8 +79,7 @@ "codeinjection_head", "codeinjection_foot", "slug_id" - ], - "locales": ["en"] + ] }, "conditions": [] }, @@ -524,34 +483,6 @@ "properties": {}, "conditions": [] }, - { - "action": "plugin::i18n.locale.create", - "actionParameters": {}, - "subject": null, - "properties": {}, - "conditions": [] - }, - { - "action": "plugin::i18n.locale.delete", - "actionParameters": {}, - "subject": null, - "properties": {}, - "conditions": [] - }, - { - "action": "plugin::i18n.locale.read", - "actionParameters": {}, - "subject": null, - "properties": {}, - "conditions": [] - }, - { - "action": "plugin::i18n.locale.update", - "actionParameters": {}, - "subject": null, - "properties": {}, - "conditions": [] - }, { "action": "plugin::upload.assets.copy-link", "actionParameters": {}, diff --git a/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##api##invited-user.invited-user.json b/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##api##invited-user.invited-user.json deleted file mode 100644 index f4ac11cba..000000000 --- a/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##api##invited-user.invited-user.json +++ /dev/null @@ -1,150 +0,0 @@ -{ - "key": "plugin_content_manager_configuration_content_types::api::invited-user.invited-user", - "value": { - "uid": "api::invited-user.invited-user", - "settings": { - "bulkable": true, - "filterable": true, - "searchable": true, - "pageSize": 10, - "mainField": "email", - "defaultSortBy": "email", - "defaultSortOrder": "ASC" - }, - "metadatas": { - "id": { - "edit": {}, - "list": { - "label": "id", - "searchable": true, - "sortable": true - } - }, - "email": { - "edit": { - "label": "email", - "description": "End-user email", - "placeholder": "", - "visible": true, - "editable": true - }, - "list": { - "label": "email", - "searchable": true, - "sortable": true - } - }, - "accepted": { - "edit": { - "label": "accepted", - "description": "End-user has accepted and logged in atleast once", - "placeholder": "", - "visible": true, - "editable": true - }, - "list": { - "label": "accepted", - "searchable": true, - "sortable": true - } - }, - "role": { - "edit": { - "label": "role", - "description": "", - "placeholder": "", - "visible": true, - "editable": true, - "mainField": "name" - }, - "list": { - "label": "role", - "searchable": true, - "sortable": true - } - }, - "createdAt": { - "edit": { - "label": "createdAt", - "description": "", - "placeholder": "", - "visible": false, - "editable": true - }, - "list": { - "label": "createdAt", - "searchable": true, - "sortable": true - } - }, - "updatedAt": { - "edit": { - "label": "updatedAt", - "description": "", - "placeholder": "", - "visible": false, - "editable": true - }, - "list": { - "label": "updatedAt", - "searchable": true, - "sortable": true - } - }, - "createdBy": { - "edit": { - "label": "createdBy", - "description": "", - "placeholder": "", - "visible": false, - "editable": true, - "mainField": "firstname" - }, - "list": { - "label": "createdBy", - "searchable": true, - "sortable": true - } - }, - "updatedBy": { - "edit": { - "label": "updatedBy", - "description": "", - "placeholder": "", - "visible": false, - "editable": true, - "mainField": "firstname" - }, - "list": { - "label": "updatedBy", - "searchable": true, - "sortable": true - } - } - }, - "layouts": { - "edit": [ - [ - { - "name": "email", - "size": 6 - }, - { - "name": "accepted", - "size": 4 - } - ], - [ - { - "name": "role", - "size": 6 - } - ] - ], - "list": ["email", "role", "accepted", "createdAt", "createdBy"] - } - }, - "type": "object", - "environment": null, - "tag": null -} diff --git a/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##plugin##i18n.locale.json b/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##plugin##i18n.locale.json deleted file mode 100644 index 617fa5b5b..000000000 --- a/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##plugin##i18n.locale.json +++ /dev/null @@ -1,129 +0,0 @@ -{ - "key": "plugin_content_manager_configuration_content_types::plugin::i18n.locale", - "value": { - "uid": "plugin::i18n.locale", - "settings": { - "bulkable": true, - "filterable": true, - "searchable": true, - "pageSize": 10, - "mainField": "name", - "defaultSortBy": "name", - "defaultSortOrder": "ASC" - }, - "metadatas": { - "id": { - "edit": {}, - "list": { - "label": "id", - "searchable": true, - "sortable": true - } - }, - "name": { - "edit": { - "label": "name", - "description": "", - "placeholder": "", - "visible": true, - "editable": true - }, - "list": { - "label": "name", - "searchable": true, - "sortable": true - } - }, - "code": { - "edit": { - "label": "code", - "description": "", - "placeholder": "", - "visible": true, - "editable": true - }, - "list": { - "label": "code", - "searchable": true, - "sortable": true - } - }, - "createdAt": { - "edit": { - "label": "createdAt", - "description": "", - "placeholder": "", - "visible": false, - "editable": true - }, - "list": { - "label": "createdAt", - "searchable": true, - "sortable": true - } - }, - "updatedAt": { - "edit": { - "label": "updatedAt", - "description": "", - "placeholder": "", - "visible": false, - "editable": true - }, - "list": { - "label": "updatedAt", - "searchable": true, - "sortable": true - } - }, - "createdBy": { - "edit": { - "label": "createdBy", - "description": "", - "placeholder": "", - "visible": false, - "editable": true, - "mainField": "firstname" - }, - "list": { - "label": "createdBy", - "searchable": true, - "sortable": true - } - }, - "updatedBy": { - "edit": { - "label": "updatedBy", - "description": "", - "placeholder": "", - "visible": false, - "editable": true, - "mainField": "firstname" - }, - "list": { - "label": "updatedBy", - "searchable": true, - "sortable": true - } - } - }, - "layouts": { - "list": ["id", "name", "code", "createdAt"], - "edit": [ - [ - { - "name": "name", - "size": 6 - }, - { - "name": "code", - "size": 6 - } - ] - ] - } - }, - "type": "object", - "environment": null, - "tag": null -} diff --git a/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##plugin##users-permissions.role.json b/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##plugin##users-permissions.role.json index b5abb68f0..b06d50c96 100644 --- a/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##plugin##users-permissions.role.json +++ b/apps/backend/config/sync/core-store.plugin_content_manager_configuration_content_types##plugin##users-permissions.role.json @@ -92,21 +92,6 @@ "sortable": false } }, - "invited_users": { - "edit": { - "label": "invited_users", - "description": "", - "placeholder": "", - "visible": true, - "editable": true, - "mainField": "id" - }, - "list": { - "label": "invited_users", - "searchable": false, - "sortable": false - } - }, "createdAt": { "edit": { "label": "createdAt", @@ -193,10 +178,6 @@ { "name": "users", "size": 6 - }, - { - "name": "invited_users", - "size": 6 } ] ] diff --git a/apps/backend/config/sync/user-role.authenticated.json b/apps/backend/config/sync/user-role.authenticated.json index 629b61476..3228601f4 100644 --- a/apps/backend/config/sync/user-role.authenticated.json +++ b/apps/backend/config/sync/user-role.authenticated.json @@ -3,21 +3,9 @@ "description": "Editors", "type": "authenticated", "permissions": [ - { - "action": "api::invited-user.invited-user.create" - }, - { - "action": "api::invited-user.invited-user.delete" - }, - { - "action": "api::invited-user.invited-user.find" - }, { "action": "api::post.post.create" }, - { - "action": "api::post.post.createLocalization" - }, { "action": "api::post.post.delete" }, diff --git a/apps/backend/config/sync/user-role.contributor.json b/apps/backend/config/sync/user-role.contributor.json index e7a7c8462..4f7af688e 100644 --- a/apps/backend/config/sync/user-role.contributor.json +++ b/apps/backend/config/sync/user-role.contributor.json @@ -6,9 +6,6 @@ { "action": "api::post.post.create" }, - { - "action": "api::post.post.createLocalization" - }, { "action": "api::post.post.delete" }, diff --git a/apps/backend/config/sync/user-role.public.json b/apps/backend/config/sync/user-role.public.json index 4b4225d79..41ad345f4 100644 --- a/apps/backend/config/sync/user-role.public.json +++ b/apps/backend/config/sync/user-role.public.json @@ -3,9 +3,6 @@ "description": "Default role given to unauthenticated user (unauthenticated API calls).", "type": "public", "permissions": [ - { - "action": "api::invited-user.invited-user.find" - }, { "action": "plugin::users-permissions.auth.callback" }, diff --git a/apps/backend/src/api/invited-user/content-types/invited-user/lifecycles.js b/apps/backend/src/api/invited-user/content-types/invited-user/lifecycles.js deleted file mode 100644 index 411cd88c6..000000000 --- a/apps/backend/src/api/invited-user/content-types/invited-user/lifecycles.js +++ /dev/null @@ -1,31 +0,0 @@ -"use strict"; - -module.exports = { - async afterCreate(event) { - const DASHBOARD_URL = - process.env.DASHBOARD_URL === "" - ? "http://localhost:3000" - : process.env.DASHBOARD_URL; - - if (global.SEEDING_DATA !== "true") { - await strapi.plugins.email.services.email.send({ - to: event.result.email, - from: "support@freecodecamp.org", - subject: "Invitation Link", - text: `Here is your invitation link: ${DASHBOARD_URL}/api/auth/signin`, - }); - } - // if (process.env.NODE_ENV === "development") { - // const { email, role } = event.params.data; - - // await strapi.plugins["users-permissions"].services.user.add({ - // username: email, - // email: email, - // password: "password", - // role: role, - // provider: "local", - // confirmed: true, - // }); - // } - }, -}; diff --git a/apps/backend/src/api/invited-user/content-types/invited-user/schema.json b/apps/backend/src/api/invited-user/content-types/invited-user/schema.json deleted file mode 100644 index 95c659091..000000000 --- a/apps/backend/src/api/invited-user/content-types/invited-user/schema.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "kind": "collectionType", - "collectionName": "invited_users", - "info": { - "singularName": "invited-user", - "pluralName": "invited-users", - "displayName": "Invited User", - "description": "" - }, - "options": { - "draftAndPublish": false - }, - "pluginOptions": {}, - "attributes": { - "email": { - "type": "email", - "required": true, - "unique": true - }, - "accepted": { - "type": "boolean", - "default": false, - "required": false - }, - "role": { - "type": "relation", - "relation": "manyToOne", - "target": "plugin::users-permissions.role", - "inversedBy": "invited_users" - } - } -} diff --git a/apps/backend/src/api/invited-user/controllers/invited-user.js b/apps/backend/src/api/invited-user/controllers/invited-user.js deleted file mode 100644 index 552112ae3..000000000 --- a/apps/backend/src/api/invited-user/controllers/invited-user.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -/** - * invited-user controller - */ - -const { createCoreController } = require("@strapi/strapi").factories; - -module.exports = createCoreController("api::invited-user.invited-user"); diff --git a/apps/backend/src/api/invited-user/routes/invited-user.js b/apps/backend/src/api/invited-user/routes/invited-user.js deleted file mode 100644 index d06069675..000000000 --- a/apps/backend/src/api/invited-user/routes/invited-user.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -/** - * invited-user router - */ - -const { createCoreRouter } = require("@strapi/strapi").factories; - -module.exports = createCoreRouter("api::invited-user.invited-user"); diff --git a/apps/backend/src/api/invited-user/services/invited-user.js b/apps/backend/src/api/invited-user/services/invited-user.js deleted file mode 100644 index 1cc3f5b5f..000000000 --- a/apps/backend/src/api/invited-user/services/invited-user.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -/** - * invited-user service - */ - -const { createCoreService } = require("@strapi/strapi").factories; - -module.exports = createCoreService("api::invited-user.invited-user"); diff --git a/apps/backend/src/extensions/users-permissions/content-types/role/schema.json b/apps/backend/src/extensions/users-permissions/content-types/role/schema.json index d294d7ac8..bce9e8a8c 100644 --- a/apps/backend/src/extensions/users-permissions/content-types/role/schema.json +++ b/apps/backend/src/extensions/users-permissions/content-types/role/schema.json @@ -45,12 +45,6 @@ "target": "plugin::users-permissions.user", "mappedBy": "role", "configurable": false - }, - "invited_users": { - "type": "relation", - "relation": "oneToMany", - "target": "api::invited-user.invited-user", - "mappedBy": "role" } } } diff --git a/apps/backend/src/index.js b/apps/backend/src/index.js index 73b9cabb9..01ced93f7 100644 --- a/apps/backend/src/index.js +++ b/apps/backend/src/index.js @@ -16,82 +16,5 @@ module.exports = { * This gives you an opportunity to set up your data model, * run jobs, or perform some special logic. */ - async bootstrap({ strapi }) { - strapi.db.lifecycles.subscribe({ - models: ["plugin::users-permissions.user"], - async beforeCreate(event) { - const { email } = event.params.data; - const invitedUser = await strapi.db - .query("api::invited-user.invited-user") - .findOne({ - populate: true, - where: { - email: { - $eq: email, - }, - }, - }); - if (invitedUser) { - event.params.data.role = invitedUser.role.id; - } - if (process.env.DATA_MIGRATION === "true") { - event.params.data.password = ""; - } - }, - async afterCreate(event) { - const { email } = event.result; - await strapi.db.query("api::invited-user.invited-user").update({ - where: { - email: { - $eq: email, - }, - }, - data: { - accepted: true, - }, - }); - }, - async beforeUpdate(event) { - const { id } = event.params.where; - const { email: newEmail } = event.params.data; - const { email: oldEmail } = await strapi.entityService.findOne( - "plugin::users-permissions.user", - id, - ); - event.state = { - oldEmail, - newEmail, - }; - }, - async afterUpdate(event) { - const { oldEmail, newEmail } = event.state; - if (oldEmail !== newEmail) { - await strapi.db.query("api::invited-user.invited-user").update({ - where: { - email: { - $eq: oldEmail, - }, - }, - data: { - email: newEmail, - }, - }); - } - }, - async beforeDelete(event) { - const { id } = event.params.where; - const { email } = await strapi.entityService.findOne( - "plugin::users-permissions.user", - id, - ); - await strapi.db.query("api::invited-user.invited-user").delete({ - where: { - email: { - $eq: email, - }, - }, - }); - }, - }); - }, + bootstrap(/*{ strapi }*/) {}, }; diff --git a/apps/backend/src/seed/index.js b/apps/backend/src/seed/index.js index 5d43c5844..1a2902371 100644 --- a/apps/backend/src/seed/index.js +++ b/apps/backend/src/seed/index.js @@ -58,37 +58,6 @@ async function createSeedUsers(strapi) { userIds = [userRes1.id, userRes2.id]; } -async function createSeedInvitedUsers(strapi) { - const contributor = await findRoleId(strapi, "Contributor"); - const editor = await findRoleId(strapi, "Editor"); - await strapi.entityService.create("api::invited-user.invited-user", { - data: { - email: "contributor@user.com", - accepted: "true", - role: { - connect: [contributor], - }, - }, - }); - await strapi.entityService.create("api::invited-user.invited-user", { - data: { - email: "editor@user.com", - accepted: "true", - role: { - connect: [editor], - }, - }, - }); - await strapi.entityService.create("api::invited-user.invited-user", { - data: { - email: "invited@user.com", - role: { - connect: [contributor], - }, - }, - }); -} - async function createSeedTags(strapi) { const tagRes1 = await strapi.entityService.create("api::tag.tag", { data: { @@ -196,7 +165,6 @@ async function generateSeedData(strapi) { console.log("Creating seed data..."); await createSeedUsers(strapi); - await createSeedInvitedUsers(strapi); await createSeedTags(strapi); await createSeedPosts(strapi); } diff --git a/apps/frontend/src/lib/invite-user.js b/apps/frontend/src/lib/invite-user.js deleted file mode 100644 index 592fd9049..000000000 --- a/apps/frontend/src/lib/invite-user.js +++ /dev/null @@ -1,116 +0,0 @@ -import qs from "qs"; - -const base = process.env.NEXT_PUBLIC_STRAPI_BACKEND_URL; - -export async function getInvitedUsers(token, queryParams) { - const url = new URL("/api/invited-users", base); - url.search = qs.stringify(queryParams, { - encodeValuesOnly: true, - }); - const res = await fetch(url, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - }); - - try { - const data = await res.json(); - if (!res.ok) { - throw new Error( - data.message || `Something went wrong. Status: ${res.status}`, - ); - } - - return data; - } catch (error) { - console.error(`getInvitedUsers Failed. Error: `, error); - throw new Error(`getInvitedUsers Failed. Error: ${error}`); - } -} - -export async function inviteUser(token, data) { - const url = new URL("/api/invited-users", base); - const res = await fetch(url, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - body: JSON.stringify(data), - }); - - try { - const data = await res.json(); - if (!res.ok) { - throw new Error( - data.message || `Something went wrong. Status: ${res.status}`, - ); - } - - return true; - } catch (error) { - const { email } = data.data; - console.error(`inviteUser Failed. email: ${email}, Error: `, error); - throw new Error(`inviteUser Failed. email: ${email}, Error: ${error}`); - } -} - -export async function invitedUserExists(token, email) { - const url = new URL("/api/invited-users", base); - url.search = qs.stringify( - { - filters: { - email: { - $eqi: email, - }, - }, - }, - { - encodeValuesOnly: true, - }, - ); - - const options = { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - }; - - const res = await fetch(url, options); - - if (!res.ok) { - throw new Error("invitedUserExists Failed"); - } - - const data = await res.json(); - return data.data.length > 0; -} - -export async function deleteInvitedUser(token, id) { - const url = new URL(`/api/invited-users/${id}`, base); - const res = await fetch(url, { - method: "DELETE", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - }); - - try { - const data = await res.json(); - if (!res.ok) { - throw new Error( - data.message || `Something went wrong. Status: ${res?.status}`, - ); - } - - return data; - } catch (error) { - console.error(`deleteInvitedUser Failed. Error: `, error); - throw new Error(`deleteInvitedUser Failed. Error: ${error}`); - } -} diff --git a/apps/frontend/src/pages/api/auth/[...nextauth].js b/apps/frontend/src/pages/api/auth/[...nextauth].js index 1ab46c061..f07f42461 100644 --- a/apps/frontend/src/pages/api/auth/[...nextauth].js +++ b/apps/frontend/src/pages/api/auth/[...nextauth].js @@ -45,21 +45,6 @@ export const authOptions = { // Details: https://next-auth.js.org/configuration/callbacks callbacks: { - async signIn({ user }) { - const { email } = user; - const url = new URL( - "api/invited-users", - process.env.NEXT_PUBLIC_STRAPI_BACKEND_URL, - ); - url.search = `filters[email][$eq]=${email}`; - const res = await fetch(url); - const { data } = await res.json(); - if (data.length === 0) { - return false; - } - return true; - }, - // This callback is called whenever a JSON Web Token is created (i.e. at sign in) // or updated(i.e whenever a session is accessed in the client). async jwt({ token, user, account }) { diff --git a/apps/frontend/src/pages/users/index.js b/apps/frontend/src/pages/users/index.js deleted file mode 100644 index 33eac53d7..000000000 --- a/apps/frontend/src/pages/users/index.js +++ /dev/null @@ -1,350 +0,0 @@ -import { - Avatar, - Badge, - Box, - Button, - ButtonGroup, - Flex, - FormControl, - FormErrorMessage, - FormLabel, - Heading, - Input, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalHeader, - ModalOverlay, - Select, - Spacer, - Text, - useDisclosure, - useToast, -} from "@chakra-ui/react"; -import intlFormatDistance from "date-fns/intlFormatDistance"; -import { Field, Form, Formik } from "formik"; -import { getServerSession } from "next-auth/next"; -import { useRouter } from "next/router"; -import { useState } from "react"; - -import NavMenu from "@/components/nav-menu"; -import { - deleteInvitedUser, - getInvitedUsers, - inviteUser, - invitedUserExists, -} from "@/lib/invite-user"; -import { getRoles } from "@/lib/roles"; -import { getUsers, userExists } from "@/lib/users"; -import { authOptions } from "@/pages/api/auth/[...nextauth]"; - -export async function getServerSideProps(context) { - const session = await getServerSession(context.req, context.res, authOptions); - const allUsers = await getUsers(session.user.jwt, { - populate: ["role", "profile_image"], - }); - const rolesData = await getRoles(session.user.jwt); - const invitedUsers = await getInvitedUsers(session.user.jwt, { - populate: "role", - filters: { - accepted: false, - }, - }); - - const roles = rolesData.roles.reduce( - (acc, role) => ({ ...acc, [role.name]: role.id }), - {}, - ); - delete roles.Public; - - return { - props: { - allUsers, - invitedUsers, - roles, - user: session.user, - }, - }; -} - -export default function UsersIndex({ allUsers, invitedUsers, roles, user }) { - const { isOpen, onOpen, onClose } = useDisclosure(); - const toast = useToast(); - const router = useRouter(); - - const [revokingInvitation, setRevokingInvitation] = useState(false); - - const handleSubmit = async (values) => { - const token = user.jwt; - const data = { - data: { - email: values.email, - role: [roles[values.role]], - }, - }; - - try { - await inviteUser(token, data); - toast({ - title: "User invited.", - status: "success", - duration: 5000, - isClosable: true, - }); - router.replace(router.asPath); - } catch (error) { - console.log(error); - toast({ - title: "An error occurred.", - description: error.message, - status: "error", - duration: 5000, - isClosable: true, - }); - } - }; - - const revokeInvitation = async (invitedUserId) => { - setRevokingInvitation(true); - const token = user.jwt; - try { - await deleteInvitedUser(token, invitedUserId); - toast({ - title: "User invitation revoked.", - status: "success", - duration: 5000, - isClosable: true, - }); - router.replace(router.asPath); - } catch (error) { - console.log(error); - toast({ - title: "An error occurred.", - description: error.message, - status: "error", - duration: 5000, - isClosable: true, - }); - } - setRevokingInvitation(false); - }; - - return ( - - - - - - Staff users - - - - - - - - Invite a New User - - - { - // Check if user exists - if (await userExists(user.jwt, values.email)) { - actions.setErrors({ - email: "A user with that email address already exists.", - }); - return; - } - - // Check if user has already been invited - if (await invitedUserExists(user.jwt, values.email)) { - actions.setErrors({ - email: - "A user with that email address has already been invited.", - }); - return; - } - - await handleSubmit(values); - onClose(); - }} - > - {({ isSubmitting }) => ( -
- - {({ field, form }) => ( - - Email - - - {form.errors.email} - - - )} - - - {({ field }) => ( - - Role - - - )} - - -
- )} -
-
-
-
- - - Invited Users - - {invitedUsers.data.map((user) => { - if (user.attributes.accepted) return null; - - const userEmail = user.attributes.email; - const userRole = user.attributes.role.data.attributes.name; - const createdAt = intlFormatDistance( - new Date(user.attributes.createdAt), - new Date(), - ); - return ( - - - - - {userEmail} - - Invitation sent: {createdAt} - - - - - - - - - - {userRole} - - - - ); - })} - - - Active Users - - {allUsers.map((user) => { - const userEmail = user.email; - const userRole = user.role.name; - const profileImage = - user.profile_image !== null - ? process.env.NEXT_PUBLIC_STRAPI_BACKEND_URL + - user.profile_image.url - : ""; - return ( - router.push(`/users/${user.id}`)} - > - - - {userEmail} - - - {userRole} - - - ); - })} - - -
-
- ); -}