mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-26 04:23:58 +03:00
Use Gravatar if it is really defined (#2359)
Signed-off-by: Denis Bunakalya <denis.bunakalya@xored.com>
This commit is contained in:
parent
508ecc6a44
commit
23641ac365
@ -243,6 +243,7 @@ specifiers:
|
||||
cors: ^2.8.5
|
||||
cropperjs: ~1.5.12
|
||||
cross-env: ~7.0.3
|
||||
cross-fetch: ^3.1.5
|
||||
crypto-js: ^4.1.1
|
||||
css-loader: ^5.2.1
|
||||
csv-parse: ~5.1.0
|
||||
@ -560,6 +561,7 @@ dependencies:
|
||||
cors: 2.8.5
|
||||
cropperjs: 1.5.12
|
||||
cross-env: 7.0.3
|
||||
cross-fetch: 3.1.5
|
||||
crypto-js: 4.1.1
|
||||
css-loader: 5.2.7_webpack@5.73.0
|
||||
csv-parse: 5.1.0
|
||||
@ -3782,6 +3784,14 @@ packages:
|
||||
cross-spawn: 7.0.3
|
||||
dev: false
|
||||
|
||||
/cross-fetch/3.1.5:
|
||||
resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==}
|
||||
dependencies:
|
||||
node-fetch: 2.6.7
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
dev: false
|
||||
|
||||
/cross-spawn/7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -3889,6 +3899,11 @@ packages:
|
||||
resolution: {integrity: sha512-JL+Q6YEikT2uoe57InjFFa6VejhSv0tDwOxeQ1bVQKeUC/NCnLAAZ8n3PzowPQQLuZ37fysDYZipB2UJkH9C6A==}
|
||||
dev: false
|
||||
|
||||
/data-uri-to-buffer/4.0.0:
|
||||
resolution: {integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==}
|
||||
engines: {node: '>= 12'}
|
||||
dev: false
|
||||
|
||||
/data-urls/2.0.0:
|
||||
resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -4943,6 +4958,14 @@ packages:
|
||||
bser: 2.1.1
|
||||
dev: false
|
||||
|
||||
/fetch-blob/3.2.0:
|
||||
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
||||
engines: {node: ^12.20 || >= 14.13}
|
||||
dependencies:
|
||||
node-domexception: 1.0.0
|
||||
web-streams-polyfill: 3.2.1
|
||||
dev: false
|
||||
|
||||
/file-entry-cache/6.0.1:
|
||||
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
|
||||
engines: {node: ^10.12.0 || >=12.0.0}
|
||||
@ -5073,6 +5096,13 @@ packages:
|
||||
mime-types: 2.1.35
|
||||
dev: false
|
||||
|
||||
/formdata-polyfill/4.0.10:
|
||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
dev: false
|
||||
|
||||
/forwarded-parse/2.1.2:
|
||||
resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==}
|
||||
dev: false
|
||||
@ -7271,6 +7301,32 @@ packages:
|
||||
resolution: {integrity: sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==}
|
||||
dev: false
|
||||
|
||||
/node-domexception/1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
dev: false
|
||||
|
||||
/node-fetch/2.6.7:
|
||||
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
peerDependencies:
|
||||
encoding: ^0.1.0
|
||||
peerDependenciesMeta:
|
||||
encoding:
|
||||
optional: true
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
dev: false
|
||||
|
||||
/node-fetch/3.2.10:
|
||||
resolution: {integrity: sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
dependencies:
|
||||
data-uri-to-buffer: 4.0.0
|
||||
fetch-blob: 3.2.0
|
||||
formdata-polyfill: 4.0.10
|
||||
dev: false
|
||||
|
||||
/node-forge/1.3.1:
|
||||
resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==}
|
||||
engines: {node: '>= 6.13.0'}
|
||||
@ -9215,6 +9271,10 @@ packages:
|
||||
universalify: 0.1.2
|
||||
dev: false
|
||||
|
||||
/tr46/0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
dev: false
|
||||
|
||||
/tr46/2.1.0:
|
||||
resolution: {integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==}
|
||||
engines: {node: '>=8'}
|
||||
@ -9557,6 +9617,15 @@ packages:
|
||||
'@zxing/text-encoding': 0.9.0
|
||||
dev: false
|
||||
|
||||
/web-streams-polyfill/3.2.1:
|
||||
resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==}
|
||||
engines: {node: '>= 8'}
|
||||
dev: false
|
||||
|
||||
/webidl-conversions/3.0.1:
|
||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
||||
dev: false
|
||||
|
||||
/webidl-conversions/5.0.0:
|
||||
resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==}
|
||||
engines: {node: '>=8'}
|
||||
@ -9777,6 +9846,13 @@ packages:
|
||||
webidl-conversions: 7.0.0
|
||||
dev: false
|
||||
|
||||
/whatwg-url/5.0.0:
|
||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||
dependencies:
|
||||
tr46: 0.0.3
|
||||
webidl-conversions: 3.0.1
|
||||
dev: false
|
||||
|
||||
/whatwg-url/8.7.0:
|
||||
resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==}
|
||||
engines: {node: '>=10'}
|
||||
@ -10633,20 +10709,23 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/contact.tgz:
|
||||
resolution: {integrity: sha512-XEyVNwWUMw6+kqGTrKrdY5qIKl+AXkFTL42bbgC5egcrvSZaMfnKqfq4ZwoWcYUFhLAa8VOJ6BJRZbxW0UfLcA==, tarball: file:projects/contact.tgz}
|
||||
resolution: {integrity: sha512-PZ/ICZGSAaO5SiOpbIAc9mwxHq8UhCtnjEAf59gO6fP1+UNyj+Oy8zdtJ/v0LobOzhYLHUikeezgJdFSIqFirA==, tarball: file:projects/contact.tgz}
|
||||
name: '@rush-temp/contact'
|
||||
version: 0.0.0
|
||||
dependencies:
|
||||
'@rushstack/heft': 0.47.9
|
||||
'@types/crypto-js': 4.1.1
|
||||
'@types/heft-jest': 1.0.3
|
||||
'@typescript-eslint/eslint-plugin': 5.42.0_8b6083565a963e7484743e25607ce89c
|
||||
'@typescript-eslint/parser': 5.42.0_eslint@8.26.0+typescript@4.7.4
|
||||
crypto-js: 4.1.1
|
||||
eslint: 8.26.0
|
||||
eslint-config-standard-with-typescript: 23.0.0_35db0d754f34ccffcc0e5a361183072e
|
||||
eslint-plugin-import: 2.26.0_eslint@8.26.0
|
||||
eslint-plugin-n: 15.4.0_eslint@8.26.0
|
||||
eslint-plugin-node: 11.1.0_eslint@8.26.0
|
||||
eslint-plugin-promise: 6.1.1_eslint@8.26.0
|
||||
node-fetch: 3.2.10
|
||||
prettier: 2.7.1
|
||||
typescript: 4.7.4
|
||||
transitivePeerDependencies:
|
||||
@ -11727,7 +11806,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/model-contact.tgz_typescript@4.7.4:
|
||||
resolution: {integrity: sha512-/KNyMsjF/sEWcLixUTYNy530r/IgRQeikYoX3aDxRyXWlofDTZEGME03o/qqiNSxw34WTzu6mHUE3+6dTUFexg==, tarball: file:projects/model-contact.tgz}
|
||||
resolution: {integrity: sha512-1LXDgoRC+p48CfA8Dhk/JuUttYtwkJXaXADwFcvDJGLmWN062SEHy5mOCB56RcYxbBZvMOuRbKKkdZ7u678jzw==, tarball: file:projects/model-contact.tgz}
|
||||
id: file:projects/model-contact.tgz
|
||||
name: '@rush-temp/model-contact'
|
||||
version: 0.0.0
|
||||
@ -11739,6 +11818,7 @@ packages:
|
||||
'@types/node': 16.11.42
|
||||
'@typescript-eslint/eslint-plugin': 5.42.0_8b6083565a963e7484743e25607ce89c
|
||||
'@typescript-eslint/parser': 5.42.0_eslint@8.26.0+typescript@4.7.4
|
||||
cross-fetch: 3.1.5
|
||||
crypto-js: 4.1.1
|
||||
eslint: 8.26.0
|
||||
eslint-config-standard-with-typescript: 23.0.0_35db0d754f34ccffcc0e5a361183072e
|
||||
@ -11748,8 +11828,10 @@ packages:
|
||||
eslint-plugin-promise: 6.1.1_eslint@8.26.0
|
||||
md5: 2.3.0
|
||||
md5.js: 1.3.5
|
||||
node-fetch: 3.2.10
|
||||
prettier: 2.7.1
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
- typescript
|
||||
dev: false
|
||||
@ -12942,7 +13024,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/presentation.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c:
|
||||
resolution: {integrity: sha512-/eG/9sTCMrZJrJmVa0ePYhfOtw2omr+HgzqeCSmawUzczU8M1zoSHIJxkvhI/Vk4n8p7cTMfI6GFL7MN4sfiqg==, tarball: file:projects/presentation.tgz}
|
||||
resolution: {integrity: sha512-BRrMCOYZQWq7l4bHtorlsbF3Vd1xC3d1+HFwxAapz+2dWVdzTZa9LWbUnxdgOdVKnoPNEBshBb7yweuAz+QYvQ==, tarball: file:projects/presentation.tgz}
|
||||
id: file:projects/presentation.tgz
|
||||
name: '@rush-temp/presentation'
|
||||
version: 0.0.0
|
||||
@ -14632,7 +14714,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
file:projects/ui.tgz_1e3963ebf0ceeb25b2fa6a1cc87e253c:
|
||||
resolution: {integrity: sha512-46COtAECm8v7tfsMRV9ol2UMMwpXYPwvp//qyVSlCIhNrWA7Mk7rBzMKeyDwi28EmjxasIbNhRQScOa5DTccig==, tarball: file:projects/ui.tgz}
|
||||
resolution: {integrity: sha512-tEGe2W6LdHgwewLIjCYDQwX+tSqWYivga5zeLBin75rsNZYJVujyTyDx7opwnVDZvCDmoVYRDCjv08X1XHzNEA==, tarball: file:projects/ui.tgz}
|
||||
id: file:projects/ui.tgz
|
||||
name: '@rush-temp/ui'
|
||||
version: 0.0.0
|
||||
@ -14647,6 +14729,7 @@ packages:
|
||||
eslint-plugin-node: 11.1.0_eslint@8.26.0
|
||||
eslint-plugin-promise: 6.1.1_eslint@8.26.0
|
||||
eslint-plugin-svelte3: 4.0.0_eslint@8.26.0+svelte@3.48.0
|
||||
fast-equals: 2.0.4
|
||||
prettier: 2.7.1
|
||||
prettier-plugin-svelte: 2.8.0_prettier@2.7.1+svelte@3.48.0
|
||||
sass: 1.53.0
|
||||
|
@ -18,7 +18,6 @@
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
"eslint": "^8.26.0",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/heft-jest": "^1.0.3",
|
||||
"@typescript-eslint/parser": "^5.41.0",
|
||||
"eslint-config-standard-with-typescript": "^23.0.0",
|
||||
@ -40,6 +39,6 @@
|
||||
"@hcengineering/contact": "~0.6.5",
|
||||
"@hcengineering/contact-resources": "~0.6.0",
|
||||
"@hcengineering/view": "^0.6.1",
|
||||
"crypto-js": "^4.1.1"
|
||||
"cross-fetch": "^3.1.5"
|
||||
}
|
||||
}
|
||||
|
@ -13,12 +13,20 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Employee, EmployeeAccount, AvatarType } from '@hcengineering/contact'
|
||||
import fetch from 'cross-fetch'
|
||||
|
||||
import {
|
||||
Employee,
|
||||
EmployeeAccount,
|
||||
AvatarType,
|
||||
buildGravatarId,
|
||||
checkHasGravatar,
|
||||
getAvatarColorForId
|
||||
} from '@hcengineering/contact'
|
||||
import { AccountRole, DOMAIN_TX, TxCreateDoc, TxOperations } from '@hcengineering/core'
|
||||
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
|
||||
import core from '@hcengineering/model-core'
|
||||
import contact from './index'
|
||||
import MD5 from 'crypto-js/md5'
|
||||
|
||||
async function createSpace (tx: TxOperations): Promise<void> {
|
||||
const current = await tx.findOne(core.class.Space, {
|
||||
@ -96,9 +104,13 @@ async function updateEmployeeAvatar (tx: TxOperations): Promise<void> {
|
||||
if (employee === undefined) return
|
||||
if (employee.avatar != null && employee.avatar !== undefined) return
|
||||
|
||||
const gravatarId = MD5(account.email.trim().toLowerCase()).toString()
|
||||
const gravatarId = buildGravatarId(account.email)
|
||||
const hasGravatar = await checkHasGravatar(gravatarId, fetch)
|
||||
|
||||
await tx.update(employee, {
|
||||
avatar: `${AvatarType.GRAVATAR}://${gravatarId}`
|
||||
avatar: hasGravatar
|
||||
? `${AvatarType.GRAVATAR}://${gravatarId}`
|
||||
: `${AvatarType.COLOR}://${getAvatarColorForId(employee._id)}`
|
||||
})
|
||||
})
|
||||
await Promise.all(promises)
|
||||
|
@ -19,7 +19,6 @@
|
||||
"@hcengineering/platform-rig": "~0.6.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
||||
"@typescript-eslint/parser": "^5.41.0",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"eslint-config-standard-with-typescript": "^23.0.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-n": "^15.4.0",
|
||||
@ -44,7 +43,6 @@
|
||||
"@hcengineering/image-cropper": "~0.6.0",
|
||||
"@hcengineering/client": "^0.6.3",
|
||||
"@hcengineering/setting": "~0.6.1",
|
||||
"fast-equals": "^2.0.3",
|
||||
"crypto-js": "^4.1.1"
|
||||
"fast-equals": "^2.0.3"
|
||||
}
|
||||
}
|
||||
|
@ -16,12 +16,11 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import { DropdownLabelsIntl, AnySvelteComponent, showPopup, Label } from '@hcengineering/ui'
|
||||
import { AvatarType } from '@hcengineering/contact'
|
||||
import { AvatarType, buildGravatarId, checkHasGravatar, getAvatarColorForId } from '@hcengineering/contact'
|
||||
import { Asset } from '@hcengineering/platform'
|
||||
|
||||
import presentation from '..'
|
||||
import { getAvatarTypeDropdownItems, getFileUrl, getAvatarColorForId } from '../utils'
|
||||
import { buildGravatarId } from '../gravatar'
|
||||
import { getAvatarTypeDropdownItems, getFileUrl } from '../utils'
|
||||
import Card from './Card.svelte'
|
||||
import AvatarComponent from './Avatar.svelte'
|
||||
import EditAvatarPopup from './EditAvatarPopup.svelte'
|
||||
@ -55,6 +54,12 @@
|
||||
let selectedAvatar: string = initialSelectedAvatar
|
||||
let selectedFile: Blob | undefined = file
|
||||
|
||||
let hasGravatar = false
|
||||
async function updateHasGravatar (email?: string) {
|
||||
hasGravatar = !!email && (await checkHasGravatar(buildGravatarId(email)))
|
||||
}
|
||||
$: updateHasGravatar(email)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function submit () {
|
||||
@ -152,7 +157,7 @@
|
||||
}}
|
||||
>
|
||||
<DropdownLabelsIntl
|
||||
items={getAvatarTypeDropdownItems(!!email)}
|
||||
items={getAvatarTypeDropdownItems(hasGravatar)}
|
||||
label={presentation.string.SelectAvatar}
|
||||
bind:selected={selectedAvatarType}
|
||||
on:selected={handleDropdownSelection}
|
||||
|
@ -1,64 +0,0 @@
|
||||
//
|
||||
// Copyright © 2022 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.
|
||||
//
|
||||
|
||||
import { IconSize } from '@hcengineering/ui'
|
||||
import MD5 from 'crypto-js/md5'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type GravatarPlaceholderType =
|
||||
| '404'
|
||||
| 'mp'
|
||||
| 'identicon'
|
||||
| 'monsterid'
|
||||
| 'wavatar'
|
||||
| 'retro'
|
||||
| 'robohash'
|
||||
| 'blank'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function buildGravatarId (email: string): string {
|
||||
return MD5(email.trim().toLowerCase()).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getGravatarUrl (
|
||||
gravatarId: string,
|
||||
size: IconSize = 'full',
|
||||
placeholder: GravatarPlaceholderType = 'identicon'
|
||||
): string {
|
||||
let width = 64
|
||||
switch (size) {
|
||||
case 'inline':
|
||||
case 'tiny':
|
||||
case 'x-small':
|
||||
case 'small':
|
||||
case 'medium':
|
||||
width = 64
|
||||
break
|
||||
case 'large':
|
||||
width = 256
|
||||
break
|
||||
case 'x-large':
|
||||
width = 512
|
||||
break
|
||||
}
|
||||
return `https://gravatar.com/avatar/${gravatarId}?s=${width}&d=${placeholder}`
|
||||
}
|
@ -47,7 +47,6 @@ export { connect, versionError } from './connect'
|
||||
export { default } from './plugin'
|
||||
export * from './types'
|
||||
export * from './utils'
|
||||
export * from './gravatar'
|
||||
export { presentationId }
|
||||
|
||||
addStringsLoader(presentationId, async (lang: string) => {
|
||||
|
@ -235,7 +235,7 @@ export function getAttributePresenterClass (
|
||||
return { attrClass, category }
|
||||
}
|
||||
|
||||
export function getAvatarTypeDropdownItems (hasEmail: boolean): DropdownIntlItem[] {
|
||||
export function getAvatarTypeDropdownItems (hasGravatar: boolean): DropdownIntlItem[] {
|
||||
return [
|
||||
{
|
||||
id: AvatarType.COLOR,
|
||||
@ -245,7 +245,7 @@ export function getAvatarTypeDropdownItems (hasEmail: boolean): DropdownIntlItem
|
||||
id: AvatarType.IMAGE,
|
||||
label: contact.string.UseImage
|
||||
},
|
||||
...(hasEmail
|
||||
...(hasGravatar
|
||||
? [
|
||||
{
|
||||
id: AvatarType.GRAVATAR,
|
||||
@ -256,31 +256,6 @@ export function getAvatarTypeDropdownItems (hasEmail: boolean): DropdownIntlItem
|
||||
]
|
||||
}
|
||||
|
||||
const AVATAR_COLORS = [
|
||||
'#4674ca', // blue
|
||||
'#315cac', // blue_dark
|
||||
'#57be8c', // green
|
||||
'#3fa372', // green_dark
|
||||
'#f9a66d', // yellow_orange
|
||||
'#ec5e44', // red
|
||||
'#e63717', // red_dark
|
||||
'#f868bc', // pink
|
||||
'#6c5fc7', // purple
|
||||
'#4e3fb4', // purple_dark
|
||||
'#57b1be', // teal
|
||||
'#847a8c' // gray
|
||||
]
|
||||
|
||||
export function getAvatarColorForId (id: string): string {
|
||||
let hash = 0
|
||||
|
||||
for (let i = 0; i < id.length; i++) {
|
||||
hash += id.charCodeAt(i)
|
||||
}
|
||||
|
||||
return AVATAR_COLORS[hash % AVATAR_COLORS.length]
|
||||
}
|
||||
|
||||
export function getAvatarProviderId (avatar?: string | null): Ref<AvatarProvider> | undefined {
|
||||
if (avatar === null || avatar === undefined || avatar === '') {
|
||||
return
|
||||
|
@ -36,7 +36,8 @@
|
||||
"@hcengineering/platform": "^0.6.7",
|
||||
"@hcengineering/theme": "^0.6.1",
|
||||
"@hcengineering/core": "^0.6.17",
|
||||
"svelte": "^3.47"
|
||||
"svelte": "^3.47",
|
||||
"fast-equals": "^2.0.3"
|
||||
},
|
||||
"repository": "https://github.com/hcenginneing/anticrm",
|
||||
"publishConfig": {
|
||||
|
@ -15,8 +15,10 @@
|
||||
<script lang="ts">
|
||||
import { IntlString, Asset } from '@hcengineering/platform'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
|
||||
import type { AnySvelteComponent, TooltipAlignment, ButtonKind, ButtonSize, DropdownIntlItem } from '../types'
|
||||
import { showPopup } from '../popups'
|
||||
import { showPopup, closePopup } from '../popups'
|
||||
import Button from './Button.svelte'
|
||||
import DropdownLabelsPopupIntl from './DropdownLabelsPopupIntl.svelte'
|
||||
import Label from './Label.svelte'
|
||||
@ -42,6 +44,30 @@
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function openPopup () {
|
||||
if (!opened) {
|
||||
opened = true
|
||||
showPopup(DropdownLabelsPopupIntl, { items, selected }, container, (result) => {
|
||||
if (result) {
|
||||
selected = result
|
||||
dispatch('selected', result)
|
||||
}
|
||||
opened = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let prevItems: DropdownIntlItem[]
|
||||
$: if (!deepEqual(items, prevItems)) {
|
||||
prevItems = items
|
||||
|
||||
if (opened) {
|
||||
closePopup()
|
||||
opened = false
|
||||
openPopup()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={container} class="min-w-0">
|
||||
@ -53,18 +79,7 @@
|
||||
{disabled}
|
||||
{justify}
|
||||
showTooltip={{ label, direction: labelDirection }}
|
||||
on:click={() => {
|
||||
if (!opened) {
|
||||
opened = true
|
||||
showPopup(DropdownLabelsPopupIntl, { items, selected }, container, (result) => {
|
||||
if (result) {
|
||||
selected = result
|
||||
dispatch('selected', result)
|
||||
}
|
||||
opened = false
|
||||
})
|
||||
}
|
||||
}}
|
||||
on:click={openPopup}
|
||||
>
|
||||
<span slot="content" class="overflow-label disabled">
|
||||
<Label label={selectedItem ? selectedItem.label : label} />
|
||||
|
@ -14,19 +14,11 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Channel, Contact, Employee, formatName } from '@hcengineering/contact'
|
||||
import { Channel, Contact, Employee, formatName, getGravatarUrl } from '@hcengineering/contact'
|
||||
import { Class, Client, DocumentQuery, Ref, RelatedDocument, WithLookup } from '@hcengineering/core'
|
||||
import { leaveWorkspace } from '@hcengineering/login-resources'
|
||||
import { Resources } from '@hcengineering/platform'
|
||||
import {
|
||||
Avatar,
|
||||
getClient,
|
||||
MessageBox,
|
||||
ObjectSearchResult,
|
||||
UserInfo,
|
||||
getFileUrl,
|
||||
getGravatarUrl
|
||||
} from '@hcengineering/presentation'
|
||||
import { Avatar, getClient, MessageBox, ObjectSearchResult, UserInfo, getFileUrl } from '@hcengineering/presentation'
|
||||
import { showPopup } from '@hcengineering/ui'
|
||||
import Channels from './components/Channels.svelte'
|
||||
import ChannelsDropdown from './components/ChannelsDropdown.svelte'
|
||||
|
@ -13,6 +13,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hcengineering/platform-rig": "~0.6.0",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/heft-jest": "^1.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.41.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
@ -29,7 +30,8 @@
|
||||
"@hcengineering/platform": "^0.6.7",
|
||||
"@hcengineering/ui": "^0.6.2",
|
||||
"@hcengineering/core": "^0.6.17",
|
||||
"@hcengineering/view": "^0.6.1"
|
||||
"@hcengineering/view": "^0.6.1",
|
||||
"crypto-js": "^4.1.1"
|
||||
},
|
||||
"repository": "https://github.com/hcengineering/anticrm",
|
||||
"publishConfig": {
|
||||
|
@ -13,6 +13,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import MD5 from 'crypto-js/md5'
|
||||
|
||||
import {
|
||||
Account,
|
||||
AttachedData,
|
||||
@ -353,7 +355,6 @@ export async function findContacts (
|
||||
|
||||
/**
|
||||
* @public
|
||||
|
||||
*/
|
||||
export async function findPerson (
|
||||
client: Client,
|
||||
@ -363,3 +364,89 @@ export async function findPerson (
|
||||
const result = await findContacts(client, contactPlugin.class.Person, person, channels)
|
||||
return result.contacts as Person[]
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type GravatarPlaceholderType =
|
||||
| '404'
|
||||
| 'mp'
|
||||
| 'identicon'
|
||||
| 'monsterid'
|
||||
| 'wavatar'
|
||||
| 'retro'
|
||||
| 'robohash'
|
||||
| 'blank'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function buildGravatarId (email: string): string {
|
||||
return MD5(email.trim().toLowerCase()).toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getGravatarUrl (
|
||||
gravatarId: string,
|
||||
size: IconSize = 'full',
|
||||
placeholder: GravatarPlaceholderType = 'identicon'
|
||||
): string {
|
||||
let width = 64
|
||||
switch (size) {
|
||||
case 'inline':
|
||||
case 'tiny':
|
||||
case 'x-small':
|
||||
case 'small':
|
||||
case 'medium':
|
||||
width = 64
|
||||
break
|
||||
case 'large':
|
||||
width = 256
|
||||
break
|
||||
case 'x-large':
|
||||
width = 512
|
||||
break
|
||||
}
|
||||
return `https://gravatar.com/avatar/${gravatarId}?s=${width}&d=${placeholder}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function checkHasGravatar (gravatarId: string, fetch?: typeof window.fetch): Promise<boolean> {
|
||||
try {
|
||||
return (await (fetch ?? window.fetch)(getGravatarUrl(gravatarId, 'full', '404'))).ok
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const AVATAR_COLORS = [
|
||||
'#4674ca', // blue
|
||||
'#315cac', // blue_dark
|
||||
'#57be8c', // green
|
||||
'#3fa372', // green_dark
|
||||
'#f9a66d', // yellow_orange
|
||||
'#ec5e44', // red
|
||||
'#e63717', // red_dark
|
||||
'#f868bc', // pink
|
||||
'#6c5fc7', // purple
|
||||
'#4e3fb4', // purple_dark
|
||||
'#57b1be', // teal
|
||||
'#847a8c' // gray
|
||||
]
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export function getAvatarColorForId (id: string): string {
|
||||
let hash = 0
|
||||
|
||||
for (let i = 0; i < id.length; i++) {
|
||||
hash += id.charCodeAt(i)
|
||||
}
|
||||
|
||||
return AVATAR_COLORS[hash % AVATAR_COLORS.length]
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"lib": ["esnext", "dom"]
|
||||
"lib": ["esnext", "dom"],
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
@ -13,7 +13,14 @@
|
||||
// limitations under the f.
|
||||
//
|
||||
|
||||
import contact, { AvatarType, combineName, Employee } from '@hcengineering/contact'
|
||||
import contact, {
|
||||
AvatarType,
|
||||
combineName,
|
||||
Employee,
|
||||
buildGravatarId,
|
||||
checkHasGravatar,
|
||||
getAvatarColorForId
|
||||
} from '@hcengineering/contact'
|
||||
import core, { AccountRole, Ref, TxOperations } from '@hcengineering/core'
|
||||
import platform, {
|
||||
getMetadata,
|
||||
@ -28,7 +35,7 @@ import platform, {
|
||||
} from '@hcengineering/platform'
|
||||
import { decodeToken, generateToken } from '@hcengineering/server-token'
|
||||
import toolPlugin, { connect, initModel, upgradeModel, version } from '@hcengineering/server-tool'
|
||||
import { createHash, pbkdf2Sync, randomBytes } from 'crypto'
|
||||
import { pbkdf2Sync, randomBytes } from 'crypto'
|
||||
import { Binary, Db, ObjectId } from 'mongodb'
|
||||
|
||||
const WORKSPACE_COLLECTION = 'workspace'
|
||||
@ -484,13 +491,22 @@ export async function assignWorkspace (db: Db, email: string, workspace: string)
|
||||
}
|
||||
|
||||
async function createEmployee (ops: TxOperations, name: string, email: string): Promise<Ref<Employee>> {
|
||||
const gravatarId = createHash('md5').update(email.trim().toLowerCase()).digest('hex')
|
||||
return await ops.createDoc(contact.class.Employee, contact.space.Employee, {
|
||||
const gravatarId = buildGravatarId(email)
|
||||
const hasGravatar = await checkHasGravatar(gravatarId)
|
||||
|
||||
const id = await ops.createDoc(contact.class.Employee, contact.space.Employee, {
|
||||
name,
|
||||
city: '',
|
||||
avatar: `${AvatarType.GRAVATAR}://${gravatarId}`,
|
||||
...(hasGravatar ? { avatar: `${AvatarType.GRAVATAR}://${gravatarId}` } : {}),
|
||||
active: true
|
||||
})
|
||||
if (!hasGravatar) {
|
||||
await ops.updateDoc(contact.class.Employee, contact.space.Employee, id, {
|
||||
avatar: `${AvatarType.COLOR}://${getAvatarColorForId(id)}`
|
||||
})
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
async function createEmployeeAccount (account: Account, workspace: string): Promise<void> {
|
||||
|
Loading…
Reference in New Issue
Block a user