Browse Source

feat: add option to toggle user signup enable/disable

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/4134/head
Pranav C 2 years ago
parent
commit
5256e7b849
  1. 34
      packages/nc-gui/components/admin/SignupSettings.vue
  2. 7
      packages/nc-gui/components/admin/UserList.vue
  3. 15
      packages/nc-gui/components/admin/UserManagement.vue
  4. 4
      packages/nc-gui/lib/constants.ts
  5. 2
      packages/nc-gui/pages/admin/index.vue
  6. 2
      packages/nocodb/src/lib/constants/index.ts
  7. 3
      packages/nocodb/src/lib/meta/api/orgLicenseApis.ts
  8. 31
      packages/nocodb/src/lib/meta/api/orgUserApis.ts
  9. 54
      scripts/sdk/swagger.json

34
packages/nc-gui/components/admin/SignupSettings.vue

@ -1,9 +1,41 @@
<script lang="ts" setup>
import { message } from 'ant-design-vue'
import { extractSdkResponseErrorMsg, useApi } from '#imports'
const { api } = useApi()
let settings = $ref({ enable_user_signup: false })
const loadSettings = async () => {
try {
const response = await api.orgAppSettings.get()
settings = response
} catch (e) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
const saveSettings = async () => {
try {
await api.orgAppSettings.set(settings)
message.success('Settings ky updated')
} catch (e) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
loadSettings()
</script>
<template>
<div>
<div class="text-xl">Settings</div>
<a-divider class="!my-3" />
<a-form-item>
<a-checkbox name="virtual">Enable user signup</a-checkbox>
<a-checkbox v-model:checked="settings.enable_user_signup" name="virtual" @change="saveSettings"
>Enable user signup</a-checkbox
>
</a-form-item>
</div>
</template>

7
packages/nc-gui/components/admin/UserList.vue

@ -18,14 +18,12 @@ let users = $ref<UserType[]>([])
let currentPage = $ref(1)
const currentLimit = $ref(10)
const showUserModal = ref(false)
const searchText = ref<string>('')
const pagination = reactive({
total: 0,
pageSize: 10,
@ -118,7 +116,6 @@ const copyPasswordResetUrl = async (user: User) => {
message.error(await extractSdkResponseErrorMsg(e))
}
}
</script>
<template>
@ -212,8 +209,7 @@ const copyPasswordResetUrl = async (user: User) => {
<div v-if="!record.roles.includes('super')" class="flex items-center gap-2">
<MdiDeleteOutline class="nc-action-btn cursor-pointer" @click="deleteUser(text)" />
<a-dropdown :trigger="['click']" class="flex" placement="bottomRight"
overlay-class-name="nc-dropdown-user-mgmt">
<a-dropdown :trigger="['click']" class="flex" placement="bottomRight" overlay-class-name="nc-dropdown-user-mgmt">
<div class="flex flex-row items-center">
<a-button type="text" class="!px-0">
<div class="flex flex-row items-center h-[1.2rem]">
@ -256,7 +252,6 @@ const copyPasswordResetUrl = async (user: User) => {
<LazyAdminUsersModal :show="showUserModal" @closed="showUserModal = false" @reload="loadUsers" />
</div>
</div>
</template>

15
packages/nc-gui/components/admin/UserManagement.vue

@ -1,13 +1,15 @@
<script lang="ts" setup>
import { useUIPermission } from '~/composables/useUIPermission'
const { isUIAllowed } = useUIPermission()
const tabs = [
...(isUIAllowed('superAdminUserManagement') ? [{ label: 'Users', key: 'users' },
{ label: 'Settings', key: 'settings' }] : []),
...(isUIAllowed('superAdminUserManagement')
? [
{ label: 'Users', key: 'users' },
{ label: 'Settings', key: 'settings' },
]
: []),
{ label: 'Reset Password', key: 'password-reset' },
]
@ -17,9 +19,7 @@ const selectedTabKey = ref(tabs[0].key)
<template>
<div class="h-full overflow-y-scroll scrollbar-thin-dull pt-4">
<a-tabs v-model:active-key="selectedTabKey" :open-keys="[]" mode="horizontal" class="nc-auth-tabs">
<a-tab-pane
v-for="(tab) of tabs"
:key="tab.key" class="select-none">
<a-tab-pane v-for="tab of tabs" :key="tab.key" class="select-none">
<template #tab>
<span>
{{ tab.label }}
@ -28,7 +28,6 @@ const selectedTabKey = ref(tabs[0].key)
</a-tab-pane>
</a-tabs>
<template v-if="selectedTabKey === 'users'">
<LazyAdminUserList class="mt-10" />
</template>
<template v-else-if="selectedTabKey === 'settings'">

4
packages/nc-gui/lib/constants.ts

@ -31,14 +31,14 @@ export const rolePermissions = {
exclude: {
appStore: true,
superAdminUserManagement: true,
appLicense:true
appLicense: true,
},
},
[ProjectRole.Owner]: {
exclude: {
appStore: true,
superAdminUserManagement: true,
appLicense:true
appLicense: true,
},
},
[ProjectRole.Editor]: {

2
packages/nc-gui/pages/admin/index.vue

@ -39,10 +39,10 @@ const {isUIAllowed} = useUIPermission()
</div>
</a-menu-item>
<a-menu-item
v-if="isUIAllowed('appLicense')"
key="license"
class="group active:(!ring-0) hover:(!bg-primary !bg-opacity-25)"
@click="navigateTo('/admin/license')"
v-if="isUIAllowed('appLicense')"
>
<div class="flex items-center space-x-2">
<MdiKeyChainVariant />

2
packages/nocodb/src/lib/constants/index.ts

@ -0,0 +1,2 @@
export const LICENSE_KEY = 'nc-license-key';
export const NC_APP_SETTINGS = 'nc-app-settings';

3
packages/nocodb/src/lib/meta/api/orgLicenseApis.ts

@ -1,10 +1,11 @@
import { Router } from 'express';
import { OrgUserRoles } from '../../../enums/OrgUserRoles';
import { LICENSE_KEY } from '../../constants'
import Store from '../../models/Store';
import { metaApiMetrics } from '../helpers/apiMetrics';
import ncMetaAclMw from '../helpers/ncMetaAclMw';
const LICENSE_KEY = 'nc-license-key';
async function licenseGet(_req, res) {
const license = await Store.get(LICENSE_KEY);

31
packages/nocodb/src/lib/meta/api/orgUserApis.ts

@ -3,8 +3,10 @@ import { PluginCategory } from 'nocodb-sdk';
import { v4 as uuidv4 } from 'uuid';
import validator from 'validator';
import { OrgUserRoles } from '../../../enums/OrgUserRoles';
import { NC_APP_SETTINGS } from '../../constants';
import Audit from '../../models/Audit';
import ProjectUser from '../../models/ProjectUser';
import Store from '../../models/Store';
import SyncSource from '../../models/SyncSource';
import User from '../../models/User';
import Noco from '../../Noco';
@ -227,6 +229,23 @@ async function generateResetUrl(req, res) {
});
}
async function appSettingsGet(_req, res) {
let settings = {};
try {
settings = JSON.parse((await Store.get(NC_APP_SETTINGS))?.value);
} catch {}
res.json(settings);
}
async function appSettingsSet(req, res) {
await Store.saveOrUpdate({
value: JSON.stringify(req.body),
key: NC_APP_SETTINGS,
});
res.json({ msg: 'License key saved' });
}
const router = Router({ mergeParams: true });
router.get(
'/api/v1/users',
@ -283,23 +302,25 @@ router.post(
ncMetaAclMw(generateResetUrl, 'generateResetUrl', {
allowedRoles: [OrgUserRoles.SUPER],
blockApiTokenAccess: true,
}));
})
);
router.get(
'/api/v1/users/settings',
'/api/v1/app-settings',
metaApiMetrics,
ncMetaAclMw(generateResetUrl, 'generateResetUrl', {
ncMetaAclMw(appSettingsGet, 'appSettingsGet', {
allowedRoles: [OrgUserRoles.SUPER],
blockApiTokenAccess: true,
})
);
router.post(
'/api/v1/users/settings',
'/api/v1/app-settings',
metaApiMetrics,
ncMetaAclMw(generateResetUrl, 'generateResetUrl', {
ncMetaAclMw(appSettingsSet, 'appSettingsSet', {
allowedRoles: [OrgUserRoles.SUPER],
blockApiTokenAccess: true,
})
);
export default router;

54
scripts/sdk/swagger.json

@ -572,6 +572,60 @@
]
}
},
"/api/v1/app-settings": {
"get": {
"summary": "App settings get",
"operationId": "org-app-settings-get",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"enable_user_signup": {
"type": "boolean"
}
}
}
}
}
}
},
"description": "",
"tags": [
"Org app settings"
]
},
"parameters": [],
"post": {
"summary": "App app settings get",
"operationId": "org-app-settings-set",
"responses": {
"200": {
"description": "OK"
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"enable_user_signup": {
"type": "boolean"
}
}
}
}
}
},
"tags": [
"Org app settings"
]
}
},
"/api/v1/tokens/{token}": {
"parameters": [
{

Loading…
Cancel
Save