Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
V
vidai
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
SexHackMe
vidai
Commits
30a08f03
Commit
30a08f03
authored
Oct 06, 2025
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add cluster tokens management page for worker processes
parent
1596a654
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
164 additions
and
2 deletions
+164
-2
cluster_tokens.html
templates/admin/cluster_tokens.html
+90
-0
base.html
templates/base.html
+1
-1
database.py
vidai/database.py
+32
-0
web.py
vidai/web.py
+41
-1
No files found.
templates/admin/cluster_tokens.html
0 → 100644
View file @
30a08f03
{% extends "base.html" %}
{% block title %}Cluster Tokens - VidAI{% endblock %}
{% block head %}
<style>
.container
{
max-width
:
1400px
;
margin
:
2rem
auto
;
padding
:
0
2rem
;
}
.admin-card
{
background
:
white
;
padding
:
2rem
;
border-radius
:
12px
;
box-shadow
:
0
2px
10px
rgba
(
0
,
0
,
0
,
0.05
);
margin-bottom
:
2rem
;
}
.card-header
{
margin-bottom
:
1.5rem
;
}
.card-header
h3
{
margin
:
0
;
color
:
#1e293b
;
}
.btn
{
padding
:
0.75rem
2rem
;
background
:
#667eea
;
color
:
white
;
border
:
none
;
border-radius
:
8px
;
font-size
:
1rem
;
font-weight
:
600
;
cursor
:
pointer
;
text-decoration
:
none
;
display
:
inline-block
;
}
.btn
:hover
{
background
:
#5a67d8
;
}
.btn-danger
{
background
:
#dc2626
;
}
.btn-danger
:hover
{
background
:
#b91c1c
;
}
.btn-success
{
background
:
#059669
;
}
.btn-success
:hover
{
background
:
#047857
;
}
.btn-icon
{
padding
:
0.5rem
;
background
:
none
;
border
:
none
;
cursor
:
pointer
;
color
:
#64748b
;
}
.btn-icon
:hover
{
color
:
#374151
;
}
.table
{
width
:
100%
;
border-collapse
:
collapse
;
margin-top
:
1rem
;
}
.table
th
,
.table
td
{
padding
:
1rem
;
text-align
:
left
;
border-bottom
:
1px
solid
#e5e7eb
;
}
.table
th
{
background
:
#f8fafc
;
font-weight
:
600
;
color
:
#374151
;
}
.actions-cell
{
display
:
flex
;
gap
:
0.5rem
;
}
.status-active
{
color
:
#065f46
;
font-weight
:
500
;
}
.status-inactive
{
color
:
#dc2626
;
font-weight
:
500
;
}
.alert
{
padding
:
0.75rem
;
border-radius
:
8px
;
margin-bottom
:
1rem
;
}
.alert-error
{
background
:
#fee2e2
;
color
:
#dc2626
;
border
:
1px
solid
#fecaca
;
}
.alert-success
{
background
:
#d1fae5
;
color
:
#065f46
;
border
:
1px
solid
#a7f3d0
;
}
.token-preview
{
font-family
:
monospace
;
background
:
#f1f5f9
;
padding
:
0.25rem
0.5rem
;
border-radius
:
4px
;
font-size
:
0.875rem
;
}
</style>
{% endblock %}
{% block content %}
<div
class=
"container"
>
<div
class=
"admin-card"
>
<div
class=
"card-header"
>
<h3><i
class=
"fas fa-key"
></i>
Cluster Tokens
</h3>
<p>
Manage authentication tokens for worker processes in the cluster.
</p>
</div>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div
class=
"alert alert-{{ 'error' if category == 'error' else 'success' }}"
>
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
<form
method=
"post"
action=
"/admin/cluster_tokens/generate"
style=
"margin-bottom: 2rem;"
>
<button
type=
"submit"
class=
"btn"
><i
class=
"fas fa-plus"
></i>
Generate New Token
</button>
</form>
<table
class=
"table"
>
<thead>
<tr>
<th>
ID
</th>
<th>
Token
</th>
<th>
Status
</th>
<th>
Created
</th>
<th>
Actions
</th>
</tr>
</thead>
<tbody>
{% for token in worker_tokens %}
<tr>
<td>
{{ token.get('id') }}
</td>
<td><span
class=
"token-preview"
>
{{ token.get('token')[:20] }}...
</span></td>
<td><span
class=
"status-{{ 'active' if token.get('active') else 'inactive' }}"
>
{{ 'Active' if token.get('active') else 'Inactive' }}
</span></td>
<td>
{{ token.get('created_at', 'N/A')[:19] if token.get('created_at') else 'N/A' }}
</td>
<td
class=
"actions-cell"
>
{% if token.get('active') %}
<form
method=
"post"
action=
"/admin/cluster_tokens/{{ token.get('id') }}/deactivate"
style=
"display: inline;"
>
<button
type=
"submit"
class=
"btn-icon"
title=
"Deactivate"
><i
class=
"fas fa-ban"
></i></button>
</form>
{% else %}
<form
method=
"post"
action=
"/admin/cluster_tokens/{{ token.get('id') }}/activate"
style=
"display: inline;"
>
<button
type=
"submit"
class=
"btn btn-success"
title=
"Activate"
style=
"padding: 0.25rem 0.5rem; font-size: 0.75rem;"
>
Activate
</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if not worker_tokens %}
<p
style=
"text-align: center; color: #64748b; margin-top: 2rem;"
>
No cluster tokens found. Generate your first token above.
</p>
{% endif %}
</div>
</div>
{% endblock %}
\ No newline at end of file
templates/base.html
View file @
30a08f03
...
@@ -78,7 +78,7 @@
...
@@ -78,7 +78,7 @@
{% endif %}
{% endif %}
<a
href=
"/history"
{%
if
active_page =
=
'
history
'
%}
class=
"active"
{%
endif
%}
>
History
</a>
<a
href=
"/history"
{%
if
active_page =
=
'
history
'
%}
class=
"active"
{%
endif
%}
>
History
</a>
{% if user.get('role') == 'admin' %}
{% if user.get('role') == 'admin' %}
<a
href=
"/a
pi_tokens"
{%
if
active_page =
=
'
api_tokens
'
%}
class=
"active"
{%
endif
%}
>
API
Tokens
</a>
<a
href=
"/a
dmin/cluster_tokens"
{%
if
active_page =
=
'
cluster_tokens
'
%}
class=
"active"
{%
endif
%}
>
Cluster
Tokens
</a>
<a
href=
"/settings"
{%
if
active_page =
=
'
settings
'
%}
class=
"active"
{%
endif
%}
>
Settings
</a>
<a
href=
"/settings"
{%
if
active_page =
=
'
settings
'
%}
class=
"active"
{%
endif
%}
>
Settings
</a>
{% endif %}
{% endif %}
</nav>
</nav>
...
...
vidai/database.py
View file @
30a08f03
...
@@ -1138,6 +1138,38 @@ def create_worker_token() -> str:
...
@@ -1138,6 +1138,38 @@ def create_worker_token() -> str:
return
token
return
token
def
get_worker_tokens
()
->
List
[
Dict
[
str
,
Any
]]:
"""Get all worker tokens."""
conn
=
get_db_connection
()
cursor
=
conn
.
cursor
()
cursor
.
execute
(
'SELECT id, token, active, created_at FROM worker_tokens ORDER BY created_at DESC'
)
rows
=
cursor
.
fetchall
()
conn
.
close
()
return
[
dict
(
row
)
for
row
in
rows
]
def
deactivate_worker_token
(
token_id
:
int
)
->
bool
:
"""Deactivate a worker token."""
conn
=
get_db_connection
()
cursor
=
conn
.
cursor
()
cursor
.
execute
(
'UPDATE worker_tokens SET active = 0 WHERE id = ?'
,
(
token_id
,))
conn
.
commit
()
success
=
cursor
.
rowcount
>
0
conn
.
close
()
return
success
def
activate_worker_token
(
token_id
:
int
)
->
bool
:
"""Activate a worker token."""
conn
=
get_db_connection
()
cursor
=
conn
.
cursor
()
cursor
.
execute
(
'UPDATE worker_tokens SET active = 1 WHERE id = ?'
,
(
token_id
,))
conn
.
commit
()
success
=
cursor
.
rowcount
>
0
conn
.
close
()
return
success
def
create_user_api_token
(
user_id
:
int
,
name
:
str
)
->
str
:
def
create_user_api_token
(
user_id
:
int
,
name
:
str
)
->
str
:
"""Create a user API token for programmatic access."""
"""Create a user API token for programmatic access."""
import
jwt
import
jwt
...
...
vidai/web.py
View file @
30a08f03
...
@@ -416,7 +416,47 @@ def generate_worker_token():
...
@@ -416,7 +416,47 @@ def generate_worker_token():
from
.auth
import
generate_worker_token
from
.auth
import
generate_worker_token
token
=
generate_worker_token
()
token
=
generate_worker_token
()
flash
(
f
'New worker token generated: {token[:20]}...'
,
'success'
)
flash
(
f
'New worker token generated: {token[:20]}...'
,
'success'
)
return
redirect
(
url_for
(
'settings'
))
return
redirect
(
url_for
(
'cluster_tokens'
))
@
app
.
route
(
'/admin/cluster_tokens'
)
@
admin_required
def
cluster_tokens
():
"""Cluster tokens management page."""
from
.database
import
get_worker_tokens
worker_tokens
=
get_worker_tokens
()
user
=
get_current_user_session
()
return
render_template
(
'admin/cluster_tokens.html'
,
user
=
user
,
worker_tokens
=
worker_tokens
,
active_page
=
'cluster_tokens'
)
@
app
.
route
(
'/admin/cluster_tokens/generate'
,
methods
=
[
'POST'
])
@
admin_required
def
generate_cluster_token
():
"""Generate a new cluster token."""
from
.auth
import
generate_worker_token
token
=
generate_worker_token
()
flash
(
f
'New cluster token generated: {token[:20]}...'
,
'success'
)
return
redirect
(
url_for
(
'cluster_tokens'
))
@
app
.
route
(
'/admin/cluster_tokens/<int:token_id>/deactivate'
,
methods
=
[
'POST'
])
@
admin_required
def
deactivate_cluster_token
(
token_id
):
"""Deactivate a cluster token."""
from
.database
import
deactivate_worker_token
if
deactivate_worker_token
(
token_id
):
flash
(
'Token deactivated successfully!'
,
'success'
)
else
:
flash
(
'Failed to deactivate token.'
,
'error'
)
return
redirect
(
url_for
(
'cluster_tokens'
))
@
app
.
route
(
'/admin/cluster_tokens/<int:token_id>/activate'
,
methods
=
[
'POST'
])
@
admin_required
def
activate_cluster_token
(
token_id
):
"""Activate a cluster token."""
from
.database
import
activate_worker_token
if
activate_worker_token
(
token_id
):
flash
(
'Token activated successfully!'
,
'success'
)
else
:
flash
(
'Failed to activate token.'
,
'error'
)
return
redirect
(
url_for
(
'cluster_tokens'
))
@
app
.
route
(
'/api_tokens'
)
@
app
.
route
(
'/api_tokens'
)
@
login_required
@
login_required
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment