Skip to content

Commit 698d856

Browse files
authored
Ver 0.0.2
2 parents 27d8d59 + 971db96 commit 698d856

20 files changed

Lines changed: 360 additions & 21 deletions

.dockerignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/venv/
2+
/.idea/
3+
.env
4+
db.sqlite3
5+
/staticfiles/
6+
/dump.rdb
7+
/prod.env
8+
/celerybeat-schedule

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
db.sqlite3
55
/staticfiles/
66
/dump.rdb
7+
/prod.env
8+
/celerybeat-schedule

README.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,29 @@
1+
# synapse_admin
2+
13
"synapse_admin" is a web-based administration tool built using Django framework for managing Matrix Synapse servers.
2-
It provides an intuitive interface for managing user accounts, rooms, permissions, and other configurations.
4+
5+
It provides an intuitive interface for managing user accounts, ~~rooms~~, ~~permissions~~, and other configurations.
6+
37
With features like real-time user activity monitoring and detailed logs, "synapse_admin" simplifies the management of Matrix Synapse servers, making it easier for administrators to manage their Matrix-based communication platforms.
4-
The project is open source and contributions are welcome from the community."
8+
9+
The project is open source and contributions are welcome from the community.
10+
11+
![Dashboard page](screenshots/1.png)
12+
13+
_Dashboard page_
14+
15+
![Users page](screenshots/2.png)
16+
17+
_Users page_
18+
19+
![Server notices page](screenshots/3.png)
20+
21+
_Server notices page_
22+
23+
![User page](screenshots/4.png)
24+
25+
_User page_
26+
27+
![Init page](screenshots/5.png)
28+
29+
_Init page_

dashboard/tasks.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from celery import Celery
2+
from django.conf import settings
3+
4+
from .helpers import load_media_statistics, load_server_map
5+
6+
app = Celery()
7+
8+
9+
@app.task
10+
def update_media_statistics_info() -> None:
11+
load_media_statistics(
12+
access_token=settings.MATRIX_ADMIN_TOKEN,
13+
server_name=settings.MATRIX_DOMAIN
14+
)
15+
16+
17+
@app.task
18+
def update_server_map() -> None:
19+
load_server_map(
20+
access_token=settings.MATRIX_ADMIN_TOKEN,
21+
server_name=settings.MATRIX_DOMAIN
22+
)

dashboard/views.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,22 @@ def get_context_data(self, **kwargs):
4545
access_token=settings.MATRIX_ADMIN_TOKEN
4646
)
4747

48-
# Sorts users by last creation_ts and slice last week
4948
users: dict = cache.get('users', {})
49+
50+
# Sorts users by last creation_ts and slice last week
5051
last_week: datetime.datetime = datetime.datetime.now() - datetime.timedelta(weeks=1)
5152
new_users: list = [user for user in users.values() if user['created_at'] > last_week]
53+
54+
# Sorts users by last_seen_at and filter for today
55+
today: datetime.date = datetime.datetime.now().date()
56+
active_users_today: list = sorted(
57+
[user for user in users.values() if
58+
user['last_seen_at'] != 'Unknown' and user['last_seen_at'].date() == today],
59+
key=lambda k: k['last_seen_at'], reverse=True
60+
)
61+
5262
context['new_users_for_last_week'] = new_users
63+
context['active_users_today'] = active_users_today
5364
context['cached_users_updated_at'] = cached_users_updated_at
5465

