Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov 2023-08-24 21:51:30 +06:00 committed by GitHub
parent 9396f7ef20
commit 821ed6cd7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 233 additions and 230 deletions

View File

@ -114,13 +114,11 @@ export function devTool (
.command('create-account <email>') .command('create-account <email>')
.description('create user and corresponding account in master database') .description('create user and corresponding account in master database')
.requiredOption('-p, --password <password>', 'user password') .requiredOption('-p, --password <password>', 'user password')
.requiredOption('-f, --first <first>', 'first name')
.requiredOption('-l, --last <last>', 'last name')
.action(async (email: string, cmd) => { .action(async (email: string, cmd) => {
const { mongodbUri } = prepareTools() const { mongodbUri } = prepareTools()
return await withDatabase(mongodbUri, async (db) => { return await withDatabase(mongodbUri, async (db) => {
console.log(`creating account ${cmd.first as string} ${cmd.last as string} (${email})...`) console.log(`creating account ${cmd.first as string} ${cmd.last as string} (${email})...`)
await createAcc(db, productId, email, cmd.password, cmd.first, cmd.last, true) await createAcc(db, productId, email, cmd.password, true)
}) })
}) })
@ -139,11 +137,13 @@ export function devTool (
program program
.command('assign-workspace <email> <workspace>') .command('assign-workspace <email> <workspace>')
.description('assign workspace') .description('assign workspace')
.requiredOption('-f, --first <first>', 'first name')
.requiredOption('-l, --last <last>', 'last name')
.action(async (email: string, workspace: string, cmd) => { .action(async (email: string, workspace: string, cmd) => {
const { mongodbUri } = prepareTools() const { mongodbUri } = prepareTools()
return await withDatabase(mongodbUri, async (db, client) => { return await withDatabase(mongodbUri, async (db, client) => {
console.log(`assigning user ${email} to ${workspace}...`) console.log(`assigning user ${email} to ${workspace}...`)
await assignWorkspace(db, productId, email, workspace) await assignWorkspace(db, productId, email, workspace, cmd.first, cmd.last)
}) })
}) })

View File

@ -90,7 +90,6 @@ export class TChannelProvider extends TDoc implements ChannelProvider {
export class TContact extends TDoc implements Contact { export class TContact extends TDoc implements Contact {
@Prop(TypeString(), contact.string.Name) @Prop(TypeString(), contact.string.Name)
@Index(IndexKind.FullText) @Index(IndexKind.FullText)
@Hidden()
name!: string name!: string
avatar?: string | null avatar?: string | null
@ -168,10 +167,6 @@ export class TEmployee extends TPerson implements Employee {
@Hidden() @Hidden()
statuses?: number statuses?: number
@Prop(TypeString(), contact.string.DisplayName)
@Hidden()
displayName?: string | null
@Prop(TypeString(), contact.string.Position) @Prop(TypeString(), contact.string.Position)
@Hidden() @Hidden()
position?: string | null position?: string | null
@ -293,6 +288,15 @@ export function createModel (builder: Builder): void {
index: 100 index: 100
}) })
builder.createDoc(activity.class.TxViewlet, core.space.Model, {
objectClass: contact.class.Person,
icon: contact.icon.Person,
txClass: core.class.TxUpdateDoc,
labelComponent: contact.activity.TxNameChange,
display: 'inline',
match: { 'operations.name': { $exists: true } }
})
builder.createDoc<Viewlet>( builder.createDoc<Viewlet>(
view.class.Viewlet, view.class.Viewlet,
core.space.Model, core.space.Model,

View File

@ -26,6 +26,9 @@ import type { AnyComponent } from '@hcengineering/ui'
import { Action, ActionCategory, ViewAction } from '@hcengineering/view' import { Action, ActionCategory, ViewAction } from '@hcengineering/view'
export default mergeIds(contactId, contact, { export default mergeIds(contactId, contact, {
activity: {
TxNameChange: '' as AnyComponent
},
component: { component: {
PersonPresenter: '' as AnyComponent, PersonPresenter: '' as AnyComponent,
ContactRefPresenter: '' as AnyComponent, ContactRefPresenter: '' as AnyComponent,

View File

@ -139,7 +139,6 @@ export function createModel (builder: Builder): void {
core.space.Model, core.space.Model,
{ {
email: systemAccountEmail, email: systemAccountEmail,
name: systemAccountEmail,
role: AccountRole.Owner role: AccountRole.Owner
}, },
core.account.System core.account.System

View File

@ -48,6 +48,5 @@ export class TSpace extends TDoc implements Space {
@UX(core.string.Account, undefined, undefined, 'name') @UX(core.string.Account, undefined, undefined, 'name')
export class TAccount extends TDoc implements Account { export class TAccount extends TDoc implements Account {
email!: string email!: string
name!: string
role!: AccountRole role!: AccountRole
} }

View File

@ -238,7 +238,6 @@ describe('memdb', () => {
}) })
const account = await model.createDoc(core.class.Account, core.space.Model, { const account = await model.createDoc(core.class.Account, core.space.Model, {
email: 'email', email: 'email',
name: 'test',
role: 0 role: 0
}) })
await model.updateDoc(core.class.Space, core.space.Model, space, { $push: { members: account } }) await model.updateDoc(core.class.Space, core.space.Model, space, { $push: { members: account } })

View File

@ -329,7 +329,6 @@ export interface Space extends Doc {
* @public * @public
*/ */
export interface Account extends Doc { export interface Account extends Doc {
name: string
email: string email: string
role: AccountRole role: AccountRole
} }

View File

@ -194,8 +194,8 @@ export function genMinModel (): TxCUD<Doc>[] {
const u1 = 'User1' as Ref<Account> const u1 = 'User1' as Ref<Account>
const u2 = 'User2' as Ref<Account> const u2 = 'User2' as Ref<Account>
txes.push( txes.push(
createDoc(core.class.Account, { email: 'user1@site.com', name: 'user1', role: 0 }, u1), createDoc(core.class.Account, { email: 'user1@site.com', role: 0 }, u1),
createDoc(core.class.Account, { email: 'user2@site.com', name: 'user2', role: 0 }, u2), createDoc(core.class.Account, { email: 'user2@site.com', role: 0 }, u2),
createDoc(core.class.Space, { createDoc(core.class.Space, {
name: 'Sp1', name: 'Sp1',
description: '', description: '',

View File

@ -101,7 +101,6 @@ describe('query', () => {
await factory.createDoc(core.class.Account, core.space.Model, { await factory.createDoc(core.class.Account, core.space.Model, {
email: 'user1@site.com', email: 'user1@site.com',
name: 'user1',
role: 0 role: 0
}) })
await factory.createDoc<Channel>(core.class.Space, core.space.Model, { await factory.createDoc<Channel>(core.class.Space, core.space.Model, {

View File

@ -46,7 +46,7 @@
const activityQuery = newActivity(client, attrs) const activityQuery = newActivity(client, attrs)
let viewlets: Map<ActivityKey, TxViewlet> let viewlets: Map<ActivityKey, TxViewlet[]> = new Map()
let allViewlets: TxViewlet[] = [] let allViewlets: TxViewlet[] = []
let editableMap: Map<Ref<Class<Doc>>, boolean> | undefined = undefined let editableMap: Map<Ref<Class<Doc>>, boolean> | undefined = undefined
@ -61,7 +61,18 @@
) )
}) })
$: viewlets = new Map(allViewlets.map((r) => [activityKey(r.objectClass, r.txClass), r])) $: viewlets = buildViewletsMap(allViewlets)
function buildViewletsMap (allViewlets: TxViewlet[]): Map<ActivityKey, TxViewlet[]> {
const viewlets = new Map()
for (const res of allViewlets) {
const key = activityKey(res.objectClass, res.txClass)
const arr = viewlets.get(key) ?? []
arr.push(res)
viewlets.set(key, arr)
}
return viewlets
}
let loading = false let loading = false

View File

@ -43,7 +43,7 @@
import TxViewTx from './TxViewTx.svelte' import TxViewTx from './TxViewTx.svelte'
export let tx: DisplayTx export let tx: DisplayTx
export let viewlets: Map<ActivityKey, TxViewlet> export let viewlets: Map<ActivityKey, TxViewlet[]>
export let showIcon: boolean = true export let showIcon: boolean = true
export let isNew: boolean = false export let isNew: boolean = false
export let isNextNew: boolean = false export let isNextNew: boolean = false

View File

@ -5,6 +5,7 @@ import core, {
Client, Client,
Collection, Collection,
Doc, Doc,
Hierarchy,
Obj, Obj,
Ref, Ref,
TxCUD, TxCUD,
@ -14,7 +15,8 @@ import core, {
TxOperations, TxOperations,
TxProcessor, TxProcessor,
TxUpdateDoc, TxUpdateDoc,
getObjectValue getObjectValue,
matchQuery
} from '@hcengineering/core' } from '@hcengineering/core'
import { Asset, IntlString, getResource, translate } from '@hcengineering/platform' import { Asset, IntlString, getResource, translate } from '@hcengineering/platform'
import { getAttributePresenterClass } from '@hcengineering/presentation' import { getAttributePresenterClass } from '@hcengineering/presentation'
@ -82,7 +84,11 @@ export function getDTxProps (dtx: DisplayTx): any {
return { tx: dtx.tx, value: dtx.doc, isOwnTx: dtx.isOwnTx, prevValue: dtx.prevDoc } return { tx: dtx.tx, value: dtx.doc, isOwnTx: dtx.isOwnTx, prevValue: dtx.prevDoc }
} }
function getViewlet (viewlets: Map<ActivityKey, TxViewlet>, dtx: DisplayTx): TxDisplayViewlet | undefined { function getViewlet (
viewlets: Map<ActivityKey, TxViewlet[]>,
dtx: DisplayTx,
hierarchy: Hierarchy
): TxDisplayViewlet | undefined {
let key: string let key: string
if (dtx.mixinTx?.mixin !== undefined && dtx.tx._id === dtx.mixinTx._id) { if (dtx.mixinTx?.mixin !== undefined && dtx.tx._id === dtx.mixinTx._id) {
key = activityKey(dtx.mixinTx.mixin, dtx.tx._class) key = activityKey(dtx.mixinTx.mixin, dtx.tx._class)
@ -91,13 +97,21 @@ function getViewlet (viewlets: Map<ActivityKey, TxViewlet>, dtx: DisplayTx): TxD
} }
const vl = viewlets.get(key) const vl = viewlets.get(key)
if (vl !== undefined) { if (vl !== undefined) {
return { ...vl, pseudo: false } for (const viewlet of vl) {
if (viewlet.match === undefined) {
return { ...viewlet, pseudo: false }
}
const res = matchQuery([dtx.tx], viewlet.match, dtx.tx._class, hierarchy)
if (res.length > 0) {
return { ...viewlet, pseudo: false }
}
}
} }
} }
export async function updateViewlet ( export async function updateViewlet (
client: TxOperations, client: TxOperations,
viewlets: Map<ActivityKey, TxViewlet>, viewlets: Map<ActivityKey, TxViewlet[]>,
dtx: DisplayTx dtx: DisplayTx
): Promise<{ ): Promise<{
viewlet: TxDisplayViewlet viewlet: TxDisplayViewlet
@ -107,7 +121,7 @@ export async function updateViewlet (
modelIcon: Asset | undefined modelIcon: Asset | undefined
iconComponent: AnyComponent | undefined iconComponent: AnyComponent | undefined
}> { }> {
let viewlet = getViewlet(viewlets, dtx) let viewlet = getViewlet(viewlets, dtx, client.getHierarchy())
const props = getDTxProps(dtx) const props = getDTxProps(dtx)
let model: AttributeModel[] = [] let model: AttributeModel[] = []

View File

@ -946,7 +946,6 @@ async function synchronizeUsers (
}) })
accountId = await ops.client.createDoc(contact.class.PersonAccount, core.space.Model, { accountId = await ops.client.createDoc(contact.class.PersonAccount, core.space.Model, {
email: u.EMAIL, email: u.EMAIL,
name: combineName(u.NAME, u.LAST_NAME),
person: employeeId, person: employeeId,
role: AccountRole.User role: AccountRole.User
}) })

View File

@ -83,7 +83,6 @@
"MergePersons": "Merge contacts", "MergePersons": "Merge contacts",
"MergePersonsFrom": "Source contact", "MergePersonsFrom": "Source contact",
"MergePersonsTo": "Final contact", "MergePersonsTo": "Final contact",
"DisplayName": "Display name",
"SelectAvatar": "Select avatar", "SelectAvatar": "Select avatar",
"AvatarProvider": "Avatar provider", "AvatarProvider": "Avatar provider",
"GravatarsManaged": "Gravatars are managed", "GravatarsManaged": "Gravatars are managed",

View File

@ -84,7 +84,6 @@
"MergePersons": "Объеденить контакта", "MergePersons": "Объеденить контакта",
"MergePersonsFrom": "Исходный контакт", "MergePersonsFrom": "Исходный контакт",
"MergePersonsTo": "Финальный контакт", "MergePersonsTo": "Финальный контакт",
"DisplayName": "Отображаемое имя",
"SelectAvatar": "Выбрать аватар", "SelectAvatar": "Выбрать аватар",
"GravatarsManaged": "Граватары управляются", "GravatarsManaged": "Граватары управляются",
"Through": "через", "Through": "через",

View File

@ -62,7 +62,6 @@
await client.createDoc(contact.class.PersonAccount, core.space.Model, { await client.createDoc(contact.class.PersonAccount, core.space.Model, {
email: email.trim(), email: email.trim(),
name,
person: id, person: id,
role: AccountRole.User role: AccountRole.User
}) })

View File

@ -14,13 +14,19 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import { Channel, Employee, PersonAccount, getFirstName, getLastName, Person } from '@hcengineering/contact' import {
import { AccountRole, getCurrentAccount, Ref } from '@hcengineering/core' Channel,
import login from '@hcengineering/login' Employee,
import { getResource } from '@hcengineering/platform' Person,
PersonAccount,
combineName,
getFirstName,
getLastName
} from '@hcengineering/contact'
import { AccountRole, Ref, getCurrentAccount } from '@hcengineering/core'
import { AttributeEditor, createQuery, getClient } from '@hcengineering/presentation' import { AttributeEditor, createQuery, getClient } from '@hcengineering/presentation'
import setting, { IntegrationType } from '@hcengineering/setting' import setting, { IntegrationType } from '@hcengineering/setting'
import { createFocusManager, EditBox, FocusHandler, Scroller } from '@hcengineering/ui' import { EditBox, FocusHandler, Scroller, createFocusManager } from '@hcengineering/ui'
import { createEventDispatcher, onMount } from 'svelte' import { createEventDispatcher, onMount } from 'svelte'
import { ChannelsDropdown } from '..' import { ChannelsDropdown } from '..'
import contact from '../plugin' import contact from '../plugin'
@ -61,13 +67,15 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
async function firstNameChange () { async function firstNameChange () {
const changeName = await getResource(login.function.ChangeName) await client.update(object, {
await changeName(firstName, getLastName(object.name)) name: combineName(firstName, getLastName(object.name))
})
} }
async function lastNameChange () { async function lastNameChange () {
const changeName = await getResource(login.function.ChangeName) await client.update(object, {
await changeName(getFirstName(object.name), lastName) name: combineName(getFirstName(object.name), lastName)
})
} }
let integrations: Set<Ref<IntegrationType>> = new Set<Ref<IntegrationType>>() let integrations: Set<Ref<IntegrationType>> = new Set<Ref<IntegrationType>>()
@ -76,7 +84,7 @@
integrations = new Set(res.map((p) => p.type)) integrations = new Set(res.map((p) => p.type))
}) })
const sendOpen = () => dispatch('open', { ignoreKeys: ['comments', 'name', 'channels', 'city', 'displayName'] }) const sendOpen = () => dispatch('open', { ignoreKeys: ['comments', 'name', 'channels', 'city'] })
onMount(sendOpen) onMount(sendOpen)
async function onAvatarDone () { async function onAvatarDone () {

View File

@ -0,0 +1,34 @@
<!--
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import { Person, formatName } from '@hcengineering/contact'
import { TxUpdateDoc } from '@hcengineering/core'
import contact from '../../plugin'
import { Label } from '@hcengineering/ui'
import activity from '@hcengineering/activity'
export let tx: TxUpdateDoc<Person>
const val = tx.operations.name
</script>
{#if val}
<span class="lower"><Label label={activity.string.Changed} /></span>
<span class="lower"><Label label={contact.string.Name} /></span>
<span class="lower"><Label label={activity.string.To} /></span>
<span class="strong overflow-label">
{formatName(val)}
</span>
{/if}

View File

@ -88,6 +88,7 @@ import ActivityChannelMessage from './components/activity/ActivityChannelMessage
import ActivityChannelPresenter from './components/activity/ActivityChannelPresenter.svelte' import ActivityChannelPresenter from './components/activity/ActivityChannelPresenter.svelte'
import ExpandRightDouble from './components/icons/ExpandRightDouble.svelte' import ExpandRightDouble from './components/icons/ExpandRightDouble.svelte'
import IconMembers from './components/icons/Members.svelte' import IconMembers from './components/icons/Members.svelte'
import TxNameChange from './components/activity/TxNameChange.svelte'
import contact from './plugin' import contact from './plugin'
import { import {
@ -274,6 +275,9 @@ export default async (): Promise<Resources> => ({
KickEmployee: kickEmployee, KickEmployee: kickEmployee,
OpenChannel: openChannelURL OpenChannel: openChannelURL
}, },
activity: {
TxNameChange
},
component: { component: {
ContactArrayEditor, ContactArrayEditor,
PersonEditor, PersonEditor,

View File

@ -140,7 +140,9 @@ export async function getRefs (
export async function getCurrentEmployeeName (): Promise<string> { export async function getCurrentEmployeeName (): Promise<string> {
const me = getCurrentAccount() as PersonAccount const me = getCurrentAccount() as PersonAccount
return formatName(me.name) const client = getClient()
const employee = await client.findOne(contact.class.Person, { _id: me.person })
return employee !== undefined ? formatName(employee.name) : ''
} }
export async function getCurrentEmployeeEmail (): Promise<string> { export async function getCurrentEmployeeEmail (): Promise<string> {

View File

@ -139,7 +139,6 @@ export interface Status extends AttachedDoc {
export interface Employee extends Person { export interface Employee extends Person {
active: boolean active: boolean
statuses?: number statuses?: number
displayName?: string | null
position?: string | null position?: string | null
} }
@ -263,7 +262,6 @@ export const contactPlugin = plugin(contactId, {
UseColor: '' as IntlString, UseColor: '' as IntlString,
PersonFirstNamePlaceholder: '' as IntlString, PersonFirstNamePlaceholder: '' as IntlString,
PersonLastNamePlaceholder: '' as IntlString, PersonLastNamePlaceholder: '' as IntlString,
DisplayName: '' as IntlString,
NumberMembers: '' as IntlString, NumberMembers: '' as IntlString,
Position: '' as IntlString Position: '' as IntlString
}, },

View File

@ -16,7 +16,7 @@
import { AttachedData, Class, Client, Doc, FindResult, Ref, Hierarchy } from '@hcengineering/core' import { AttachedData, Class, Client, Doc, FindResult, Ref, Hierarchy } from '@hcengineering/core'
import { IconSize } from '@hcengineering/ui' import { IconSize } from '@hcengineering/ui'
import { MD5 } from 'crypto-js' import { MD5 } from 'crypto-js'
import { Channel, Contact, contactPlugin, Employee, Person } from '.' import { Channel, Contact, contactPlugin, Person } from '.'
import { AVATAR_COLORS, GravatarPlaceholderType } from './types' import { AVATAR_COLORS, GravatarPlaceholderType } from './types'
/** /**
@ -212,19 +212,12 @@ export function formatName (name: string): string {
* @public * @public
*/ */
export function getName (hierarchy: Hierarchy, value: Contact): string { export function getName (hierarchy: Hierarchy, value: Contact): string {
if (isEmployee(hierarchy, value)) { if (isPerson(hierarchy, value)) {
return hierarchy.as(value, contactPlugin.mixin.Employee).displayName ?? formatName(value.name)
}
if (isPerson(value)) {
return formatName(value.name) return formatName(value.name)
} }
return value.name return value.name
} }
function isEmployee (hierarchy: Hierarchy, value: Contact): value is Employee { function isPerson (hierarchy: Hierarchy, value: Contact): value is Person {
return hierarchy.hasMixin(value, contactPlugin.mixin.Employee) return hierarchy.isDerived(value._class, contactPlugin.class.Person)
}
function isPerson (value: Contact): value is Person {
return value._class === contactPlugin.class.Person
} }

View File

@ -25,6 +25,8 @@
import { onMount } from 'svelte' import { onMount } from 'svelte'
const fields = [ 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', name: 'workspace',
i18n: login.string.Workspace, i18n: login.string.Workspace,
@ -34,7 +36,9 @@
] ]
const object = { const object = {
workspace: '' workspace: '',
first: '',
last: ''
} }
let status: Status<any> = OK let status: Status<any> = OK
@ -54,7 +58,7 @@
func: async () => { func: async () => {
status = new Status(Severity.INFO, login.status.ConnectingToServer, {}) status = new Status(Severity.INFO, login.status.ConnectingToServer, {})
const [loginStatus, result] = await createWorkspace(object.workspace) const [loginStatus, result] = await createWorkspace(object.workspace, object.first, object.last)
status = loginStatus status = loginStatus
if (result !== undefined) { if (result !== undefined) {

View File

@ -30,6 +30,8 @@
$: fields = $: fields =
page === 'login' 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: 'email', name: 'username', i18n: login.string.Email },
{ {
id: 'current-password', id: 'current-password',
@ -63,7 +65,7 @@
const [loginStatus, result] = const [loginStatus, result] =
page === 'login' page === 'login'
? await join(object.username, object.password, location.query?.inviteId ?? '') ? await join(object.username, object.password, object.first, object.last, location.query?.inviteId ?? '')
: await signUpJoin( : await signUpJoin(
object.username, object.username,
object.password, object.password,

View File

@ -22,8 +22,6 @@
import Form from './Form.svelte' import Form from './Form.svelte'
const fields = [ 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: 'email', name: 'username', i18n: login.string.Email },
{ id: 'new-password', name: 'password', i18n: login.string.Password, password: true }, { id: 'new-password', name: 'password', i18n: login.string.Password, password: true },
{ id: 'new-password', name: 'password2', i18n: login.string.PasswordRepeat, password: true } { id: 'new-password', name: 'password2', i18n: login.string.PasswordRepeat, password: true }
@ -44,7 +42,7 @@
func: async () => { func: async () => {
status = new Status(Severity.INFO, login.status.ConnectingToServer, {}) status = new Status(Severity.INFO, login.status.ConnectingToServer, {})
const [loginStatus, result] = await signUp(object.username, object.password, object.first, object.last) const [loginStatus, result] = await signUp(object.username, object.password)
status = loginStatus status = loginStatus

View File

@ -16,7 +16,7 @@
import InviteLink from './components/InviteLink.svelte' import InviteLink from './components/InviteLink.svelte'
import LoginApp from './components/LoginApp.svelte' import LoginApp from './components/LoginApp.svelte'
import { changeName, changePassword, getWorkspaces, leaveWorkspace, selectWorkspace, sendInvite } from './utils' import { changePassword, getWorkspaces, leaveWorkspace, selectWorkspace, sendInvite } from './utils'
/*! /*!
* Anticrm Platform Login Plugin * Anticrm Platform Login Plugin
* © 2020, 2021 Anticrm Platform Contributors. * © 2020, 2021 Anticrm Platform Contributors.
@ -30,7 +30,6 @@ export default async () => ({
InviteLink InviteLink
}, },
function: { function: {
ChangeName: changeName,
LeaveWorkspace: leaveWorkspace, LeaveWorkspace: leaveWorkspace,
ChangePassword: changePassword, ChangePassword: changePassword,
SelectWorkspace: selectWorkspace, SelectWorkspace: selectWorkspace,

View File

@ -76,12 +76,7 @@ export async function doLogin (email: string, password: string): Promise<[Status
} }
} }
export async function signUp ( export async function signUp (email: string, password: string): Promise<[Status, LoginInfo | undefined]> {
email: string,
password: string,
first: string,
last: string
): Promise<[Status, LoginInfo | undefined]> {
const accountsUrl = getMetadata(login.metadata.AccountsUrl) const accountsUrl = getMetadata(login.metadata.AccountsUrl)
if (accountsUrl === undefined) { if (accountsUrl === undefined) {
@ -98,7 +93,7 @@ export async function signUp (
const request = { const request = {
method: 'createAccount', method: 'createAccount',
params: [email, password, first, last] params: [email, password]
} }
try { try {
@ -116,7 +111,11 @@ export async function signUp (
} }
} }
export async function createWorkspace (workspace: string): Promise<[Status, LoginInfo | undefined]> { export async function createWorkspace (
workspace: string,
firstName: string,
lastName: string
): Promise<[Status, LoginInfo | undefined]> {
const accountsUrl = getMetadata(login.metadata.AccountsUrl) const accountsUrl = getMetadata(login.metadata.AccountsUrl)
if (accountsUrl === undefined) { if (accountsUrl === undefined) {
@ -143,7 +142,7 @@ export async function createWorkspace (workspace: string): Promise<[Status, Logi
const request = { const request = {
method: 'createWorkspace', method: 'createWorkspace',
params: [workspace] params: [workspace, firstName, lastName]
} }
try { try {
@ -426,6 +425,8 @@ export async function getInviteLink (expHours: number = 1, emailMask: string = '
export async function join ( export async function join (
email: string, email: string,
password: string, password: string,
first: string,
last: string,
inviteId: string inviteId: string
): Promise<[Status, WorkspaceLoginInfo | undefined]> { ): Promise<[Status, WorkspaceLoginInfo | undefined]> {
const accountsUrl = getMetadata(login.metadata.AccountsUrl) const accountsUrl = getMetadata(login.metadata.AccountsUrl)
@ -444,7 +445,7 @@ export async function join (
const request = { const request = {
method: 'join', method: 'join',
params: [email, password, inviteId] params: [email, password, first, last, inviteId]
} }
try { try {
@ -503,37 +504,6 @@ export async function signUpJoin (
} }
} }
export async function changeName (first: string, last: string): Promise<void> {
const accountsUrl = getMetadata(login.metadata.AccountsUrl)
if (accountsUrl === undefined) {
throw new Error('accounts url not specified')
}
const overrideToken = getMetadata(login.metadata.OverrideLoginToken)
if (overrideToken !== undefined) {
const endpoint = getMetadata(login.metadata.OverrideEndpoint)
if (endpoint !== undefined) {
return
}
}
const token = getMetadata(presentation.metadata.Token) as string
const request = {
method: 'changeName',
params: [first, last]
}
await fetch(accountsUrl, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + token,
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
})
}
export async function changePassword (oldPassword: string, password: string): Promise<void> { export async function changePassword (oldPassword: string, password: string): Promise<void> {
const accountsUrl = getMetadata(login.metadata.AccountsUrl) const accountsUrl = getMetadata(login.metadata.AccountsUrl)

View File

@ -69,7 +69,6 @@ export default plugin(loginId, {
InviteLimit: '' as IntlString InviteLimit: '' as IntlString
}, },
function: { function: {
ChangeName: '' as Resource<(first: string, last: string) => Promise<void>>,
SendInvite: '' as Resource<(email: string) => Promise<void>>, SendInvite: '' as Resource<(email: string) => Promise<void>>,
LeaveWorkspace: '' as Resource<(email: string) => Promise<void>>, LeaveWorkspace: '' as Resource<(email: string) => Promise<void>>,
ChangePassword: '' as Resource<(oldPassword: string, password: string) => Promise<void>>, ChangePassword: '' as Resource<(oldPassword: string, password: string) => Promise<void>>,

View File

@ -106,7 +106,7 @@
} }
} }
let viewlets: Map<ActivityKey, TxViewlet> let viewlets: Map<ActivityKey, TxViewlet[]>
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => { const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {
if (dir === 'vertical') { if (dir === 'vertical') {
@ -121,7 +121,14 @@
const descriptors = createQuery() const descriptors = createQuery()
descriptors.query(activity.class.TxViewlet, {}, (result) => { descriptors.query(activity.class.TxViewlet, {}, (result) => {
viewlets = new Map(result.map((r) => [activityKey(r.objectClass, r.txClass), r])) viewlets = new Map()
for (const res of result) {
const key = activityKey(res.objectClass, res.txClass)
const arr = viewlets.get(key) ?? []
arr.push(res)
viewlets.set(key, arr)
}
viewlets = viewlets
}) })
let selected = 0 let selected = 0

View File

@ -105,11 +105,18 @@
} }
} }
let viewlets: Map<ActivityKey, TxViewlet> let viewlets: Map<ActivityKey, TxViewlet[]>
const descriptors = createQuery() const descriptors = createQuery()
descriptors.query(activity.class.TxViewlet, {}, (result) => { descriptors.query(activity.class.TxViewlet, {}, (result) => {
viewlets = new Map(result.map((r) => [activityKey(r.objectClass, r.txClass), r])) viewlets = new Map()
for (const res of result) {
const key = activityKey(res.objectClass, res.txClass)
const arr = viewlets.get(key) ?? []
arr.push(res)
viewlets.set(key, arr)
}
viewlets = viewlets
}) })
let selected = 0 let selected = 0

View File

@ -26,7 +26,7 @@
import TxView from './TxView.svelte' import TxView from './TxView.svelte'
export let value: DocUpdates export let value: DocUpdates
export let viewlets: Map<ActivityKey, TxViewlet> export let viewlets: Map<ActivityKey, TxViewlet[]>
export let selected: boolean export let selected: boolean
export let preview: boolean = false export let preview: boolean = false

View File

@ -125,11 +125,18 @@
} }
} }
let viewlets: Map<ActivityKey, TxViewlet> let viewlets: Map<ActivityKey, TxViewlet[]>
const descriptors = createQuery() const descriptors = createQuery()
descriptors.query(activity.class.TxViewlet, {}, (result) => { descriptors.query(activity.class.TxViewlet, {}, (result) => {
viewlets = new Map(result.map((r) => [activityKey(r.objectClass, r.txClass), r])) viewlets = new Map()
for (const res of result) {
const key = activityKey(res.objectClass, res.txClass)
const arr = viewlets.get(key) ?? []
arr.push(res)
viewlets.set(key, arr)
}
viewlets = viewlets
}) })
let selected = 0 let selected = 0

View File

@ -30,7 +30,7 @@
export let value: PersonAccount export let value: PersonAccount
export let items: DocUpdates[] export let items: DocUpdates[]
export let viewlets: Map<ActivityKey, TxViewlet> export let viewlets: Map<ActivityKey, TxViewlet[]>
export let selected: boolean export let selected: boolean
$: firstItem = items[0] $: firstItem = items[0]

View File

@ -35,7 +35,7 @@
export let tx: TxCUD<Doc> export let tx: TxCUD<Doc>
export let objectId: Ref<Doc> export let objectId: Ref<Doc>
export let viewlets: Map<ActivityKey, TxViewlet> export let viewlets: Map<ActivityKey, TxViewlet[]>
const client = getClient() const client = getClient()
let ptx: DisplayTx | undefined let ptx: DisplayTx | undefined

View File

@ -27,7 +27,7 @@
import request from '../plugin' import request from '../plugin'
export let tx: Tx export let tx: Tx
const viewlets: Map<ActivityKey, TxViewlet> = new Map<ActivityKey, TxViewlet>() const viewlets: Map<ActivityKey, TxViewlet[]> = new Map<ActivityKey, TxViewlet[]>()
const client = getClient() const client = getClient()
let ptx: DisplayTx | undefined let ptx: DisplayTx | undefined

View File

@ -13,11 +13,11 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import contact, { PersonAccount, formatName } from '@hcengineering/contact' import contact, { PersonAccount } from '@hcengineering/contact'
import { EmployeePresenter, personByIdStore } from '@hcengineering/contact-resources' import { EmployeePresenter, personByIdStore } from '@hcengineering/contact-resources'
import { AccountRole, getCurrentAccount, SortingOrder } from '@hcengineering/core' import { AccountRole, SortingOrder, getCurrentAccount } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation' import { createQuery, getClient } from '@hcengineering/presentation'
import { DropdownIntlItem, DropdownLabelsIntl, Icon, Label, EditBox } from '@hcengineering/ui' import { DropdownIntlItem, DropdownLabelsIntl, EditBox, Icon, Label } from '@hcengineering/ui'
import setting from '../plugin' import setting from '../plugin'
const client = getClient() const client = getClient()
@ -64,13 +64,13 @@
<div class="ac-column max"> <div class="ac-column max">
{#each accounts as account (account._id)} {#each accounts as account (account._id)}
{@const employee = $personByIdStore.get(account.person)} {@const employee = $personByIdStore.get(account.person)}
{#if account.name.includes(search)} {#if employee?.name?.includes(search)}
<div class="flex-row-center p-2"> <div class="flex-row-center p-2">
<div class="p-1 min-w-80"> <div class="p-1 min-w-80">
{#if employee} {#if employee}
<EmployeePresenter value={employee} disabled={false} /> <EmployeePresenter value={employee} disabled={false} />
{:else} {:else}
{formatName(account.name)} {account.email}
{/if} {/if}
</div> </div>
<DropdownLabelsIntl <DropdownLabelsIntl

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
--> -->
<script lang="ts"> <script lang="ts">
import contact, { Employee, PersonAccount, getFirstName, getLastName } from '@hcengineering/contact' import contact, { Employee, PersonAccount, combineName, getFirstName, getLastName } from '@hcengineering/contact'
import { ChannelsEditor, EditableAvatar, employeeByIdStore } from '@hcengineering/contact-resources' import { ChannelsEditor, EditableAvatar, employeeByIdStore } from '@hcengineering/contact-resources'
import { Ref, getCurrentAccount } from '@hcengineering/core' import { Ref, getCurrentAccount } from '@hcengineering/core'
import login from '@hcengineering/login' import login from '@hcengineering/login'
@ -30,7 +30,6 @@
const employee = account !== undefined ? $employeeByIdStore.get(account.person as Ref<Employee>) : undefined const employee = account !== undefined ? $employeeByIdStore.get(account.person as Ref<Employee>) : undefined
let firstName = employee ? getFirstName(employee.name) : '' let firstName = employee ? getFirstName(employee.name) : ''
let lastName = employee ? getLastName(employee.name) : '' let lastName = employee ? getLastName(employee.name) : ''
let displayName = employee?.displayName ?? ''
onDestroy( onDestroy(
employeeByIdStore.subscribe((p) => { employeeByIdStore.subscribe((p) => {
@ -38,7 +37,6 @@
if (emp) { if (emp) {
firstName = getFirstName(emp.name) firstName = getFirstName(emp.name)
lastName = getLastName(emp.name) lastName = getLastName(emp.name)
displayName = emp?.displayName ?? ''
} }
}) })
) )
@ -74,10 +72,10 @@
) )
} }
function changeDisplayName () { async function nameChange () {
if (employee) { if (employee) {
client.update(employee, { await client.update(employee, {
displayName: displayName.trim() === '' ? null : displayName name: combineName(firstName, lastName)
}) })
} }
} }
@ -110,27 +108,14 @@
kind={'large-style'} kind={'large-style'}
autoFocus autoFocus
focusIndex={1} focusIndex={1}
on:change={async () => { on:change={nameChange}
const changeName = await getResource(login.function.ChangeName)
changeName(firstName, lastName)
}}
/> />
<EditBox <EditBox
placeholder={contact.string.PersonLastNamePlaceholder} placeholder={contact.string.PersonLastNamePlaceholder}
bind:value={lastName} bind:value={lastName}
kind={'large-style'} kind={'large-style'}
focusIndex={2} focusIndex={2}
on:change={async () => { on:change={nameChange}
const changeName = await getResource(login.function.ChangeName)
changeName(firstName, lastName)
}}
/>
<EditBox
placeholder={contact.string.DisplayName}
bind:value={displayName}
kind={'large-style'}
focusIndex={2}
on:change={changeDisplayName}
/> />
<div class="location"> <div class="location">
<AttributeEditor <AttributeEditor

View File

@ -184,7 +184,9 @@
{/if} {/if}
<div class="ml-2 flex-col"> <div class="ml-2 flex-col">
{#if account} {#if account}
<div class="overflow-label fs-bold caption-color">{formatName(account.name)}</div> <div class="overflow-label fs-bold caption-color">
{employee !== undefined ? formatName(employee.name) : ''}
</div>
<div class="overflow-label text-sm content-dark-color">{account.email}</div> <div class="overflow-label text-sm content-dark-color">{account.email}</div>
{/if} {/if}
</div> </div>

View File

@ -253,7 +253,9 @@ async function getEmailNotification (
attachedTo: { $in: Array.from(contacts) } attachedTo: { $in: Array.from(contacts) }
}) })
const senderName = formatName(sender.name) const senderPerson = (await control.findAll(contact.class.Person, { _id: sender.person }))[0]
const senderName = senderPerson !== undefined ? formatName(senderPerson.name) : ''
const content = await getContent(doc, senderName, type, control, '') const content = await getContent(doc, senderName, type, control, '')
if (content === undefined) return [] if (content === undefined) return []

View File

@ -221,8 +221,12 @@ async function createEmailNotificationTxes (
const receiver = (await control.modelDb.findAll(contact.class.PersonAccount, { _id: receiverId }))[0] const receiver = (await control.modelDb.findAll(contact.class.PersonAccount, { _id: receiverId }))[0]
if (receiver === undefined) return if (receiver === undefined) return
let senderName = ''
const senderName = sender !== undefined ? formatName(sender.name) : '' if (sender !== undefined) {
const senderPerson = (await control.modelDb.findAll(contact.class.Person, { _id: sender.person }))[0]
senderName = senderPerson !== undefined ? formatName(senderPerson.name) : ''
}
const content = await getContent(doc, senderName, type, control, data) const content = await getContent(doc, senderName, type, control, data)

View File

@ -87,7 +87,7 @@ describe('server', () => {
}) })
await methods.assignWorkspace(db, '', { await methods.assignWorkspace(db, '', {
method: 'assignWorkspace', method: 'assignWorkspace',
params: ['andrey', workspace] params: ['andrey', workspace, 'firstName', 'lastName']
}) })
const request: any = { const request: any = {
@ -140,7 +140,7 @@ describe('server', () => {
}) })
await methods.assignWorkspace(db, '', { await methods.assignWorkspace(db, '', {
method: 'assignWorkspace', method: 'assignWorkspace',
params: ['andrey', workspace] params: ['andrey', workspace, 'first', 'last']
}) })
// Check we had one // Check we had one

View File

@ -97,8 +97,6 @@ const getTransactor = (): string => {
export interface Account { export interface Account {
_id: ObjectId _id: ObjectId
email: string email: string
first: string
last: string
hash: Binary hash: Binary
salt: Binary salt: Binary
workspaces: ObjectId[] workspaces: ObjectId[]
@ -349,12 +347,14 @@ export async function join (
productId: string, productId: string,
email: string, email: string,
password: string, password: string,
firstName: string,
lastName: string,
inviteId: ObjectId inviteId: ObjectId
): Promise<WorkspaceLoginInfo> { ): Promise<WorkspaceLoginInfo> {
const invite = await getInvite(db, inviteId) const invite = await getInvite(db, inviteId)
const workspace = await checkInvite(invite, email) const workspace = await checkInvite(invite, email)
console.log(`join attempt:${email}, ${workspace.name}`) console.log(`join attempt:${email}, ${workspace.name}`)
await assignWorkspace(db, productId, email, workspace.name) await assignWorkspace(db, productId, email, workspace.name, firstName, lastName)
const token = (await login(db, productId, email, password)).token const token = (await login(db, productId, email, password)).token
const result = await selectWorkspace(db, productId, token, workspace.name) const result = await selectWorkspace(db, productId, token, workspace.name)
@ -470,8 +470,8 @@ export async function signUpJoin (
console.log(`signup join:${email} ${first} ${last}`) console.log(`signup join:${email} ${first} ${last}`)
const invite = await getInvite(db, inviteId) const invite = await getInvite(db, inviteId)
const workspace = await checkInvite(invite, email) const workspace = await checkInvite(invite, email)
await createAcc(db, productId, email, password, first, last, invite?.emailMask === email) await createAcc(db, productId, email, password, invite?.emailMask === email)
await assignWorkspace(db, productId, email, workspace.name) await assignWorkspace(db, productId, email, workspace.name, first, last)
const token = (await login(db, productId, email, password)).token const token = (await login(db, productId, email, password)).token
const result = await selectWorkspace(db, productId, token, workspace.name) const result = await selectWorkspace(db, productId, token, workspace.name)
@ -487,8 +487,6 @@ export async function createAcc (
productId: string, productId: string,
email: string, email: string,
password: string, password: string,
first: string,
last: string,
confirmed: boolean = false confirmed: boolean = false
): Promise<Account> { ): Promise<Account> {
const salt = randomBytes(32) const salt = randomBytes(32)
@ -508,8 +506,6 @@ export async function createAcc (
email, email,
hash, hash,
salt, salt,
first,
last,
confirmed, confirmed,
workspaces: [] workspaces: []
}) })
@ -527,15 +523,8 @@ export async function createAcc (
/** /**
* @public * @public
*/ */
export async function createAccount ( export async function createAccount (db: Db, productId: string, email: string, password: string): Promise<LoginInfo> {
db: Db, const account = await createAcc(db, productId, email, password, false)
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 = { const result = {
endpoint: getEndpoint(), endpoint: getEndpoint(),
@ -634,7 +623,14 @@ export async function upgradeWorkspace (
*/ */
export const createUserWorkspace = export const createUserWorkspace =
(version: Data<Version>, txes: Tx[], migrationOperation: [string, MigrateOperation][]) => (version: Data<Version>, txes: Tx[], migrationOperation: [string, MigrateOperation][]) =>
async (db: Db, productId: string, token: string, workspace: string): Promise<LoginInfo> => { async (
db: Db,
productId: string,
token: string,
workspace: string,
firstName: string,
lastName: string
): Promise<LoginInfo> => {
if (!/^[0-9a-z][0-9a-z-]{2,62}[0-9a-z]$/.test(workspace)) { 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 })) throw new PlatformError(new Status(Severity.ERROR, platform.status.InvalidId, { id: workspace }))
} }
@ -682,7 +678,7 @@ export const createUserWorkspace =
// Update last workspace time. // Update last workspace time.
await db.collection(ACCOUNT_COLLECTION).updateOne({ _id: info._id }, { $set: { lastWorkspace: Date.now() } }) await db.collection(ACCOUNT_COLLECTION).updateOne({ _id: info._id }, { $set: { lastWorkspace: Date.now() } })
await assignWorkspace(db, productId, email, workspace) await assignWorkspace(db, productId, email, workspace, firstName, lastName)
await setRole(email, workspace, productId, AccountRole.Owner) await setRole(email, workspace, productId, AccountRole.Owner)
const result = { const result = {
endpoint: getEndpoint(), endpoint: getEndpoint(),
@ -791,7 +787,14 @@ export async function setRole (email: string, workspace: string, productId: stri
/** /**
* @public * @public
*/ */
export async function assignWorkspace (db: Db, productId: string, email: string, workspace: string): Promise<void> { export async function assignWorkspace (
db: Db,
productId: string,
email: string,
workspace: string,
firstName: string,
lastName: string
): Promise<void> {
const initWS = getMetadata(toolPlugin.metadata.InitWorkspace) const initWS = getMetadata(toolPlugin.metadata.InitWorkspace)
if (initWS !== undefined && initWS === workspace) { if (initWS !== undefined && initWS === workspace) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {})) throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
@ -799,7 +802,7 @@ export async function assignWorkspace (db: Db, productId: string, email: string,
const { workspaceId, accountId } = await getWorkspaceAndAccount(db, productId, email, workspace) const { workspaceId, accountId } = await getWorkspaceAndAccount(db, productId, email, workspace)
const account = await db.collection<Account>(ACCOUNT_COLLECTION).findOne({ _id: accountId }) const account = await db.collection<Account>(ACCOUNT_COLLECTION).findOne({ _id: accountId })
if (account !== null) await createPersonAccount(account, productId, workspace) if (account !== null) await createPersonAccount(account, productId, workspace, firstName, lastName)
// Add account into workspace. // Add account into workspace.
await db.collection(WORKSPACE_COLLECTION).updateOne({ _id: workspaceId }, { $addToSet: { accounts: accountId } }) await db.collection(WORKSPACE_COLLECTION).updateOne({ _id: workspaceId }, { $addToSet: { accounts: accountId } })
@ -833,12 +836,18 @@ async function createEmployee (ops: TxOperations, name: string, email: string):
return id return id
} }
async function createPersonAccount (account: Account, productId: string, workspace: string): Promise<void> { async function createPersonAccount (
account: Account,
productId: string,
workspace: string,
firstName: string,
lastName: string
): Promise<void> {
const connection = await connect(getTransactor(), getWorkspaceId(workspace, productId)) const connection = await connect(getTransactor(), getWorkspaceId(workspace, productId))
try { try {
const ops = new TxOperations(connection, core.account.System) const ops = new TxOperations(connection, core.account.System)
const name = combineName(account.first, account.last) const name = combineName(firstName, lastName)
// Check if EmployeeAccoun is not exists // Check if EmployeeAccoun is not exists
const existingAccount = await ops.findOne(contact.class.PersonAccount, { email: account.email }) const existingAccount = await ops.findOne(contact.class.PersonAccount, { email: account.email })
if (existingAccount === undefined) { if (existingAccount === undefined) {
@ -847,7 +856,6 @@ async function createPersonAccount (account: Account, productId: string, workspa
await ops.createDoc(contact.class.PersonAccount, core.space.Model, { await ops.createDoc(contact.class.PersonAccount, core.space.Model, {
email: account.email, email: account.email,
person: employee, person: employee,
name,
role: 0 role: 0
}) })
} else { } else {
@ -975,57 +983,6 @@ export async function restorePassword (db: Db, productId: string, token: string,
return await login(db, productId, email, password) return await login(db, productId, email, password)
} }
/**
* @public
*/
export async function changeName (db: Db, productId: string, token: string, first: string, last: string): Promise<void> {
const { email } = decodeToken(token)
const account = await getAccount(db, email)
if (account === null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, { account: email }))
}
await db.collection<Account>(ACCOUNT_COLLECTION).updateOne({ _id: account._id }, { $set: { first, last } })
account.first = first
account.last = last
const workspaces = await db
.collection<Workspace>(WORKSPACE_COLLECTION)
.find(withProductId(productId, { _id: { $in: account.workspaces } }))
.toArray()
const promises: Promise<void>[] = []
for (const ws of workspaces) {
promises.push(updatePersonAccount(account, ws.workspace, ws.productId))
}
await Promise.all(promises)
}
async function updatePersonAccount (account: Account, workspace: string, productId: string): Promise<void> {
const connection = await connect(getTransactor(), getWorkspaceId(workspace, productId), account.email)
try {
const ops = new TxOperations(connection, core.account.System)
const name = combineName(account.first, account.last)
const employeeAccount = await ops.findOne(contact.class.PersonAccount, { email: account.email })
if (employeeAccount === undefined) return
await ops.update(employeeAccount, {
name
})
const employee = await ops.findOne(contact.mixin.Employee, { _id: employeeAccount.person as Ref<Employee> })
if (employee === undefined) return
await ops.update(employee, {
name
})
} finally {
await connection.close()
}
}
/** /**
* @public * @public
*/ */
@ -1246,7 +1203,6 @@ export function getMethods (
removeWorkspace: wrap(removeWorkspace), removeWorkspace: wrap(removeWorkspace),
leaveWorkspace: wrap(leaveWorkspace), leaveWorkspace: wrap(leaveWorkspace),
listWorkspaces: wrap(listWorkspaces), listWorkspaces: wrap(listWorkspaces),
changeName: wrap(changeName),
changePassword: wrap(changePassword), changePassword: wrap(changePassword),
requestPassword: wrap(requestPassword), requestPassword: wrap(requestPassword),
restorePassword: wrap(restorePassword), restorePassword: wrap(restorePassword),

View File

@ -42,7 +42,6 @@ export async function getUser (storage: ServerStorage, ctx: SessionContext): Pro
role: AccountRole.Owner, role: AccountRole.Owner,
email: systemAccountEmail, email: systemAccountEmail,
space: core.space.Model, space: core.space.Model,
name: core.string.System,
modifiedBy: core.account.System, modifiedBy: core.account.System,
modifiedOn: 0 modifiedOn: 0
} }

View File

@ -199,8 +199,8 @@ export function genMinModel (): TxCUD<Doc>[] {
const u1 = 'User1' as Ref<Account> const u1 = 'User1' as Ref<Account>
const u2 = 'User2' as Ref<Account> const u2 = 'User2' as Ref<Account>
txes.push( txes.push(
createDoc(core.class.Account, { email: 'user1@site.com', name: '1', role: 0 }, u1), createDoc(core.class.Account, { email: 'user1@site.com', role: 0 }, u1),
createDoc(core.class.Account, { email: 'user2@site.com', name: '2', role: 0 }, u2), createDoc(core.class.Account, { email: 'user2@site.com', role: 0 }, u2),
createDoc(core.class.Space, { createDoc(core.class.Space, {
name: 'Sp1', name: 'Sp1',
description: '', description: '',

View File

@ -174,8 +174,8 @@ export function genMinModel (): TxCUD<Doc>[] {
const u1 = 'User1' as Ref<Account> const u1 = 'User1' as Ref<Account>
const u2 = 'User2' as Ref<Account> const u2 = 'User2' as Ref<Account>
txes.push( txes.push(
createDoc(core.class.Account, { email: 'user1@site.com', name: 'test1', role: 0 }, u1), createDoc(core.class.Account, { email: 'user1@site.com', role: 0 }, u1),
createDoc(core.class.Account, { email: 'user2@site.com', name: 'test2', role: 0 }, u2), createDoc(core.class.Account, { email: 'user2@site.com', role: 0 }, u2),
createDoc(core.class.Space, { createDoc(core.class.Space, {
name: 'Sp1', name: 'Sp1',
description: '', description: '',

View File

@ -10,7 +10,7 @@ export SERVER_SECRET=secret
# Create workspace record in accounts # Create workspace record in accounts
node ../dev/tool/bundle.js create-workspace sanity-ws -o SanityTest node ../dev/tool/bundle.js create-workspace sanity-ws -o SanityTest
# Create user record in accounts # Create user record in accounts
node ../dev/tool/bundle.js create-account user1 -f John -l Appleseed -p 1234 node ../dev/tool/bundle.js create-account user1 -p 1234
node ../dev/tool/bundle.js confirm-email user1 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 node ../dev/tool/bundle.js upgrade-workspace sanity-ws
# Re-assign user to workspace. # Re-assign user to workspace.
node ../dev/tool/bundle.js assign-workspace user1 sanity-ws node ../dev/tool/bundle.js assign-workspace user1 sanity-ws -f John -l Appleseed
node ../dev/tool/bundle.js configure sanity-ws --enable=* node ../dev/tool/bundle.js configure sanity-ws --enable=*
node ../dev/tool/bundle.js configure sanity-ws --list node ../dev/tool/bundle.js configure sanity-ws --list

View File

@ -9,7 +9,7 @@ docker-compose -p sanity up -d --force-recreate --renew-anon-volumes
# Create workspace record in accounts # Create workspace record in accounts
./tool.sh create-workspace sanity-ws -o SanityTest ./tool.sh create-workspace sanity-ws -o SanityTest
# Create user record in accounts # Create user record in accounts
./tool.sh create-account user1 -f John -l Appleseed -p 1234 ./tool.sh create-account user1 -p 1234
# Make user the workspace maintainer # Make user the workspace maintainer
./tool.sh set-user-role user1 sanity-ws 1 ./tool.sh set-user-role user1 sanity-ws 1
./tool.sh confirm-email user1 ./tool.sh confirm-email user1

View File

@ -13,7 +13,7 @@ node ../dev/tool/bundle.js backup-restore ./sanity-ws sanity-ws
node ../dev/tool/bundle.js upgrade-workspace sanity-ws node ../dev/tool/bundle.js upgrade-workspace sanity-ws
# Re-assign user to workspace. # Re-assign user to workspace.
node ../dev/tool/bundle.js assign-workspace user1 sanity-ws node ../dev/tool/bundle.js assign-workspace user1 sanity-ws -f John -l Appleseed
node ../dev/tool/bundle.js configure sanity-ws --enable=* node ../dev/tool/bundle.js configure sanity-ws --enable=*
node ../dev/tool/bundle.js configure sanity-ws --list node ../dev/tool/bundle.js configure sanity-ws --list

View File

@ -6,7 +6,7 @@
./tool.sh upgrade-workspace sanity-ws ./tool.sh upgrade-workspace sanity-ws
# Re-assign user to workspace. # Re-assign user to workspace.
./tool.sh assign-workspace user1 sanity-ws ./tool.sh assign-workspace user1 sanity-ws -f John -l Appleseed
./tool.sh configure sanity-ws --enable=* ./tool.sh configure sanity-ws --enable=*
./tool.sh configure sanity-ws --list ./tool.sh configure sanity-ws --list