mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-03 08:57:14 +03:00
Account fix (#3637)
This commit is contained in:
parent
9a161ed71b
commit
f56d65dc20
@ -114,11 +114,13 @@ export function devTool (
|
||||
.command('create-account <email>')
|
||||
.description('create user and corresponding account in master database')
|
||||
.requiredOption('-p, --password <password>', 'user password')
|
||||
.requiredOption('-f, --first <first>', 'first name')
|
||||
.requiredOption('-l, --last <last>', 'last name')
|
||||
.action(async (email: string, cmd) => {
|
||||
const { mongodbUri } = prepareTools()
|
||||
return await withDatabase(mongodbUri, async (db) => {
|
||||
console.log(`creating account ${cmd.first as string} ${cmd.last as string} (${email})...`)
|
||||
await createAcc(db, productId, email, cmd.password, true)
|
||||
await createAcc(db, productId, email, cmd.password, cmd.first, cmd.last, true)
|
||||
})
|
||||
})
|
||||
|
||||
@ -137,13 +139,11 @@ export function devTool (
|
||||
program
|
||||
.command('assign-workspace <email> <workspace>')
|
||||
.description('assign workspace')
|
||||
.requiredOption('-f, --first <first>', 'first name')
|
||||
.requiredOption('-l, --last <last>', 'last name')
|
||||
.action(async (email: string, workspace: string, cmd) => {
|
||||
const { mongodbUri } = prepareTools()
|
||||
return await withDatabase(mongodbUri, async (db, client) => {
|
||||
console.log(`assigning user ${email} to ${workspace}...`)
|
||||
await assignWorkspace(db, productId, email, workspace, cmd.first, cmd.last)
|
||||
await assignWorkspace(db, productId, email, workspace)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -27,7 +27,12 @@
|
||||
"WantAnotherWorkspace": "Want to create another workspace?",
|
||||
"ChangeAccount": "Change account",
|
||||
"NotSeeingWorkspace": "Not seeing your workspace?",
|
||||
"WorkspaceNameRule": "The workspace name can contain lowercase letters, numbers and symbol - (inside name)",
|
||||
"WorkspaceNameRule": "Workspace name cannot contain special characters except -",
|
||||
"WorkspaceNameRuleCapital": "The workspace name must contain only lowercase letters",
|
||||
"WorkspaceNameRuleHyphen": "The workspace name cannot start with a dash (-)",
|
||||
"WorkspaceNameRuleHyphenEnd": "The workspace name cannot end with a dash (-)",
|
||||
"WorkspaceNameRuleLengthLow": "Workspace name must be at least 3 characters",
|
||||
"WorkspaceNameRuleLengthHigh": "Workspace name must be no longer than 63 characters",
|
||||
"ForgotPassword": "Forgot your password?",
|
||||
"KnowPassword": "Know your password?",
|
||||
"Recover": "Recover",
|
||||
|
@ -27,7 +27,12 @@
|
||||
"WantAnotherWorkspace": "Хотите создать другое рабочее пространство?",
|
||||
"ChangeAccount": "Сменить пользователя",
|
||||
"NotSeeingWorkspace": "Не видите ваше рабочее пространство?",
|
||||
"WorkspaceNameRule": "Название рабочего пространства должно состоять из строчных латинских букв, цифр и символа - (внутри имени)",
|
||||
"WorkspaceNameRule": "Название рабочего пространства не может содержать специальные символы кроме -",
|
||||
"WorkspaceNameRuleCapital": "Название рабочего пространства должно содержать только строчные буквы",
|
||||
"WorkspaceNameRuleHyphen": "Название рабочего пространства не может начинаться с символа 'тире' (-)",
|
||||
"WorkspaceNameRuleHyphenEnd": "Название рабочего пространства не может заканчиваться символом 'тире' (-)",
|
||||
"WorkspaceNameRuleLengthLow": "Название рабочего пространства должно быть не короче 3 символов",
|
||||
"WorkspaceNameRuleLengthHigh": "Название рабочего пространства должно быть не длиннее 63 символов",
|
||||
"ForgotPassword": "Забыли пароль?",
|
||||
"KnowPassword": "Знаете пароль?",
|
||||
"Recover": "Восстановить",
|
||||
|
@ -25,20 +25,46 @@
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
const fields = [
|
||||
{ id: 'given-name', name: 'first', i18n: login.string.FirstName, short: true },
|
||||
{ id: 'family-name', name: 'last', i18n: login.string.LastName, short: true },
|
||||
{
|
||||
name: 'workspace',
|
||||
i18n: login.string.Workspace,
|
||||
rule: /^[0-9a-z][0-9a-z-]{2,62}[0-9a-z]$/,
|
||||
rules: [
|
||||
{
|
||||
rule: /^-/,
|
||||
notMatch: true,
|
||||
ruleDescr: login.string.WorkspaceNameRuleHyphen
|
||||
},
|
||||
{
|
||||
rule: /-$/,
|
||||
notMatch: true,
|
||||
ruleDescr: login.string.WorkspaceNameRuleHyphenEnd
|
||||
},
|
||||
{
|
||||
rule: /[A-Z]/,
|
||||
notMatch: true,
|
||||
ruleDescr: login.string.WorkspaceNameRuleCapital
|
||||
},
|
||||
{
|
||||
rule: /^[0-9a-z-]+$/,
|
||||
notMatch: false,
|
||||
ruleDescr: login.string.WorkspaceNameRule
|
||||
},
|
||||
{
|
||||
rule: /^[0-9a-z-]{3,}$/,
|
||||
notMatch: false,
|
||||
ruleDescr: login.string.WorkspaceNameRuleLengthLow
|
||||
},
|
||||
{
|
||||
rule: /^[0-9a-z-]{3,63}$/,
|
||||
notMatch: false,
|
||||
ruleDescr: login.string.WorkspaceNameRuleLengthHigh
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const object = {
|
||||
workspace: '',
|
||||
first: '',
|
||||
last: ''
|
||||
workspace: ''
|
||||
}
|
||||
|
||||
let status: Status<any> = OK
|
||||
@ -58,7 +84,7 @@
|
||||
func: async () => {
|
||||
status = new Status(Severity.INFO, login.status.ConnectingToServer, {})
|
||||
|
||||
const [loginStatus, result] = await createWorkspace(object.workspace, object.first, object.last)
|
||||
const [loginStatus, result] = await createWorkspace(object.workspace)
|
||||
status = loginStatus
|
||||
|
||||
if (result !== undefined) {
|
||||
|
@ -38,8 +38,11 @@
|
||||
password?: boolean
|
||||
optional?: boolean
|
||||
short?: boolean
|
||||
rule?: RegExp
|
||||
ruleDescr?: IntlString
|
||||
rules?: {
|
||||
rule: RegExp
|
||||
notMatch: boolean
|
||||
ruleDescr: IntlString
|
||||
}[]
|
||||
}
|
||||
|
||||
interface Action {
|
||||
@ -89,15 +92,15 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f.rule !== undefined) {
|
||||
if (!f.rule.test(v)) {
|
||||
status = new Status(Severity.INFO, login.status.IncorrectValue, {
|
||||
field: await translate(field.i18n, {}, language)
|
||||
})
|
||||
if (f.rules !== undefined) {
|
||||
for (const rule of f.rules) {
|
||||
if (rule.rule.test(v) === rule.notMatch) {
|
||||
status = new Status(Severity.INFO, rule.ruleDescr, {})
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
status = OK
|
||||
return true
|
||||
}
|
||||
@ -185,11 +188,6 @@
|
||||
trim(field.name)
|
||||
}}
|
||||
/>
|
||||
{#if field.ruleDescr}
|
||||
<div class="hint">
|
||||
<Label label={field.ruleDescr} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
|
@ -30,8 +30,6 @@
|
||||
$: fields =
|
||||
page === 'login'
|
||||
? [
|
||||
{ id: 'given-name', name: 'first', i18n: login.string.FirstName, short: true },
|
||||
{ id: 'family-name', name: 'last', i18n: login.string.LastName, short: true },
|
||||
{ id: 'email', name: 'username', i18n: login.string.Email },
|
||||
{
|
||||
id: 'current-password',
|
||||
@ -65,7 +63,7 @@
|
||||
|
||||
const [loginStatus, result] =
|
||||
page === 'login'
|
||||
? await join(object.username, object.password, object.first, object.last, location.query?.inviteId ?? '')
|
||||
? await join(object.username, object.password, location.query?.inviteId ?? '')
|
||||
: await signUpJoin(
|
||||
object.username,
|
||||
object.password,
|
||||
|
@ -22,6 +22,8 @@
|
||||
import Form from './Form.svelte'
|
||||
|
||||
const fields = [
|
||||
{ id: 'given-name', name: 'first', i18n: login.string.FirstName, short: true },
|
||||
{ id: 'family-name', name: 'last', i18n: login.string.LastName, short: true },
|
||||
{ id: 'email', name: 'username', i18n: login.string.Email },
|
||||
{ id: 'new-password', name: 'password', i18n: login.string.Password, password: true },
|
||||
{ id: 'new-password', name: 'password2', i18n: login.string.PasswordRepeat, password: true }
|
||||
@ -42,7 +44,7 @@
|
||||
func: async () => {
|
||||
status = new Status(Severity.INFO, login.status.ConnectingToServer, {})
|
||||
|
||||
const [loginStatus, result] = await signUp(object.username, object.password)
|
||||
const [loginStatus, result] = await signUp(object.username, object.password, object.first, object.last)
|
||||
|
||||
status = loginStatus
|
||||
|
||||
|
@ -49,6 +49,11 @@ export default mergeIds(loginId, login, {
|
||||
NotSeeingWorkspace: '' as IntlString,
|
||||
ChangeAccount: '' as IntlString,
|
||||
WorkspaceNameRule: '' as IntlString,
|
||||
WorkspaceNameRuleHyphen: '' as IntlString,
|
||||
WorkspaceNameRuleHyphenEnd: '' as IntlString,
|
||||
WorkspaceNameRuleLengthLow: '' as IntlString,
|
||||
WorkspaceNameRuleLengthHigh: '' as IntlString,
|
||||
WorkspaceNameRuleCapital: '' as IntlString,
|
||||
ForgotPassword: '' as IntlString,
|
||||
Recover: '' as IntlString,
|
||||
KnowPassword: '' as IntlString,
|
||||
|
@ -76,7 +76,12 @@ export async function doLogin (email: string, password: string): Promise<[Status
|
||||
}
|
||||
}
|
||||
|
||||
export async function signUp (email: string, password: string): Promise<[Status, LoginInfo | undefined]> {
|
||||
export async function signUp (
|
||||
email: string,
|
||||
password: string,
|
||||
first: string,
|
||||
last: string
|
||||
): Promise<[Status, LoginInfo | undefined]> {
|
||||
const accountsUrl = getMetadata(login.metadata.AccountsUrl)
|
||||
|
||||
if (accountsUrl === undefined) {
|
||||
@ -93,7 +98,7 @@ export async function signUp (email: string, password: string): Promise<[Status,
|
||||
|
||||
const request = {
|
||||
method: 'createAccount',
|
||||
params: [email, password]
|
||||
params: [email, password, first, last]
|
||||
}
|
||||
|
||||
try {
|
||||
@ -111,11 +116,7 @@ export async function signUp (email: string, password: string): Promise<[Status,
|
||||
}
|
||||
}
|
||||
|
||||
export async function createWorkspace (
|
||||
workspace: string,
|
||||
firstName: string,
|
||||
lastName: string
|
||||
): Promise<[Status, LoginInfo | undefined]> {
|
||||
export async function createWorkspace (workspace: string): Promise<[Status, LoginInfo | undefined]> {
|
||||
const accountsUrl = getMetadata(login.metadata.AccountsUrl)
|
||||
|
||||
if (accountsUrl === undefined) {
|
||||
@ -142,7 +143,7 @@ export async function createWorkspace (
|
||||
|
||||
const request = {
|
||||
method: 'createWorkspace',
|
||||
params: [workspace, firstName, lastName]
|
||||
params: [workspace]
|
||||
}
|
||||
|
||||
try {
|
||||
@ -425,8 +426,6 @@ export async function getInviteLink (expHours: number = 1, emailMask: string = '
|
||||
export async function join (
|
||||
email: string,
|
||||
password: string,
|
||||
first: string,
|
||||
last: string,
|
||||
inviteId: string
|
||||
): Promise<[Status, WorkspaceLoginInfo | undefined]> {
|
||||
const accountsUrl = getMetadata(login.metadata.AccountsUrl)
|
||||
@ -445,7 +444,7 @@ export async function join (
|
||||
|
||||
const request = {
|
||||
method: 'join',
|
||||
params: [email, password, first, last, inviteId]
|
||||
params: [email, password, inviteId]
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -87,7 +87,7 @@ describe('server', () => {
|
||||
})
|
||||
await methods.assignWorkspace(db, '', {
|
||||
method: 'assignWorkspace',
|
||||
params: ['andrey', workspace, 'firstName', 'lastName']
|
||||
params: ['andrey', workspace]
|
||||
})
|
||||
|
||||
const request: any = {
|
||||
@ -140,7 +140,7 @@ describe('server', () => {
|
||||
})
|
||||
await methods.assignWorkspace(db, '', {
|
||||
method: 'assignWorkspace',
|
||||
params: ['andrey', workspace, 'first', 'last']
|
||||
params: ['andrey', workspace]
|
||||
})
|
||||
|
||||
// Check we had one
|
||||
|
@ -101,6 +101,8 @@ export interface Account {
|
||||
salt: Binary
|
||||
workspaces: ObjectId[]
|
||||
// Defined for server admins only
|
||||
first: string
|
||||
last: string
|
||||
admin?: boolean
|
||||
confirmed?: boolean
|
||||
lastWorkspace?: number
|
||||
@ -347,14 +349,12 @@ export async function join (
|
||||
productId: string,
|
||||
email: string,
|
||||
password: string,
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
inviteId: ObjectId
|
||||
): Promise<WorkspaceLoginInfo> {
|
||||
const invite = await getInvite(db, inviteId)
|
||||
const workspace = await checkInvite(invite, email)
|
||||
console.log(`join attempt:${email}, ${workspace.name}`)
|
||||
await assignWorkspace(db, productId, email, workspace.name, firstName, lastName)
|
||||
await assignWorkspace(db, productId, email, workspace.name)
|
||||
|
||||
const token = (await login(db, productId, email, password)).token
|
||||
const result = await selectWorkspace(db, productId, token, workspace.name)
|
||||
@ -470,8 +470,8 @@ export async function signUpJoin (
|
||||
console.log(`signup join:${email} ${first} ${last}`)
|
||||
const invite = await getInvite(db, inviteId)
|
||||
const workspace = await checkInvite(invite, email)
|
||||
await createAcc(db, productId, email, password, invite?.emailMask === email)
|
||||
await assignWorkspace(db, productId, email, workspace.name, first, last)
|
||||
await createAcc(db, productId, email, password, first, last, invite?.emailMask === email)
|
||||
await assignWorkspace(db, productId, email, workspace.name)
|
||||
|
||||
const token = (await login(db, productId, email, password)).token
|
||||
const result = await selectWorkspace(db, productId, token, workspace.name)
|
||||
@ -487,6 +487,8 @@ export async function createAcc (
|
||||
productId: string,
|
||||
email: string,
|
||||
password: string,
|
||||
first: string,
|
||||
last: string,
|
||||
confirmed: boolean = false
|
||||
): Promise<Account> {
|
||||
const salt = randomBytes(32)
|
||||
@ -506,6 +508,8 @@ export async function createAcc (
|
||||
email,
|
||||
hash,
|
||||
salt,
|
||||
first,
|
||||
last,
|
||||
confirmed,
|
||||
workspaces: []
|
||||
})
|
||||
@ -523,8 +527,15 @@ export async function createAcc (
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function createAccount (db: Db, productId: string, email: string, password: string): Promise<LoginInfo> {
|
||||
const account = await createAcc(db, productId, email, password, false)
|
||||
export async function createAccount (
|
||||
db: Db,
|
||||
productId: string,
|
||||
email: string,
|
||||
password: string,
|
||||
first: string,
|
||||
last: string
|
||||
): Promise<LoginInfo> {
|
||||
const account = await createAcc(db, productId, email, password, first, last, false)
|
||||
|
||||
const result = {
|
||||
endpoint: getEndpoint(),
|
||||
@ -623,14 +634,7 @@ export async function upgradeWorkspace (
|
||||
*/
|
||||
export const createUserWorkspace =
|
||||
(version: Data<Version>, txes: Tx[], migrationOperation: [string, MigrateOperation][]) =>
|
||||
async (
|
||||
db: Db,
|
||||
productId: string,
|
||||
token: string,
|
||||
workspace: string,
|
||||
firstName: string,
|
||||
lastName: string
|
||||
): Promise<LoginInfo> => {
|
||||
async (db: Db, productId: string, token: string, workspace: string): Promise<LoginInfo> => {
|
||||
if (!/^[0-9a-z][0-9a-z-]{2,62}[0-9a-z]$/.test(workspace)) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.InvalidId, { id: workspace }))
|
||||
}
|
||||
@ -678,7 +682,7 @@ export const createUserWorkspace =
|
||||
// Update last workspace time.
|
||||
await db.collection(ACCOUNT_COLLECTION).updateOne({ _id: info._id }, { $set: { lastWorkspace: Date.now() } })
|
||||
|
||||
await assignWorkspace(db, productId, email, workspace, firstName, lastName)
|
||||
await assignWorkspace(db, productId, email, workspace)
|
||||
await setRole(email, workspace, productId, AccountRole.Owner)
|
||||
const result = {
|
||||
endpoint: getEndpoint(),
|
||||
@ -787,14 +791,7 @@ export async function setRole (email: string, workspace: string, productId: stri
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function assignWorkspace (
|
||||
db: Db,
|
||||
productId: string,
|
||||
email: string,
|
||||
workspace: string,
|
||||
firstName: string,
|
||||
lastName: string
|
||||
): Promise<void> {
|
||||
export async function assignWorkspace (db: Db, productId: string, email: string, workspace: string): Promise<void> {
|
||||
const initWS = getMetadata(toolPlugin.metadata.InitWorkspace)
|
||||
if (initWS !== undefined && initWS === workspace) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
||||
@ -802,7 +799,7 @@ export async function assignWorkspace (
|
||||
const { workspaceId, accountId } = await getWorkspaceAndAccount(db, productId, email, workspace)
|
||||
const account = await db.collection<Account>(ACCOUNT_COLLECTION).findOne({ _id: accountId })
|
||||
|
||||
if (account !== null) await createPersonAccount(account, productId, workspace, firstName, lastName)
|
||||
if (account !== null) await createPersonAccount(account, productId, workspace)
|
||||
|
||||
// Add account into workspace.
|
||||
await db.collection(WORKSPACE_COLLECTION).updateOne({ _id: workspaceId }, { $addToSet: { accounts: accountId } })
|
||||
@ -836,18 +833,12 @@ async function createEmployee (ops: TxOperations, name: string, email: string):
|
||||
return id
|
||||
}
|
||||
|
||||
async function createPersonAccount (
|
||||
account: Account,
|
||||
productId: string,
|
||||
workspace: string,
|
||||
firstName: string,
|
||||
lastName: string
|
||||
): Promise<void> {
|
||||
async function createPersonAccount (account: Account, productId: string, workspace: string): Promise<void> {
|
||||
const connection = await connect(getTransactor(), getWorkspaceId(workspace, productId))
|
||||
try {
|
||||
const ops = new TxOperations(connection, core.account.System)
|
||||
|
||||
const name = combineName(firstName, lastName)
|
||||
const name = combineName(account.first, account.last)
|
||||
// Check if EmployeeAccoun is not exists
|
||||
const existingAccount = await ops.findOne(contact.class.PersonAccount, { email: account.email })
|
||||
if (existingAccount === undefined) {
|
||||
|
@ -10,7 +10,7 @@ export SERVER_SECRET=secret
|
||||
# Create workspace record in accounts
|
||||
node ../dev/tool/bundle.js create-workspace sanity-ws -o SanityTest
|
||||
# Create user record in accounts
|
||||
node ../dev/tool/bundle.js create-account user1 -p 1234
|
||||
node ../dev/tool/bundle.js create-account user1 -f John -l Appleseed -p 1234
|
||||
node ../dev/tool/bundle.js confirm-email user1
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ node ../dev/tool/bundle.js backup-restore ./sanity-ws sanity-ws
|
||||
node ../dev/tool/bundle.js upgrade-workspace sanity-ws
|
||||
|
||||
# Re-assign user to workspace.
|
||||
node ../dev/tool/bundle.js assign-workspace user1 sanity-ws -f John -l Appleseed
|
||||
node ../dev/tool/bundle.js assign-workspace user1 sanity-ws
|
||||
|
||||
node ../dev/tool/bundle.js configure sanity-ws --enable=*
|
||||
node ../dev/tool/bundle.js configure sanity-ws --list
|
@ -9,7 +9,7 @@ docker-compose -p sanity up -d --force-recreate --renew-anon-volumes
|
||||
# Create workspace record in accounts
|
||||
./tool.sh create-workspace sanity-ws -o SanityTest
|
||||
# Create user record in accounts
|
||||
./tool.sh create-account user1 -p 1234
|
||||
./tool.sh create-account user1 -f John -l Appleseed -p 1234
|
||||
# Make user the workspace maintainer
|
||||
./tool.sh set-user-role user1 sanity-ws 1
|
||||
./tool.sh confirm-email user1
|
||||
|
@ -13,7 +13,7 @@ node ../dev/tool/bundle.js backup-restore ./sanity-ws sanity-ws
|
||||
node ../dev/tool/bundle.js upgrade-workspace sanity-ws
|
||||
|
||||
# Re-assign user to workspace.
|
||||
node ../dev/tool/bundle.js assign-workspace user1 sanity-ws -f John -l Appleseed
|
||||
node ../dev/tool/bundle.js assign-workspace user1 sanity-ws
|
||||
|
||||
node ../dev/tool/bundle.js configure sanity-ws --enable=*
|
||||
node ../dev/tool/bundle.js configure sanity-ws --list
|
@ -6,7 +6,7 @@
|
||||
./tool.sh upgrade-workspace sanity-ws
|
||||
|
||||
# Re-assign user to workspace.
|
||||
./tool.sh assign-workspace user1 sanity-ws -f John -l Appleseed
|
||||
./tool.sh assign-workspace user1 sanity-ws
|
||||
|
||||
./tool.sh configure sanity-ws --enable=*
|
||||
./tool.sh configure sanity-ws --list
|
||||
|
Loading…
Reference in New Issue
Block a user