5566
context['amount_of_uploaded_media'] = convert_size(

docker-compose-prod.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
version: "3.9"
2+
3+
services:
4+
web:
5+
build: .
6+
command: sh -c "python manage.py collectstatic --noinput && gunicorn project.wsgi -b 0.0.0.0:8000"
7+
volumes:
8+
- .:/app
9+
ports:
10+
- "8000:8000"
11+
env_file: prod.env
12+
depends_on:
13+
- redis
14+
restart: unless-stopped
15+
16+
redis:
17+
image: redis
18+
ports:
19+
- "6379:6379"
20+
restart: unless-stopped
21+
22+
celery:
23+
build: .
24+
command: celery -A project worker -l INFO
25+
env_file: prod.env
26+
volumes:
27+
- ".:/app"
28+
depends_on:
29+
- redis
30+
restart: unless-stopped
31+
32+
celery-beat:
33+
build: .
34+
command: celery -A project beat -l INFO
35+
env_file: prod.env
36+
volumes:
37+
- ".:/app"
38+
depends_on:
39+
- redis
40+
restart: unless-stopped

load_presentation_mode_data.py

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import datetime
2+
import os
3+
import random
4+
from django.core.cache import cache
5+
from django.conf import settings
6+
7+
from dashboard.helpers import convert_size
8+
9+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
10+
11+
now_datetime: datetime.datetime = datetime.datetime.now()
12+
13+
# Set init successful
14+
cache.set(
15+
'init_successful',
16+
True,
17+
60 * 60 # 1 hour
18+
)
19+
20+
# Set random users
21+
users = {}
22+
for i in range(0, 20):
23+
user_name: str = f'@user_{i}:matrix.test.server'
24+
25+
user = {
26+
'name': user_name,
27+
'name_without_server_name_ending': user_name[:-(len('matrix.test.server') + 1)],
28+
'display_name': f'@user_{i}',
29+
'is_admin': random.getrandbits(1),
30+
'is_deactivated': random.getrandbits(1),
31+
'created_at': now_datetime - datetime.timedelta(
32+
days=random.randint(2, 20), hours=random.randint(1, 6), minutes=random.randint(1, 60)
33+
),
34+
'avatar_mxc_url': None,
35+
'last_seen_ip': '127.0.0.1',
36+
'last_seen_at': now_datetime - datetime.timedelta(
37+
days=random.randint(0, 2), hours=random.randint(1, 4), minutes=random.randint(1, 60)
38+
),
39+
'last_seen_country': random.choice(('🇺🇸', '🇺🇦', '🏳️‍🌈'))
40+
}
41+
42+
users[user_name] = user
43+
44+
cache.set(
45+
settings.CACHED_USERS,
46+
users,
47+
60 * 60 # 1 hour
48+
)
49+
cache.set(
50+
settings.CACHED_USERS_UPDATED_AT,
51+
now_datetime,
52+
60 * 60 # 1 hour
53+
)
54+
55+
# Set media statistics
56+
media_statistics = []
57+
58+
for user in users.values():
59+
media_count: int = random.randint(0, 100)
60+
61+
media_statistics.append(
62+
{
63+
'user_id': user['name'],
64+
'displayname': user['name_without_server_name_ending'],
65+
'media_count': media_count,
66+
'media_length': media_count * random.randint(100000, 900000)
67+
}
68+
)
69+
70+
cache.set(
71+
settings.CACHED_MEDIA_STATISTICS,
72+
media_statistics,
73+
60 * 60 # 1 hour
74+
)
75+
cache.set(
76+
settings.CACHED_MEDIA_STATISTICS_UPDATED_AT,
77+
now_datetime,
78+
60 * 60 # 1 hour
79+
)
80+
81+
for user_statistics in media_statistics:
82+
try:
83+
users[user_statistics['user_id']]['upload_media_count'] = user_statistics['media_count']
84+
users[user_statistics['user_id']]['size_of_upload_media'] = convert_size(user_statistics['media_length'])
85+
except KeyError:
86+
continue
87+
88+
cache.set(
89+
settings.CACHED_USERS,
90+
users,
91+
60 * 60 # 1 hour
92+
)
93+
94+
# Set server map
95+
server_map: dict = {
96+
'nodes': [
97+
{
98+
'color': '#99a9af',
99+
'size': random.randint(10, 30),
100+
'id': '!420C1B7875A242ADB6:matrix.org',
101+
'label': '#public_room_1:matrix.test.server',
102+
'shape': 'dot'
103+
},
104+
{
105+
'color': '#99a9af',
106+
'size': random.randint(10, 30),
107+
'id': '!420C1B7875A242ADB7:matrix.org',
108+
'label': '#public_room_2:matrix.test.server',
109+
'shape': 'dot'
110+
}
111+
],
112+
'edges': []
113+
}
114+
115+
for user in users.values():
116+
server_map['nodes'].append(
117+
{
118+
'color': '#326051',
119+
'size': 5,
120+
'id': user['name'],
121+
'label': user['name_without_server_name_ending'],
122+
'shape': 'dot'
123+
}
124+
)
125+
126+
if random.getrandbits(1):
127+
server_map['edges'].append(
128+
{
129+
'from': user['name'],
130+
'to': server_map['nodes'][random.getrandbits(1)]['id']
131+
}
132+
)
133+
134+
for user in users.values():
135+
if random.getrandbits(1):
136+
first_user = random.choice(tuple(users.values()))
137+
second_user = random.choice(tuple(users.values()))
138+
139+
if first_user != second_user:
140+
server_map['edges'].append(
141+
{
142+
'from': first_user['name'],
143+
'to': second_user['name']
144+
}
145+
)
146+
147+
cache.set(
148+
settings.CACHED_SERVER_MAP,
149+
server_map,
150+
60 * 60 # 1 hour
151+
)
152+
cache.set(
153+
settings.CACHED_SERVER_MAP_UPDATED_AT,
154+
now_datetime,
155+
60 * 60 # 1 hour
156+
)

project/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .celery import app as celery_app
2+
3+
__all__ = ('celery_app',)

project/celery.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import os
2+
from celery import Celery
3+
4+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')
5+
6+
app = Celery('project')
7+
app.config_from_object('django.conf:settings', namespace='CELERY')
8+
app.autodiscover_tasks()

project/settings.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
ALLOWED_HOSTS = []
1313

14-
1514
INSTALLED_APPS = [
1615
'django.contrib.auth',
1716
'django.contrib.contenttypes',
@@ -35,6 +34,7 @@
3534
'django.contrib.auth.middleware.AuthenticationMiddleware',
3635
'django.contrib.messages.middleware.MessageMiddleware',
3736
'django.middleware.clickjacking.XFrameOptionsMiddleware',
37+
'whitenoise.middleware.WhiteNoiseMiddleware',
3838
]
3939

4040
ROOT_URLCONF = 'project.urls'
@@ -80,7 +80,6 @@
8080
},
8181
]
8282

