hazo_auth 3.0.3 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -0
- package/SETUP_CHECKLIST.md +369 -0
- package/dist/app/api/hazo_auth/library_photo/[category]/[filename]/route.d.ts +2 -2
- package/dist/app/api/hazo_auth/library_photo/[category]/[filename]/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/library_photo/[category]/[filename]/route.js +1 -1
- package/dist/app/api/hazo_auth/profile_picture/[filename]/route.d.ts +2 -2
- package/dist/app/api/hazo_auth/profile_picture/[filename]/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/profile_picture/[filename]/route.js +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_library_tab.d.ts.map +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +2 -2
- package/dist/components/layouts/rbac_test/index.d.ts +15 -0
- package/dist/components/layouts/rbac_test/index.d.ts.map +1 -0
- package/dist/components/layouts/rbac_test/index.js +378 -0
- package/dist/components/layouts/shared/components/password_field.js +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
- package/dist/components/layouts/shared/components/two_column_auth_layout.js +1 -1
- package/dist/components/layouts/user_management/components/roles_matrix.d.ts +2 -3
- package/dist/components/layouts/user_management/components/roles_matrix.d.ts.map +1 -1
- package/dist/components/layouts/user_management/components/roles_matrix.js +133 -8
- package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts +12 -0
- package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/scope_hierarchy_tab.js +291 -0
- package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts +13 -0
- package/dist/components/layouts/user_management/components/scope_labels_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/scope_labels_tab.js +158 -0
- package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts +11 -0
- package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/user_scopes_tab.js +267 -0
- package/dist/components/layouts/user_management/index.d.ts +9 -2
- package/dist/components/layouts/user_management/index.d.ts.map +1 -1
- package/dist/components/layouts/user_management/index.js +22 -6
- package/dist/components/ui/select.d.ts +14 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +59 -0
- package/dist/components/ui/tree-view.d.ts +108 -0
- package/dist/components/ui/tree-view.d.ts.map +1 -0
- package/dist/components/ui/tree-view.js +194 -0
- package/dist/lib/auth/auth_types.d.ts +45 -0
- package/dist/lib/auth/auth_types.d.ts.map +1 -1
- package/dist/lib/auth/auth_types.js +13 -0
- package/dist/lib/auth/hazo_get_auth.server.d.ts +4 -2
- package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.js +107 -3
- package/dist/lib/auth/scope_cache.d.ts +92 -0
- package/dist/lib/auth/scope_cache.d.ts.map +1 -0
- package/dist/lib/auth/scope_cache.js +171 -0
- package/dist/lib/scope_hierarchy_config.server.d.ts +39 -0
- package/dist/lib/scope_hierarchy_config.server.d.ts.map +1 -0
- package/dist/lib/scope_hierarchy_config.server.js +96 -0
- package/dist/lib/services/email_service.d.ts.map +1 -1
- package/dist/lib/services/email_service.js +7 -2
- package/dist/lib/services/profile_picture_service.d.ts +1 -7
- package/dist/lib/services/profile_picture_service.d.ts.map +1 -1
- package/dist/lib/services/profile_picture_service.js +77 -32
- package/dist/lib/services/registration_service.js +1 -1
- package/dist/lib/services/scope_labels_service.d.ts +48 -0
- package/dist/lib/services/scope_labels_service.d.ts.map +1 -0
- package/dist/lib/services/scope_labels_service.js +277 -0
- package/dist/lib/services/scope_service.d.ts +114 -0
- package/dist/lib/services/scope_service.d.ts.map +1 -0
- package/dist/lib/services/scope_service.js +582 -0
- package/dist/lib/services/user_scope_service.d.ts +74 -0
- package/dist/lib/services/user_scope_service.d.ts.map +1 -0
- package/dist/lib/services/user_scope_service.js +415 -0
- package/hazo_auth_config.example.ini +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ScopeLevel } from "../services/scope_service";
|
|
2
|
+
/**
|
|
3
|
+
* User scope assignment record
|
|
4
|
+
*/
|
|
5
|
+
export type UserScopeEntry = {
|
|
6
|
+
scope_type: ScopeLevel;
|
|
7
|
+
scope_id: string;
|
|
8
|
+
scope_seq: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Cache entry structure for user scopes
|
|
12
|
+
*/
|
|
13
|
+
type ScopeCacheEntry = {
|
|
14
|
+
user_id: string;
|
|
15
|
+
scopes: UserScopeEntry[];
|
|
16
|
+
timestamp: number;
|
|
17
|
+
cache_version: number;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* LRU cache implementation for user scope lookups
|
|
21
|
+
* Uses Map to maintain insertion order for LRU eviction
|
|
22
|
+
*/
|
|
23
|
+
declare class ScopeCache {
|
|
24
|
+
private cache;
|
|
25
|
+
private max_size;
|
|
26
|
+
private ttl_ms;
|
|
27
|
+
private scope_version_map;
|
|
28
|
+
constructor(max_size: number, ttl_minutes: number);
|
|
29
|
+
/**
|
|
30
|
+
* Gets a cache entry for a user's scopes
|
|
31
|
+
* Returns undefined if not found or expired
|
|
32
|
+
* @param user_id - User ID to look up
|
|
33
|
+
* @returns Cache entry or undefined
|
|
34
|
+
*/
|
|
35
|
+
get(user_id: string): ScopeCacheEntry | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Sets a cache entry for a user's scopes
|
|
38
|
+
* Evicts least recently used entries if cache is full
|
|
39
|
+
* @param user_id - User ID
|
|
40
|
+
* @param scopes - User's scope assignments
|
|
41
|
+
*/
|
|
42
|
+
set(user_id: string, scopes: UserScopeEntry[]): void;
|
|
43
|
+
/**
|
|
44
|
+
* Invalidates cache for a specific user
|
|
45
|
+
* @param user_id - User ID to invalidate
|
|
46
|
+
*/
|
|
47
|
+
invalidate_user(user_id: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Invalidates cache for all users with a specific scope
|
|
50
|
+
* Uses cache version to determine if invalidation is needed
|
|
51
|
+
* @param scope_type - Scope level
|
|
52
|
+
* @param scope_id - Scope ID to invalidate
|
|
53
|
+
*/
|
|
54
|
+
invalidate_by_scope(scope_type: ScopeLevel, scope_id: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* Invalidates cache for all users with any scope of a specific level
|
|
57
|
+
* @param scope_type - Scope level to invalidate
|
|
58
|
+
*/
|
|
59
|
+
invalidate_by_scope_level(scope_type: ScopeLevel): void;
|
|
60
|
+
/**
|
|
61
|
+
* Invalidates all cache entries
|
|
62
|
+
*/
|
|
63
|
+
invalidate_all(): void;
|
|
64
|
+
/**
|
|
65
|
+
* Gets the maximum cache version for a set of scopes
|
|
66
|
+
* Used to determine if cache entry is stale
|
|
67
|
+
* @param scopes - Array of scope entries
|
|
68
|
+
* @returns Maximum version number
|
|
69
|
+
*/
|
|
70
|
+
private get_max_scope_version;
|
|
71
|
+
/**
|
|
72
|
+
* Gets cache statistics
|
|
73
|
+
* @returns Object with cache size and max size
|
|
74
|
+
*/
|
|
75
|
+
get_stats(): {
|
|
76
|
+
size: number;
|
|
77
|
+
max_size: number;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Gets or creates the global scope cache instance
|
|
82
|
+
* @param max_size - Maximum cache size (default: 5000)
|
|
83
|
+
* @param ttl_minutes - TTL in minutes (default: 15)
|
|
84
|
+
* @returns Scope cache instance
|
|
85
|
+
*/
|
|
86
|
+
export declare function get_scope_cache(max_size?: number, ttl_minutes?: number): ScopeCache;
|
|
87
|
+
/**
|
|
88
|
+
* Resets the global scope cache instance (useful for testing)
|
|
89
|
+
*/
|
|
90
|
+
export declare function reset_scope_cache(): void;
|
|
91
|
+
export {};
|
|
92
|
+
//# sourceMappingURL=scope_cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope_cache.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/scope_cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAI5D;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,cAAM,UAAU;IACd,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,iBAAiB,CAAsB;gBAEnC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAOjD;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IA8BjD;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI;IAwBpD;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAItC;;;;;OAKG;IACH,mBAAmB,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAsBnE;;;OAGG;IACH,yBAAyB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAevD;;OAEG;IACH,cAAc,IAAI,IAAI;IAKtB;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAe7B;;;OAGG;IACH,SAAS,IAAI;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;KAClB;CAMF;AAMD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,GAAE,MAAa,EACvB,WAAW,GAAE,MAAW,GACvB,UAAU,CAKZ;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LRU cache implementation for user scope lookups
|
|
3
|
+
* Uses Map to maintain insertion order for LRU eviction
|
|
4
|
+
*/
|
|
5
|
+
class ScopeCache {
|
|
6
|
+
constructor(max_size, ttl_minutes) {
|
|
7
|
+
this.cache = new Map();
|
|
8
|
+
this.max_size = max_size;
|
|
9
|
+
this.ttl_ms = ttl_minutes * 60 * 1000;
|
|
10
|
+
this.scope_version_map = new Map();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Gets a cache entry for a user's scopes
|
|
14
|
+
* Returns undefined if not found or expired
|
|
15
|
+
* @param user_id - User ID to look up
|
|
16
|
+
* @returns Cache entry or undefined
|
|
17
|
+
*/
|
|
18
|
+
get(user_id) {
|
|
19
|
+
const entry = this.cache.get(user_id);
|
|
20
|
+
if (!entry) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const now = Date.now();
|
|
24
|
+
const age = now - entry.timestamp;
|
|
25
|
+
// Check if entry is expired (TTL)
|
|
26
|
+
if (age > this.ttl_ms) {
|
|
27
|
+
this.cache.delete(user_id);
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
// Check if any of user's scopes have been invalidated
|
|
31
|
+
const max_scope_version = this.get_max_scope_version(entry.scopes);
|
|
32
|
+
if (max_scope_version > entry.cache_version) {
|
|
33
|
+
this.cache.delete(user_id);
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
// Move to end (most recently used)
|
|
37
|
+
this.cache.delete(user_id);
|
|
38
|
+
this.cache.set(user_id, entry);
|
|
39
|
+
return entry;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Sets a cache entry for a user's scopes
|
|
43
|
+
* Evicts least recently used entries if cache is full
|
|
44
|
+
* @param user_id - User ID
|
|
45
|
+
* @param scopes - User's scope assignments
|
|
46
|
+
*/
|
|
47
|
+
set(user_id, scopes) {
|
|
48
|
+
// Evict LRU entries if cache is full
|
|
49
|
+
while (this.cache.size >= this.max_size) {
|
|
50
|
+
const first_key = this.cache.keys().next().value;
|
|
51
|
+
if (first_key) {
|
|
52
|
+
this.cache.delete(first_key);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Get current cache version for user's scopes
|
|
59
|
+
const cache_version = this.get_max_scope_version(scopes);
|
|
60
|
+
const entry = {
|
|
61
|
+
user_id,
|
|
62
|
+
scopes,
|
|
63
|
+
timestamp: Date.now(),
|
|
64
|
+
cache_version,
|
|
65
|
+
};
|
|
66
|
+
this.cache.set(user_id, entry);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Invalidates cache for a specific user
|
|
70
|
+
* @param user_id - User ID to invalidate
|
|
71
|
+
*/
|
|
72
|
+
invalidate_user(user_id) {
|
|
73
|
+
this.cache.delete(user_id);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Invalidates cache for all users with a specific scope
|
|
77
|
+
* Uses cache version to determine if invalidation is needed
|
|
78
|
+
* @param scope_type - Scope level
|
|
79
|
+
* @param scope_id - Scope ID to invalidate
|
|
80
|
+
*/
|
|
81
|
+
invalidate_by_scope(scope_type, scope_id) {
|
|
82
|
+
const scope_key = `${scope_type}:${scope_id}`;
|
|
83
|
+
const current_version = this.scope_version_map.get(scope_key) || 0;
|
|
84
|
+
this.scope_version_map.set(scope_key, current_version + 1);
|
|
85
|
+
// Remove entries where cache version is older than scope version
|
|
86
|
+
const entries_to_remove = [];
|
|
87
|
+
for (const [user_id, entry] of this.cache.entries()) {
|
|
88
|
+
// Check if user has this scope
|
|
89
|
+
const has_scope = entry.scopes.some((s) => s.scope_type === scope_type && s.scope_id === scope_id);
|
|
90
|
+
if (has_scope) {
|
|
91
|
+
entries_to_remove.push(user_id);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const user_id of entries_to_remove) {
|
|
95
|
+
this.cache.delete(user_id);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Invalidates cache for all users with any scope of a specific level
|
|
100
|
+
* @param scope_type - Scope level to invalidate
|
|
101
|
+
*/
|
|
102
|
+
invalidate_by_scope_level(scope_type) {
|
|
103
|
+
const entries_to_remove = [];
|
|
104
|
+
for (const [user_id, entry] of this.cache.entries()) {
|
|
105
|
+
// Check if user has any scope of this level
|
|
106
|
+
const has_level = entry.scopes.some((s) => s.scope_type === scope_type);
|
|
107
|
+
if (has_level) {
|
|
108
|
+
entries_to_remove.push(user_id);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const user_id of entries_to_remove) {
|
|
112
|
+
this.cache.delete(user_id);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Invalidates all cache entries
|
|
117
|
+
*/
|
|
118
|
+
invalidate_all() {
|
|
119
|
+
this.cache.clear();
|
|
120
|
+
this.scope_version_map.clear();
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Gets the maximum cache version for a set of scopes
|
|
124
|
+
* Used to determine if cache entry is stale
|
|
125
|
+
* @param scopes - Array of scope entries
|
|
126
|
+
* @returns Maximum version number
|
|
127
|
+
*/
|
|
128
|
+
get_max_scope_version(scopes) {
|
|
129
|
+
if (scopes.length === 0) {
|
|
130
|
+
return 0;
|
|
131
|
+
}
|
|
132
|
+
let max_version = 0;
|
|
133
|
+
for (const scope of scopes) {
|
|
134
|
+
const scope_key = `${scope.scope_type}:${scope.scope_id}`;
|
|
135
|
+
const version = this.scope_version_map.get(scope_key) || 0;
|
|
136
|
+
max_version = Math.max(max_version, version);
|
|
137
|
+
}
|
|
138
|
+
return max_version;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Gets cache statistics
|
|
142
|
+
* @returns Object with cache size and max size
|
|
143
|
+
*/
|
|
144
|
+
get_stats() {
|
|
145
|
+
return {
|
|
146
|
+
size: this.cache.size,
|
|
147
|
+
max_size: this.max_size,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// section: singleton
|
|
152
|
+
// Global scope cache instance (initialized with defaults, will be configured on first use)
|
|
153
|
+
let scope_cache_instance = null;
|
|
154
|
+
/**
|
|
155
|
+
* Gets or creates the global scope cache instance
|
|
156
|
+
* @param max_size - Maximum cache size (default: 5000)
|
|
157
|
+
* @param ttl_minutes - TTL in minutes (default: 15)
|
|
158
|
+
* @returns Scope cache instance
|
|
159
|
+
*/
|
|
160
|
+
export function get_scope_cache(max_size = 5000, ttl_minutes = 15) {
|
|
161
|
+
if (!scope_cache_instance) {
|
|
162
|
+
scope_cache_instance = new ScopeCache(max_size, ttl_minutes);
|
|
163
|
+
}
|
|
164
|
+
return scope_cache_instance;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Resets the global scope cache instance (useful for testing)
|
|
168
|
+
*/
|
|
169
|
+
export function reset_scope_cache() {
|
|
170
|
+
scope_cache_instance = null;
|
|
171
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ScopeLevel } from "./services/scope_service";
|
|
2
|
+
/**
|
|
3
|
+
* Scope hierarchy configuration options for HRBAC
|
|
4
|
+
*/
|
|
5
|
+
export type ScopeHierarchyConfig = {
|
|
6
|
+
/** Whether HRBAC is enabled (default: false) */
|
|
7
|
+
enable_hrbac: boolean;
|
|
8
|
+
/** Default organization for single-tenant apps (optional) */
|
|
9
|
+
default_org: string;
|
|
10
|
+
/** Cache TTL in minutes for scope lookups (default: 15) */
|
|
11
|
+
scope_cache_ttl_minutes: number;
|
|
12
|
+
/** Maximum entries in scope cache (default: 5000) */
|
|
13
|
+
scope_cache_max_entries: number;
|
|
14
|
+
/** Which scope levels are active/enabled */
|
|
15
|
+
active_levels: ScopeLevel[];
|
|
16
|
+
/** Default labels for each scope level */
|
|
17
|
+
default_labels: Record<ScopeLevel, string>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Reads HRBAC scope hierarchy configuration from hazo_auth_config.ini file
|
|
21
|
+
* Falls back to defaults if config file is not found or section is missing
|
|
22
|
+
* @returns Scope hierarchy configuration options
|
|
23
|
+
*/
|
|
24
|
+
export declare function get_scope_hierarchy_config(): ScopeHierarchyConfig;
|
|
25
|
+
/**
|
|
26
|
+
* Checks if HRBAC is enabled in the configuration
|
|
27
|
+
* Convenience function for quick checks
|
|
28
|
+
*/
|
|
29
|
+
export declare function is_hrbac_enabled(): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Gets the default organization from config
|
|
32
|
+
* Returns empty string if not configured (multi-tenant mode)
|
|
33
|
+
*/
|
|
34
|
+
export declare function get_default_org(): string;
|
|
35
|
+
/**
|
|
36
|
+
* Gets the default label for a scope level
|
|
37
|
+
*/
|
|
38
|
+
export declare function get_default_label(level: ScopeLevel): string;
|
|
39
|
+
//# sourceMappingURL=scope_hierarchy_config.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope_hierarchy_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/scope_hierarchy_config.server.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAK3D;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,gDAAgD;IAChD,YAAY,EAAE,OAAO,CAAC;IACtB,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,uBAAuB,EAAE,MAAM,CAAC;IAChC,qDAAqD;IACrD,uBAAuB,EAAE,MAAM,CAAC;IAChC,4CAA4C;IAC5C,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5B,0CAA0C;IAC1C,cAAc,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;CAC5C,CAAC;AA0DF;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,oBAAoB,CAkCjE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAG3D"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// file_description: server-only helper to read HRBAC scope hierarchy configuration from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_config_value, get_config_number, get_config_boolean, } from "./config/config_loader.server";
|
|
4
|
+
import { SCOPE_LEVELS } from "./services/scope_service";
|
|
5
|
+
// section: constants
|
|
6
|
+
const SECTION_NAME = "hazo_auth__scope_hierarchy";
|
|
7
|
+
const DEFAULT_LABELS = {
|
|
8
|
+
hazo_scopes_l1: "Level 1",
|
|
9
|
+
hazo_scopes_l2: "Level 2",
|
|
10
|
+
hazo_scopes_l3: "Level 3",
|
|
11
|
+
hazo_scopes_l4: "Level 4",
|
|
12
|
+
hazo_scopes_l5: "Level 5",
|
|
13
|
+
hazo_scopes_l6: "Level 6",
|
|
14
|
+
hazo_scopes_l7: "Level 7",
|
|
15
|
+
};
|
|
16
|
+
// section: helpers
|
|
17
|
+
/**
|
|
18
|
+
* Parses the active_levels config value into an array of ScopeLevel
|
|
19
|
+
* If not configured, returns all levels
|
|
20
|
+
*/
|
|
21
|
+
function parse_active_levels(config_value) {
|
|
22
|
+
if (!config_value || config_value.trim().length === 0) {
|
|
23
|
+
return [...SCOPE_LEVELS]; // All levels active by default
|
|
24
|
+
}
|
|
25
|
+
const levels = config_value.split(",").map((s) => s.trim());
|
|
26
|
+
const valid_levels = [];
|
|
27
|
+
for (const level of levels) {
|
|
28
|
+
if (SCOPE_LEVELS.includes(level)) {
|
|
29
|
+
valid_levels.push(level);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return valid_levels.length > 0 ? valid_levels : [...SCOPE_LEVELS];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Reads default labels from config, falling back to defaults
|
|
36
|
+
*/
|
|
37
|
+
function get_default_labels() {
|
|
38
|
+
const labels = Object.assign({}, DEFAULT_LABELS);
|
|
39
|
+
for (let i = 1; i <= 7; i++) {
|
|
40
|
+
const level = `hazo_scopes_l${i}`;
|
|
41
|
+
const config_key = `default_label_l${i}`;
|
|
42
|
+
const config_value = get_config_value(SECTION_NAME, config_key, "");
|
|
43
|
+
if (config_value && config_value.trim().length > 0) {
|
|
44
|
+
labels[level] = config_value.trim();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return labels;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Reads HRBAC scope hierarchy configuration from hazo_auth_config.ini file
|
|
51
|
+
* Falls back to defaults if config file is not found or section is missing
|
|
52
|
+
* @returns Scope hierarchy configuration options
|
|
53
|
+
*/
|
|
54
|
+
export function get_scope_hierarchy_config() {
|
|
55
|
+
// Core HRBAC enablement
|
|
56
|
+
const enable_hrbac = get_config_boolean(SECTION_NAME, "enable_hrbac", false);
|
|
57
|
+
// Default organization for single-tenant apps
|
|
58
|
+
const default_org = get_config_value(SECTION_NAME, "default_org", "");
|
|
59
|
+
// Cache settings
|
|
60
|
+
const scope_cache_ttl_minutes = get_config_number(SECTION_NAME, "scope_cache_ttl_minutes", 15);
|
|
61
|
+
const scope_cache_max_entries = get_config_number(SECTION_NAME, "scope_cache_max_entries", 5000);
|
|
62
|
+
// Active levels
|
|
63
|
+
const active_levels_str = get_config_value(SECTION_NAME, "active_levels", "");
|
|
64
|
+
const active_levels = parse_active_levels(active_levels_str);
|
|
65
|
+
// Default labels
|
|
66
|
+
const default_labels = get_default_labels();
|
|
67
|
+
return {
|
|
68
|
+
enable_hrbac,
|
|
69
|
+
default_org,
|
|
70
|
+
scope_cache_ttl_minutes,
|
|
71
|
+
scope_cache_max_entries,
|
|
72
|
+
active_levels,
|
|
73
|
+
default_labels,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Checks if HRBAC is enabled in the configuration
|
|
78
|
+
* Convenience function for quick checks
|
|
79
|
+
*/
|
|
80
|
+
export function is_hrbac_enabled() {
|
|
81
|
+
return get_config_boolean(SECTION_NAME, "enable_hrbac", false);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Gets the default organization from config
|
|
85
|
+
* Returns empty string if not configured (multi-tenant mode)
|
|
86
|
+
*/
|
|
87
|
+
export function get_default_org() {
|
|
88
|
+
return get_config_value(SECTION_NAME, "default_org", "");
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Gets the default label for a scope level
|
|
92
|
+
*/
|
|
93
|
+
export function get_default_label(level) {
|
|
94
|
+
const config_key = `default_label_l${level.charAt(level.length - 1)}`;
|
|
95
|
+
return get_config_value(SECTION_NAME, config_key, DEFAULT_LABELS[level]);
|
|
96
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/email_service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAoB,MAAM,aAAa,CAAC;AAGnE,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AAE9F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;
|
|
1
|
+
{"version":3,"file":"email_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/email_service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAoB,MAAM,aAAa,CAAC;AAGnE,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AAE9F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAmBF;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAEpE;AA0YD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAwErG;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,iBAAiB,EAChC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiD/C"}
|
|
@@ -6,7 +6,12 @@ import { create_app_logger } from "../app_logger";
|
|
|
6
6
|
import { read_config_section } from "../config/config_loader.server";
|
|
7
7
|
// section: constants
|
|
8
8
|
const DEFAULT_EMAIL_FROM = "noreply@hazo_auth.local";
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Gets the default email template directory (lazy-evaluated to avoid Edge Runtime issues)
|
|
11
|
+
*/
|
|
12
|
+
function get_default_email_template_dir() {
|
|
13
|
+
return path.resolve(process.cwd(), "email_templates");
|
|
14
|
+
}
|
|
10
15
|
// section: singleton
|
|
11
16
|
/**
|
|
12
17
|
* Singleton instance for hazo_notify emailer configuration
|
|
@@ -66,7 +71,7 @@ function get_email_template_directory() {
|
|
|
66
71
|
? template_dir
|
|
67
72
|
: path.resolve(process.cwd(), template_dir);
|
|
68
73
|
}
|
|
69
|
-
return
|
|
74
|
+
return get_default_email_template_dir();
|
|
70
75
|
}
|
|
71
76
|
/**
|
|
72
77
|
* Gets email from address from config
|
|
@@ -55,13 +55,7 @@ export declare function get_library_source(): "project" | "node_modules" | null;
|
|
|
55
55
|
* Clears the library path cache (useful for testing or after copying files)
|
|
56
56
|
*/
|
|
57
57
|
export declare function clear_library_cache(): void;
|
|
58
|
-
|
|
59
|
-
* Gets default profile picture based on configuration priority
|
|
60
|
-
* @param user_email - User's email address
|
|
61
|
-
* @param user_name - User's name (optional)
|
|
62
|
-
* @returns Default profile picture URL and source, or null if no default available
|
|
63
|
-
*/
|
|
64
|
-
export declare function get_default_profile_picture(user_email: string, user_name?: string): DefaultProfilePictureResult | null;
|
|
58
|
+
export declare function get_default_profile_picture(user_email: string, user_name?: string): Promise<DefaultProfilePictureResult | null>;
|
|
65
59
|
/**
|
|
66
60
|
* Updates user profile picture in database
|
|
67
61
|
* @param adapter - The hazo_connect adapter instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile_picture_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/profile_picture_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASvD,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAGnG,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAE1D,MAAM,MAAM,2BAA2B,GAAG;IACxC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,oBAAoB,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,cAAc,CAAC;CACpC,CAAC;AA2DF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAOrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAyBjD;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAU,EAChB,SAAS,GAAE,MAAW,GACrB,mBAAmB,CA6FrB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAI7D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAcxF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,SAAS,GAAG,cAAc,GAAG,IAAI,CAGtE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;
|
|
1
|
+
{"version":3,"file":"profile_picture_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/profile_picture_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASvD,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAGnG,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAE1D,MAAM,MAAM,2BAA2B,GAAG;IACxC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,oBAAoB,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,cAAc,CAAC;CACpC,CAAC;AA2DF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAOrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAyBjD;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAU,EAChB,SAAS,GAAE,MAAW,GACrB,mBAAmB,CA6FrB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAI7D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAcxF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,SAAS,GAAG,cAAc,GAAG,IAAI,CAGtE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AA4DD,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CA+D7C;AAED;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,EACf,mBAAmB,EAAE,MAAM,EAC3B,cAAc,EAAE,oBAAoB,GACnC,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsB/C"}
|
|
@@ -238,7 +238,50 @@ export function clear_library_cache() {
|
|
|
238
238
|
* @param user_name - User's name (optional)
|
|
239
239
|
* @returns Default profile picture URL and source, or null if no default available
|
|
240
240
|
*/
|
|
241
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Checks if a Gravatar exists for the given email by making a HEAD request
|
|
243
|
+
* @param email - User email address
|
|
244
|
+
* @returns Promise<boolean> - true if Gravatar exists (status 200), false otherwise (404 or error)
|
|
245
|
+
*/
|
|
246
|
+
async function check_gravatar_exists(email) {
|
|
247
|
+
try {
|
|
248
|
+
const uiSizes = get_ui_sizes_config();
|
|
249
|
+
const gravatar_url = get_gravatar_url(email, uiSizes.gravatar_size);
|
|
250
|
+
// Make HEAD request to check if image exists without downloading it
|
|
251
|
+
const response = await fetch(gravatar_url, {
|
|
252
|
+
method: 'HEAD',
|
|
253
|
+
// Add timeout to prevent hanging
|
|
254
|
+
signal: AbortSignal.timeout(5000) // 5 second timeout
|
|
255
|
+
});
|
|
256
|
+
// Gravatar returns 200 if user has an image, 404 if using default/mystery-person
|
|
257
|
+
return response.ok;
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
// If fetch fails (network error, timeout, etc.), assume no Gravatar
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Gets a random image from a random category in the library
|
|
266
|
+
* @returns string | null - Random library photo URL or null if no photos available
|
|
267
|
+
*/
|
|
268
|
+
function get_random_library_photo() {
|
|
269
|
+
const categories = get_library_categories();
|
|
270
|
+
if (categories.length === 0) {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
// Pick a random category
|
|
274
|
+
const random_category = categories[Math.floor(Math.random() * categories.length)];
|
|
275
|
+
// Get photos from that category
|
|
276
|
+
const photos = get_library_photos(random_category);
|
|
277
|
+
if (photos.length === 0) {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
// Pick a random photo from that category
|
|
281
|
+
const random_photo = photos[Math.floor(Math.random() * photos.length)];
|
|
282
|
+
return random_photo;
|
|
283
|
+
}
|
|
284
|
+
export async function get_default_profile_picture(user_email, user_name) {
|
|
242
285
|
const config = get_profile_picture_config();
|
|
243
286
|
if (!config.user_photo_default) {
|
|
244
287
|
return null;
|
|
@@ -246,25 +289,25 @@ export function get_default_profile_picture(user_email, user_name) {
|
|
|
246
289
|
const uiSizes = get_ui_sizes_config();
|
|
247
290
|
// Try priority 1
|
|
248
291
|
if (config.user_photo_default_priority1 === "gravatar") {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
292
|
+
// Check if Gravatar actually exists for this email
|
|
293
|
+
const gravatar_exists = await check_gravatar_exists(user_email);
|
|
294
|
+
if (gravatar_exists) {
|
|
295
|
+
const gravatar_url = get_gravatar_url(user_email, uiSizes.gravatar_size);
|
|
296
|
+
return {
|
|
297
|
+
profile_picture_url: gravatar_url,
|
|
298
|
+
profile_source: "gravatar",
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
// If Gravatar doesn't exist, fall through to priority 2
|
|
256
302
|
}
|
|
257
303
|
else if (config.user_photo_default_priority1 === "library") {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
profile_source: "library",
|
|
266
|
-
};
|
|
267
|
-
}
|
|
304
|
+
// Use random library photo instead of first photo
|
|
305
|
+
const random_photo = get_random_library_photo();
|
|
306
|
+
if (random_photo) {
|
|
307
|
+
return {
|
|
308
|
+
profile_picture_url: random_photo,
|
|
309
|
+
profile_source: "library",
|
|
310
|
+
};
|
|
268
311
|
}
|
|
269
312
|
}
|
|
270
313
|
// Try priority 2 if priority 1 didn't work (only if priority2 is different from priority1)
|
|
@@ -272,22 +315,24 @@ export function get_default_profile_picture(user_email, user_name) {
|
|
|
272
315
|
const priority2 = config.user_photo_default_priority2;
|
|
273
316
|
if (priority2 && priority2 !== priority1) {
|
|
274
317
|
if (priority2 === "gravatar") {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
318
|
+
// Check if Gravatar actually exists for this email
|
|
319
|
+
const gravatar_exists = await check_gravatar_exists(user_email);
|
|
320
|
+
if (gravatar_exists) {
|
|
321
|
+
const gravatar_url = get_gravatar_url(user_email, uiSizes.gravatar_size);
|
|
322
|
+
return {
|
|
323
|
+
profile_picture_url: gravatar_url,
|
|
324
|
+
profile_source: "gravatar",
|
|
325
|
+
};
|
|
326
|
+
}
|
|
280
327
|
}
|
|
281
328
|
else if (priority2 === "library") {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
};
|
|
290
|
-
}
|
|
329
|
+
// Use random library photo instead of first photo
|
|
330
|
+
const random_photo = get_random_library_photo();
|
|
331
|
+
if (random_photo) {
|
|
332
|
+
return {
|
|
333
|
+
profile_picture_url: random_photo,
|
|
334
|
+
profile_source: "library",
|
|
335
|
+
};
|
|
291
336
|
}
|
|
292
337
|
}
|
|
293
338
|
}
|
|
@@ -61,7 +61,7 @@ export async function register_user(adapter, data) {
|
|
|
61
61
|
// Set default profile picture if enabled
|
|
62
62
|
const profile_picture_config = get_profile_picture_config();
|
|
63
63
|
if (profile_picture_config.user_photo_default) {
|
|
64
|
-
const default_photo = get_default_profile_picture(email, name);
|
|
64
|
+
const default_photo = await get_default_profile_picture(email, name);
|
|
65
65
|
if (default_photo) {
|
|
66
66
|
insert_data.profile_picture_url = default_photo.profile_picture_url;
|
|
67
67
|
// Map UI source value to database enum value
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { HazoConnectAdapter } from "hazo_connect";
|
|
2
|
+
import type { ScopeLevel } from "./scope_service";
|
|
3
|
+
export type ScopeLabel = {
|
|
4
|
+
id: string;
|
|
5
|
+
org: string;
|
|
6
|
+
scope_type: ScopeLevel;
|
|
7
|
+
label: string;
|
|
8
|
+
created_at: string;
|
|
9
|
+
changed_at: string;
|
|
10
|
+
};
|
|
11
|
+
export type ScopeLabelResult = {
|
|
12
|
+
success: boolean;
|
|
13
|
+
label?: ScopeLabel;
|
|
14
|
+
labels?: ScopeLabel[];
|
|
15
|
+
error?: string;
|
|
16
|
+
};
|
|
17
|
+
export declare const DEFAULT_SCOPE_LABELS: Record<ScopeLevel, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Gets all scope labels for an organization
|
|
20
|
+
*/
|
|
21
|
+
export declare function get_scope_labels(adapter: HazoConnectAdapter, org: string): Promise<ScopeLabelResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Gets all scope labels for an organization, with defaults filled in for missing levels
|
|
24
|
+
*/
|
|
25
|
+
export declare function get_scope_labels_with_defaults(adapter: HazoConnectAdapter, org: string, custom_defaults?: Record<ScopeLevel, string>): Promise<ScopeLabelResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Gets the label for a specific scope level
|
|
28
|
+
* Returns the custom label if set, otherwise returns the default
|
|
29
|
+
*/
|
|
30
|
+
export declare function get_label_for_level(adapter: HazoConnectAdapter, org: string, scope_type: ScopeLevel, custom_default?: string): Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Creates or updates a scope label for an organization
|
|
33
|
+
* Uses upsert pattern - creates if not exists, updates if exists
|
|
34
|
+
*/
|
|
35
|
+
export declare function upsert_scope_label(adapter: HazoConnectAdapter, org: string, scope_type: ScopeLevel, label: string): Promise<ScopeLabelResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Batch upsert scope labels for an organization
|
|
38
|
+
* Useful for saving all labels at once from the UI
|
|
39
|
+
*/
|
|
40
|
+
export declare function batch_upsert_scope_labels(adapter: HazoConnectAdapter, org: string, labels: Array<{
|
|
41
|
+
scope_type: ScopeLevel;
|
|
42
|
+
label: string;
|
|
43
|
+
}>): Promise<ScopeLabelResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Deletes a scope label, reverting to default
|
|
46
|
+
*/
|
|
47
|
+
export declare function delete_scope_label(adapter: HazoConnectAdapter, org: string, scope_type: ScopeLevel): Promise<ScopeLabelResult>;
|
|
48
|
+
//# sourceMappingURL=scope_labels_service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope_labels_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/scope_labels_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAKvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAIlD,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAQ3D,CAAC;AAIF;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,gBAAgB,CAAC,CA4B3B;AAED;;GAEG;AACH,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,MAAM,EACX,eAAe,CAAC,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,gBAAgB,CAAC,CA0D3B;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,UAAU,EACtB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,gBAAgB,CAAC,CAuE3B;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,KAAK,CAAC;IAAE,UAAU,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GACvD,OAAO,CAAC,gBAAgB,CAAC,CAwC3B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,gBAAgB,CAAC,CAwC3B"}
|