@kaikybrofc/omnizap-system 2.3.4 → 2.3.5
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 +14 -14
- package/app/modules/stickerModule/stickerCommand.js +1 -6
- package/app/modules/stickerModule/stickerTextCommand.js +1 -6
- package/package.json +1 -1
- package/public/index.html +8 -8
- package/public/js/apps/homeApp.js +22 -18
- package/public/js/apps/loginApp.js +3 -1
- package/public/js/apps/userProfileApp.js +0 -9
- package/public/user/index.html +224 -120
- package/server/controllers/admin/adminBanService.js +138 -0
- package/server/controllers/admin/adminPanelHandlers.js +1965 -0
- package/server/controllers/{systemAdminController.js → admin/systemAdminController.js} +2 -2
- package/server/controllers/{stickerCatalogController.js → sticker/stickerCatalogController.js} +129 -2116
- package/server/controllers/userController.js +1 -1
- package/server/routes/admin/systemAdminRouter.js +1 -1
- package/server/routes/indexRouter.js +3 -3
- package/server/routes/{stickerCatalog → sticker}/stickerApiRouter.js +1 -1
- package/server/routes/{stickerCatalog → sticker}/stickerDataRouter.js +1 -1
- package/server/routes/{stickerCatalog → sticker}/stickerSiteRouter.js +1 -1
- /package/server/controllers/{stickerCatalog → sticker}/nonCatalogHandlers.js +0 -0
- /package/server/routes/{stickerCatalog → sticker}/catalogHandlers/catalogAdminHttp.js +0 -0
- /package/server/routes/{stickerCatalog → sticker}/catalogHandlers/catalogAuthHttp.js +0 -0
- /package/server/routes/{stickerCatalog → sticker}/catalogHandlers/catalogPublicHttp.js +0 -0
- /package/server/routes/{stickerCatalog → sticker}/catalogHandlers/catalogUploadHttp.js +0 -0
- /package/server/routes/{stickerCatalog → sticker}/catalogRouter.js +0 -0
package/public/user/index.html
CHANGED
|
@@ -16,14 +16,21 @@
|
|
|
16
16
|
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Sora:wght@500;600;700&display=swap" rel="stylesheet" />
|
|
17
17
|
<style>
|
|
18
18
|
:root {
|
|
19
|
-
--bg: #
|
|
20
|
-
--bg-2: #
|
|
21
|
-
--
|
|
22
|
-
--
|
|
23
|
-
--
|
|
24
|
-
--
|
|
25
|
-
--
|
|
26
|
-
--
|
|
19
|
+
--bg: #060d1a;
|
|
20
|
+
--bg-2: #0c1a31;
|
|
21
|
+
--bg-3: #102542;
|
|
22
|
+
--surface: #132340d6;
|
|
23
|
+
--surface-2: #152948f0;
|
|
24
|
+
--line: #8ab4ff2b;
|
|
25
|
+
--line-strong: #9fc4ff61;
|
|
26
|
+
--text: #f5f9ff;
|
|
27
|
+
--muted: #9eb2ce;
|
|
28
|
+
--primary: #1fd08b;
|
|
29
|
+
--accent: #5a8fff;
|
|
30
|
+
--danger: #ffb3b3;
|
|
31
|
+
--radius-xl: 26px;
|
|
32
|
+
--radius-lg: 18px;
|
|
33
|
+
--radius-md: 14px;
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
* {
|
|
@@ -40,33 +47,33 @@
|
|
|
40
47
|
body {
|
|
41
48
|
color: var(--text);
|
|
42
49
|
font-family: 'Manrope', system-ui, sans-serif;
|
|
43
|
-
background:
|
|
50
|
+
background:
|
|
51
|
+
radial-gradient(70rem 40rem at -12% -18%, #1d4ed855, transparent 62%),
|
|
52
|
+
radial-gradient(55rem 30rem at 108% -6%, #0ea5e941, transparent 66%),
|
|
53
|
+
linear-gradient(160deg, var(--bg), var(--bg-2) 52%, var(--bg-3));
|
|
44
54
|
min-height: 100vh;
|
|
45
|
-
|
|
46
|
-
align-items: center;
|
|
47
|
-
justify-content: center;
|
|
48
|
-
padding: 24px 14px;
|
|
55
|
+
padding: clamp(12px, 2.2vw, 28px);
|
|
49
56
|
}
|
|
50
57
|
|
|
51
58
|
.page {
|
|
52
|
-
width: min(
|
|
53
|
-
|
|
54
|
-
border
|
|
55
|
-
|
|
59
|
+
width: min(1080px, 100%);
|
|
60
|
+
margin-inline: auto;
|
|
61
|
+
border: 1px solid #8ab4ff1f;
|
|
62
|
+
border-radius: var(--radius-xl);
|
|
63
|
+
background: linear-gradient(145deg, #101d37ef 2%, #0f1b33f3 44%, #13294af2 100%);
|
|
56
64
|
box-shadow:
|
|
57
|
-
0
|
|
58
|
-
inset 0 1px 0 #
|
|
65
|
+
0 25px 70px #01091585,
|
|
66
|
+
inset 0 1px 0 #d3e4ff2e;
|
|
59
67
|
overflow: hidden;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
.head {
|
|
63
|
-
border-bottom: 1px solid
|
|
64
|
-
padding:
|
|
65
|
-
display:
|
|
71
|
+
border-bottom: 1px solid var(--line);
|
|
72
|
+
padding: clamp(16px, 2.1vw, 24px);
|
|
73
|
+
display: grid;
|
|
74
|
+
grid-template-columns: 1fr auto;
|
|
75
|
+
gap: 12px 16px;
|
|
66
76
|
align-items: center;
|
|
67
|
-
justify-content: space-between;
|
|
68
|
-
gap: 14px;
|
|
69
|
-
flex-wrap: wrap;
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
.brand {
|
|
@@ -75,71 +82,93 @@
|
|
|
75
82
|
gap: 10px;
|
|
76
83
|
font-family: 'Sora', sans-serif;
|
|
77
84
|
font-weight: 700;
|
|
78
|
-
letter-spacing: 0.
|
|
85
|
+
letter-spacing: 0.03em;
|
|
79
86
|
text-decoration: none;
|
|
80
87
|
color: var(--text);
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
.brand img {
|
|
84
|
-
width:
|
|
85
|
-
height:
|
|
86
|
-
border-radius:
|
|
87
|
-
border: 1px solid
|
|
91
|
+
width: 34px;
|
|
92
|
+
height: 34px;
|
|
93
|
+
border-radius: 12px;
|
|
94
|
+
border: 1px solid var(--line);
|
|
88
95
|
object-fit: cover;
|
|
96
|
+
box-shadow: 0 10px 22px #0000004b;
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
.head-actions {
|
|
92
|
-
display:
|
|
93
|
-
|
|
100
|
+
display: grid;
|
|
101
|
+
grid-auto-flow: column;
|
|
102
|
+
grid-auto-columns: max-content;
|
|
94
103
|
gap: 8px;
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
.btn {
|
|
98
107
|
border: 1px solid var(--line);
|
|
99
108
|
border-radius: 12px;
|
|
100
|
-
background: #
|
|
109
|
+
background: #0e1b33;
|
|
101
110
|
color: var(--text);
|
|
102
111
|
text-decoration: none;
|
|
103
|
-
padding:
|
|
112
|
+
padding: 10px 14px;
|
|
104
113
|
font-size: 14px;
|
|
105
|
-
font-weight:
|
|
114
|
+
font-weight: 700;
|
|
115
|
+
line-height: 1.2;
|
|
116
|
+
text-align: center;
|
|
117
|
+
display: inline-flex;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
align-items: center;
|
|
106
120
|
transition:
|
|
107
121
|
transform 0.2s ease,
|
|
108
122
|
border-color 0.2s ease,
|
|
109
|
-
box-shadow 0.2s ease
|
|
123
|
+
box-shadow 0.2s ease,
|
|
124
|
+
background-color 0.2s ease;
|
|
110
125
|
cursor: pointer;
|
|
111
126
|
}
|
|
112
127
|
|
|
113
128
|
.btn:hover {
|
|
114
129
|
transform: translateY(-1px);
|
|
115
|
-
border-color:
|
|
116
|
-
box-shadow: 0
|
|
130
|
+
border-color: var(--line-strong);
|
|
131
|
+
box-shadow: 0 12px 24px #01091557;
|
|
117
132
|
}
|
|
118
133
|
|
|
119
134
|
.btn.primary {
|
|
120
135
|
border-color: transparent;
|
|
121
|
-
background: #22c55e;
|
|
122
|
-
color: #
|
|
123
|
-
box-shadow: 0
|
|
136
|
+
background: linear-gradient(120deg, #1fd08b, #22c55e);
|
|
137
|
+
color: #072116;
|
|
138
|
+
box-shadow: 0 12px 24px #22c55e3d;
|
|
124
139
|
}
|
|
125
140
|
|
|
126
141
|
.btn.primary:hover {
|
|
127
|
-
background: #
|
|
142
|
+
background: linear-gradient(120deg, #2be09b, #33d46d);
|
|
128
143
|
}
|
|
129
144
|
|
|
130
145
|
.content {
|
|
131
|
-
padding:
|
|
146
|
+
padding: clamp(18px, 2.6vw, 30px);
|
|
147
|
+
display: grid;
|
|
148
|
+
gap: clamp(14px, 2vw, 22px);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.intro {
|
|
132
152
|
display: grid;
|
|
133
|
-
gap:
|
|
153
|
+
gap: 8px;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.eyebrow {
|
|
157
|
+
margin: 0;
|
|
158
|
+
font-family: 'Sora', sans-serif;
|
|
159
|
+
font-size: 12px;
|
|
160
|
+
letter-spacing: 0.16em;
|
|
161
|
+
text-transform: uppercase;
|
|
162
|
+
color: #95b8ff;
|
|
134
163
|
}
|
|
135
164
|
|
|
136
165
|
h1 {
|
|
137
166
|
margin: 0;
|
|
138
167
|
font-family: 'Sora', sans-serif;
|
|
139
|
-
font-size: clamp(
|
|
140
|
-
line-height: 1.
|
|
141
|
-
letter-spacing: -0.
|
|
142
|
-
background: linear-gradient(
|
|
168
|
+
font-size: clamp(28px, 4vw, 46px);
|
|
169
|
+
line-height: 1.05;
|
|
170
|
+
letter-spacing: -0.03em;
|
|
171
|
+
background: linear-gradient(100deg, #f6fbff 0%, #9bc5ff 52%, #77b4ff 100%);
|
|
143
172
|
-webkit-background-clip: text;
|
|
144
173
|
background-clip: text;
|
|
145
174
|
color: transparent;
|
|
@@ -147,141 +176,205 @@
|
|
|
147
176
|
|
|
148
177
|
.lead {
|
|
149
178
|
margin: 0;
|
|
150
|
-
color: #
|
|
179
|
+
color: #bfd3ef;
|
|
151
180
|
line-height: 1.6;
|
|
152
181
|
font-size: 16px;
|
|
182
|
+
max-width: 68ch;
|
|
153
183
|
}
|
|
154
184
|
|
|
155
185
|
.card {
|
|
156
|
-
border: 1px solid #
|
|
157
|
-
border-radius: var(--radius);
|
|
158
|
-
background: var(--
|
|
159
|
-
padding:
|
|
186
|
+
border: 1px solid #5d8dd23b;
|
|
187
|
+
border-radius: var(--radius-lg);
|
|
188
|
+
background: linear-gradient(150deg, var(--surface) 0%, var(--surface-2) 100%);
|
|
189
|
+
padding: clamp(14px, 2.2vw, 20px);
|
|
160
190
|
display: grid;
|
|
161
191
|
gap: 12px;
|
|
162
|
-
backdrop-filter: blur(
|
|
192
|
+
backdrop-filter: blur(9px);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.dashboard-card {
|
|
196
|
+
position: relative;
|
|
197
|
+
overflow: hidden;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.dashboard-card::before {
|
|
201
|
+
content: '';
|
|
202
|
+
position: absolute;
|
|
203
|
+
inset: 0;
|
|
204
|
+
pointer-events: none;
|
|
205
|
+
background: linear-gradient(160deg, #8fb3ff10 0%, transparent 36%, #1fd08b0f 100%);
|
|
163
206
|
}
|
|
164
207
|
|
|
165
208
|
.status {
|
|
209
|
+
position: relative;
|
|
166
210
|
margin: 0;
|
|
167
|
-
color: #
|
|
211
|
+
color: #e7f0ff;
|
|
168
212
|
font-size: 15px;
|
|
213
|
+
font-weight: 600;
|
|
169
214
|
line-height: 1.5;
|
|
215
|
+
padding: 12px 14px;
|
|
216
|
+
border: 1px solid #6d9de440;
|
|
217
|
+
border-radius: var(--radius-md);
|
|
218
|
+
background: #112647d1;
|
|
170
219
|
}
|
|
171
220
|
|
|
172
221
|
.error {
|
|
222
|
+
position: relative;
|
|
173
223
|
margin: 0;
|
|
174
|
-
border: 1px solid #
|
|
175
|
-
border-radius:
|
|
176
|
-
background: #
|
|
177
|
-
color:
|
|
178
|
-
padding:
|
|
224
|
+
border: 1px solid #ff8f8f87;
|
|
225
|
+
border-radius: var(--radius-md);
|
|
226
|
+
background: #3d1e2fb0;
|
|
227
|
+
color: var(--danger);
|
|
228
|
+
padding: 10px 12px;
|
|
179
229
|
font-size: 14px;
|
|
180
230
|
}
|
|
181
231
|
|
|
182
232
|
.profile {
|
|
233
|
+
position: relative;
|
|
183
234
|
display: grid;
|
|
184
235
|
grid-template-columns: auto 1fr;
|
|
185
|
-
gap: 12px;
|
|
236
|
+
gap: 12px 14px;
|
|
186
237
|
align-items: center;
|
|
187
|
-
border: 1px solid #
|
|
188
|
-
border-radius:
|
|
189
|
-
background: #
|
|
190
|
-
padding: 12px;
|
|
238
|
+
border: 1px solid #7facf249;
|
|
239
|
+
border-radius: var(--radius-md);
|
|
240
|
+
background: #0f1f38bf;
|
|
241
|
+
padding: clamp(12px, 1.8vw, 16px);
|
|
191
242
|
}
|
|
192
243
|
|
|
193
244
|
.avatar {
|
|
194
|
-
width:
|
|
195
|
-
height:
|
|
245
|
+
width: clamp(64px, 8vw, 82px);
|
|
246
|
+
height: clamp(64px, 8vw, 82px);
|
|
196
247
|
border-radius: 16px;
|
|
197
|
-
border: 1px solid #
|
|
248
|
+
border: 1px solid #7ca8e178;
|
|
198
249
|
object-fit: cover;
|
|
199
|
-
background: #
|
|
250
|
+
background: #0b1528;
|
|
251
|
+
box-shadow: 0 10px 24px #030b1961;
|
|
200
252
|
}
|
|
201
253
|
|
|
202
254
|
.profile-meta h2 {
|
|
203
|
-
margin: 0 0
|
|
204
|
-
font-size: 20px;
|
|
255
|
+
margin: 0 0 6px;
|
|
256
|
+
font-size: clamp(20px, 2.1vw, 26px);
|
|
205
257
|
line-height: 1.2;
|
|
258
|
+
letter-spacing: -0.02em;
|
|
206
259
|
}
|
|
207
260
|
|
|
208
261
|
.profile-meta p {
|
|
209
262
|
margin: 0;
|
|
210
263
|
color: var(--muted);
|
|
211
264
|
font-size: 14px;
|
|
212
|
-
line-height: 1.
|
|
265
|
+
line-height: 1.5;
|
|
213
266
|
word-break: break-word;
|
|
214
267
|
}
|
|
215
268
|
|
|
216
269
|
.grid {
|
|
270
|
+
position: relative;
|
|
217
271
|
display: grid;
|
|
218
|
-
grid-template-columns: repeat(
|
|
219
|
-
gap:
|
|
272
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
273
|
+
gap: 10px;
|
|
220
274
|
}
|
|
221
275
|
|
|
222
276
|
.metric {
|
|
223
|
-
border: 1px solid #
|
|
224
|
-
border-radius:
|
|
225
|
-
background: #
|
|
226
|
-
padding:
|
|
277
|
+
border: 1px solid #7facf242;
|
|
278
|
+
border-radius: var(--radius-md);
|
|
279
|
+
background: #0f1f39b8;
|
|
280
|
+
padding: 12px;
|
|
281
|
+
min-height: 94px;
|
|
282
|
+
display: grid;
|
|
283
|
+
align-content: space-between;
|
|
227
284
|
}
|
|
228
285
|
|
|
229
286
|
.metric-label {
|
|
230
|
-
margin: 0
|
|
231
|
-
color: #
|
|
287
|
+
margin: 0;
|
|
288
|
+
color: #9bb2d2;
|
|
232
289
|
font-size: 12px;
|
|
290
|
+
font-weight: 600;
|
|
291
|
+
letter-spacing: 0.05em;
|
|
292
|
+
text-transform: uppercase;
|
|
233
293
|
}
|
|
234
294
|
|
|
235
295
|
.metric-value {
|
|
236
|
-
margin: 0;
|
|
237
|
-
color: #
|
|
238
|
-
font-size:
|
|
296
|
+
margin: 6px 0 0;
|
|
297
|
+
color: #f1f7ff;
|
|
298
|
+
font-size: clamp(22px, 3vw, 28px);
|
|
239
299
|
font-weight: 800;
|
|
240
|
-
letter-spacing: -0.
|
|
300
|
+
letter-spacing: -0.02em;
|
|
301
|
+
line-height: 1.05;
|
|
241
302
|
}
|
|
242
303
|
|
|
243
|
-
.
|
|
244
|
-
|
|
245
|
-
border-radius: 12px;
|
|
246
|
-
background: #11302294;
|
|
247
|
-
padding: 10px;
|
|
304
|
+
.actions {
|
|
305
|
+
position: relative;
|
|
248
306
|
display: grid;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
font-size: 14px;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
.summary strong {
|
|
255
|
-
color: #f4fff8;
|
|
307
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
308
|
+
gap: 10px;
|
|
256
309
|
}
|
|
257
310
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
flex-wrap: wrap;
|
|
261
|
-
gap: 8px;
|
|
311
|
+
#user-chat-link {
|
|
312
|
+
grid-column: 1 / -1;
|
|
262
313
|
}
|
|
263
314
|
|
|
264
315
|
.footer {
|
|
265
316
|
margin: 0;
|
|
266
|
-
color: #
|
|
317
|
+
color: #88a2c8;
|
|
267
318
|
font-size: 12px;
|
|
268
|
-
|
|
319
|
+
text-align: center;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
@media (min-width: 920px) {
|
|
323
|
+
.dashboard-card {
|
|
324
|
+
grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
|
|
325
|
+
grid-template-areas:
|
|
326
|
+
'status status'
|
|
327
|
+
'error error'
|
|
328
|
+
'profile grid'
|
|
329
|
+
'actions actions';
|
|
330
|
+
gap: 14px;
|
|
331
|
+
}
|
|
269
332
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
333
|
+
#user-status {
|
|
334
|
+
grid-area: status;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
#user-error {
|
|
338
|
+
grid-area: error;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
#user-profile {
|
|
342
|
+
grid-area: profile;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
#user-grid {
|
|
346
|
+
grid-area: grid;
|
|
347
|
+
align-self: start;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
#user-actions {
|
|
351
|
+
grid-area: actions;
|
|
352
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
#user-chat-link {
|
|
356
|
+
grid-column: span 2;
|
|
273
357
|
}
|
|
274
358
|
}
|
|
275
359
|
|
|
276
|
-
@media (max-width:
|
|
360
|
+
@media (max-width: 840px) {
|
|
277
361
|
.head {
|
|
278
|
-
|
|
362
|
+
grid-template-columns: 1fr;
|
|
279
363
|
}
|
|
280
364
|
|
|
281
|
-
.
|
|
282
|
-
|
|
365
|
+
.head-actions {
|
|
366
|
+
width: 100%;
|
|
367
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
368
|
+
grid-auto-flow: row;
|
|
369
|
+
grid-auto-columns: 1fr;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.head-actions .btn {
|
|
373
|
+
width: 100%;
|
|
283
374
|
}
|
|
375
|
+
}
|
|
284
376
|
|
|
377
|
+
@media (max-width: 620px) {
|
|
285
378
|
.profile {
|
|
286
379
|
grid-template-columns: 1fr;
|
|
287
380
|
text-align: center;
|
|
@@ -291,9 +384,23 @@
|
|
|
291
384
|
margin-inline: auto;
|
|
292
385
|
}
|
|
293
386
|
|
|
294
|
-
.actions
|
|
387
|
+
.actions {
|
|
388
|
+
grid-template-columns: 1fr;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
#user-chat-link {
|
|
392
|
+
grid-column: auto;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.actions .btn,
|
|
396
|
+
.actions button.btn {
|
|
295
397
|
width: 100%;
|
|
296
|
-
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
@media (max-width: 430px) {
|
|
402
|
+
.grid {
|
|
403
|
+
grid-template-columns: 1fr;
|
|
297
404
|
}
|
|
298
405
|
}
|
|
299
406
|
</style>
|
|
@@ -312,10 +419,13 @@
|
|
|
312
419
|
</header>
|
|
313
420
|
|
|
314
421
|
<section class="content">
|
|
315
|
-
<
|
|
316
|
-
|
|
422
|
+
<div class="intro">
|
|
423
|
+
<p class="eyebrow">Painel do usuário</p>
|
|
424
|
+
<h1>Minha Conta</h1>
|
|
425
|
+
<p class="lead">Informações da sua conta vinculada ao OmniZap e atalhos rápidos para gerenciar seus stickers com agilidade no desktop e no celular.</p>
|
|
426
|
+
</div>
|
|
317
427
|
|
|
318
|
-
<article class="card">
|
|
428
|
+
<article class="card dashboard-card">
|
|
319
429
|
<p id="user-status" class="status">Carregando dados da conta...</p>
|
|
320
430
|
<p id="user-error" class="error" hidden></p>
|
|
321
431
|
|
|
@@ -347,12 +457,6 @@
|
|
|
347
457
|
</article>
|
|
348
458
|
</div>
|
|
349
459
|
|
|
350
|
-
<div id="user-summary" class="summary" hidden>
|
|
351
|
-
<div><strong>Owner JID:</strong> <span id="user-owner-jid"></span></div>
|
|
352
|
-
<div><strong>Google ID:</strong> <span id="user-google-sub"></span></div>
|
|
353
|
-
<div><strong>Sessão expira:</strong> <span id="user-expires-at"></span></div>
|
|
354
|
-
</div>
|
|
355
|
-
|
|
356
460
|
<div id="user-actions" class="actions" hidden>
|
|
357
461
|
<a id="user-chat-link" class="btn primary" href="https://api.whatsapp.com/send/?text=%2Fmenu&type=custom_url&app_absent=0" target="_blank" rel="noreferrer noopener"> Voltar ao chat do bot (/menu) </a>
|
|
358
462
|
<a id="user-manage-main-link" class="btn" href="/stickers/perfil">Gerenciar meus stickers</a>
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
export const createStickerCatalogAdminBanService = ({ executeQuery, tables, sanitizeText, normalizeGoogleSubject, normalizeEmail, normalizeJid, toIsoOrNull, revokeGoogleWebSessionsByIdentity = async () => 0 }) => {
|
|
4
|
+
const TABLES = tables;
|
|
5
|
+
|
|
6
|
+
const mapAdminBanRow = (row) => {
|
|
7
|
+
if (!row || typeof row !== 'object') return null;
|
|
8
|
+
return {
|
|
9
|
+
id: String(row.id || '').trim(),
|
|
10
|
+
google_sub: normalizeGoogleSubject(row.google_sub),
|
|
11
|
+
email: normalizeEmail(row.email),
|
|
12
|
+
owner_jid: normalizeJid(row.owner_jid) || null,
|
|
13
|
+
reason: sanitizeText(row.reason || '', 255, { allowEmpty: true }) || null,
|
|
14
|
+
created_by_google_sub: normalizeGoogleSubject(row.created_by_google_sub),
|
|
15
|
+
created_by_email: normalizeEmail(row.created_by_email),
|
|
16
|
+
created_at: toIsoOrNull(row.created_at),
|
|
17
|
+
updated_at: toIsoOrNull(row.updated_at),
|
|
18
|
+
revoked_at: toIsoOrNull(row.revoked_at),
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const findActiveAdminBanForIdentity = async ({ googleSub = '', email = '', ownerJid = '' } = {}) => {
|
|
23
|
+
const normalizedSub = normalizeGoogleSubject(googleSub);
|
|
24
|
+
const normalizedEmail = normalizeEmail(email);
|
|
25
|
+
const normalizedOwnerJid = normalizeJid(ownerJid) || '';
|
|
26
|
+
const clauses = [];
|
|
27
|
+
const params = [];
|
|
28
|
+
if (normalizedSub) {
|
|
29
|
+
clauses.push('google_sub = ?');
|
|
30
|
+
params.push(normalizedSub);
|
|
31
|
+
}
|
|
32
|
+
if (normalizedEmail) {
|
|
33
|
+
clauses.push('email = ?');
|
|
34
|
+
params.push(normalizedEmail);
|
|
35
|
+
}
|
|
36
|
+
if (normalizedOwnerJid) {
|
|
37
|
+
clauses.push('owner_jid = ?');
|
|
38
|
+
params.push(normalizedOwnerJid);
|
|
39
|
+
}
|
|
40
|
+
if (!clauses.length) return null;
|
|
41
|
+
|
|
42
|
+
const rows = await executeQuery(
|
|
43
|
+
`SELECT *
|
|
44
|
+
FROM ${TABLES.STICKER_WEB_ADMIN_BAN}
|
|
45
|
+
WHERE revoked_at IS NULL
|
|
46
|
+
AND (${clauses.join(' OR ')})
|
|
47
|
+
ORDER BY created_at DESC
|
|
48
|
+
LIMIT 1`,
|
|
49
|
+
params,
|
|
50
|
+
);
|
|
51
|
+
return mapAdminBanRow(Array.isArray(rows) ? rows[0] : null);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const listAdminBans = async ({ activeOnly = false, limit = 100 } = {}) => {
|
|
55
|
+
const safeLimit = Math.max(1, Math.min(500, Number(limit || 100)));
|
|
56
|
+
const rows = await executeQuery(
|
|
57
|
+
`SELECT *
|
|
58
|
+
FROM ${TABLES.STICKER_WEB_ADMIN_BAN}
|
|
59
|
+
${activeOnly ? 'WHERE revoked_at IS NULL' : ''}
|
|
60
|
+
ORDER BY created_at DESC
|
|
61
|
+
LIMIT ${safeLimit}`,
|
|
62
|
+
);
|
|
63
|
+
return (Array.isArray(rows) ? rows : []).map(mapAdminBanRow).filter(Boolean);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const createAdminBanRecord = async ({ googleSub = '', email = '', ownerJid = '', reason = '', adminSession = null }) => {
|
|
67
|
+
const normalizedSub = normalizeGoogleSubject(googleSub);
|
|
68
|
+
const normalizedEmail = normalizeEmail(email);
|
|
69
|
+
const normalizedOwnerJid = normalizeJid(ownerJid) || '';
|
|
70
|
+
if (!normalizedSub && !normalizedEmail && !normalizedOwnerJid) {
|
|
71
|
+
const error = new Error('Informe google_sub, email ou owner_jid para banir.');
|
|
72
|
+
error.statusCode = 400;
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const existing = await findActiveAdminBanForIdentity({
|
|
77
|
+
googleSub: normalizedSub,
|
|
78
|
+
email: normalizedEmail,
|
|
79
|
+
ownerJid: normalizedOwnerJid,
|
|
80
|
+
});
|
|
81
|
+
if (existing) return { created: false, ban: existing };
|
|
82
|
+
|
|
83
|
+
const banId = randomUUID();
|
|
84
|
+
await executeQuery(
|
|
85
|
+
`INSERT INTO ${TABLES.STICKER_WEB_ADMIN_BAN}
|
|
86
|
+
(id, google_sub, email, owner_jid, reason, created_by_google_sub, created_by_email)
|
|
87
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
88
|
+
[banId, normalizedSub || null, normalizedEmail || null, normalizedOwnerJid || null, sanitizeText(reason || '', 255, { allowEmpty: true }) || null, normalizeGoogleSubject(adminSession?.googleSub) || null, normalizeEmail(adminSession?.email) || null],
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (normalizedSub || normalizedEmail || normalizedOwnerJid) {
|
|
92
|
+
await revokeGoogleWebSessionsByIdentity({
|
|
93
|
+
googleSub: normalizedSub,
|
|
94
|
+
email: normalizedEmail,
|
|
95
|
+
ownerJid: normalizedOwnerJid,
|
|
96
|
+
}).catch(() => {});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const rows = await executeQuery(`SELECT * FROM ${TABLES.STICKER_WEB_ADMIN_BAN} WHERE id = ? LIMIT 1`, [banId]);
|
|
100
|
+
return { created: true, ban: mapAdminBanRow(Array.isArray(rows) ? rows[0] : null) };
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const revokeAdminBanRecord = async (banId) => {
|
|
104
|
+
const normalizedId = sanitizeText(banId, 36, { allowEmpty: false });
|
|
105
|
+
if (!normalizedId) {
|
|
106
|
+
const error = new Error('ban_id invalido.');
|
|
107
|
+
error.statusCode = 400;
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
await executeQuery(
|
|
111
|
+
`UPDATE ${TABLES.STICKER_WEB_ADMIN_BAN}
|
|
112
|
+
SET revoked_at = COALESCE(revoked_at, UTC_TIMESTAMP())
|
|
113
|
+
WHERE id = ?`,
|
|
114
|
+
[normalizedId],
|
|
115
|
+
);
|
|
116
|
+
const rows = await executeQuery(`SELECT * FROM ${TABLES.STICKER_WEB_ADMIN_BAN} WHERE id = ? LIMIT 1`, [normalizedId]);
|
|
117
|
+
return mapAdminBanRow(Array.isArray(rows) ? rows[0] : null);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const assertGoogleIdentityNotBanned = async ({ sub = '', email = '', ownerJid = '' } = {}) => {
|
|
121
|
+
const ban = await findActiveAdminBanForIdentity({ googleSub: sub, email, ownerJid });
|
|
122
|
+
if (!ban) return null;
|
|
123
|
+
const error = new Error('Conta bloqueada pela administracao.');
|
|
124
|
+
error.statusCode = 403;
|
|
125
|
+
error.code = 'ADMIN_BANNED';
|
|
126
|
+
error.ban = ban;
|
|
127
|
+
throw error;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
mapAdminBanRow,
|
|
132
|
+
findActiveAdminBanForIdentity,
|
|
133
|
+
listAdminBans,
|
|
134
|
+
createAdminBanRecord,
|
|
135
|
+
revokeAdminBanRecord,
|
|
136
|
+
assertGoogleIdentityNotBanned,
|
|
137
|
+
};
|
|
138
|
+
};
|