83-
8483
LANGUAGE_CODE = 'en-us'
8584
TIME_ZONE = 'Europe/Kiev'
8685
USE_I18N = True
@@ -91,6 +90,7 @@
9190
STATICFILES_DIRS = (
9291
BASE_DIR / 'static',
9392
)
93+
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
9494

9595
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
9696

@@ -134,3 +134,20 @@
134134

135135
CACHED_MEDIA_STATISTICS: str = 'media_statistics'
136136
CACHED_MEDIA_STATISTICS_UPDATED_AT: str = 'media_statistics_updated_at'
137+
138+
# CELERY
139+
CELERY_BEAT_SCHEDULE = {
140+
'update_users_info_every_30m': {
141+
'task': 'users.tasks.update_users_info',
142+
'schedule': 60 * 30
143+
},
144+
'update_media_statistics_info_every_1h': {
145+
'task': 'dashboard.tasks.update_media_statistics_info',
146+
'schedule': 60 * 60
147+
},
148+
'update_server_map_every_12h': {
149+
'task': 'users.tasks.dashboard.tasks.update_server_map',
150+
'schedule': 60 * 60 * 12
151+
},
152+
}
153+
CELERY_BROKER_URL = env('REDIS_LOCATION', default='redis://redis:6379/')

0 commit comments

Comments
 (0)