Compare commits
27 Commits
e9574ff7a8
...
prod
| Author | SHA1 | Date | |
|---|---|---|---|
| bfe281fb05 | |||
| f8b700b982 | |||
| c96ad735d7 | |||
| ce266c879c | |||
| ddb8b97fd4 | |||
| e014b1f526 | |||
| 4bffbaa71c | |||
| f1b57abeca | |||
| d756179afc | |||
| b9a2ab5509 | |||
| 8fb349d74b | |||
| eec0828dda | |||
| 7238b50ee6 | |||
| 2a30408bf0 | |||
| ed33722449 | |||
| a79f6cd9f0 | |||
| 5275687b26 | |||
| f47f0d61ca | |||
| fba06976d4 | |||
| 965a015c51 | |||
| 3045e8334a | |||
| 2b739efb3a | |||
| f3e0b835d1 | |||
| fb299a7908 | |||
| ff45d77f44 | |||
| c6388b04b2 | |||
| 0948519267 |
@@ -6,16 +6,17 @@ services:
|
|||||||
platform-nginx:
|
platform-nginx:
|
||||||
image: mathwave/sprint-repo:platform
|
image: mathwave/sprint-repo:platform
|
||||||
networks:
|
networks:
|
||||||
- common-infra-nginx
|
- common-infra-nginx-development
|
||||||
|
- configurator-development
|
||||||
|
- postgres-development
|
||||||
|
- minio-development
|
||||||
environment:
|
environment:
|
||||||
DB_HOST: "pg.develop.sprinthub.ru"
|
DB_HOST: "postgres"
|
||||||
DB_PASSWORD: $DB_PASSWORD_DEV
|
DB_PASSWORD: $DB_PASSWORD_DEV
|
||||||
MINIO_HOST: "minio.develop.sprinthub.ru"
|
MINIO_HOST: "minio"
|
||||||
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_DEV
|
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_DEV
|
||||||
REDIS_HOST: "redis.develop.sprinthub.ru"
|
REDIS_HOST: "redis.dev.chocomarsh.com"
|
||||||
REDIS_PASSWORD: $REDIS_PASSWORD_DEV
|
REDIS_PASSWORD: $REDIS_PASSWORD_DEV
|
||||||
RABBITMQ_HOST: "rabbitmq.develop.sprinthub.ru"
|
|
||||||
RABBITMQ_PASSWORD: $RABBITMQ_PASSWORD_DEV
|
|
||||||
VK_SERVICE_TOKEN: $VK_SERVICE_TOKEN
|
VK_SERVICE_TOKEN: $VK_SERVICE_TOKEN
|
||||||
YANDEX_SERVICE_TOKEN: $YANDEX_SERVICE_TOKEN
|
YANDEX_SERVICE_TOKEN: $YANDEX_SERVICE_TOKEN
|
||||||
PLATFORM_SECURITY_TOKEN: $PLATFORM_SECURITY_TOKEN
|
PLATFORM_SECURITY_TOKEN: $PLATFORM_SECURITY_TOKEN
|
||||||
@@ -36,15 +37,16 @@ services:
|
|||||||
|
|
||||||
fetch_stats:
|
fetch_stats:
|
||||||
image: mathwave/sprint-repo:platform
|
image: mathwave/sprint-repo:platform
|
||||||
|
networks:
|
||||||
|
- postgres-development
|
||||||
|
- minio-development
|
||||||
environment:
|
environment:
|
||||||
DB_HOST: "pg.develop.sprinthub.ru"
|
DB_HOST: "postgres"
|
||||||
DB_PASSWORD: $DB_PASSWORD_DEV
|
DB_PASSWORD: $DB_PASSWORD_DEV
|
||||||
MINIO_HOST: "minio.develop.sprinthub.ru"
|
MINIO_HOST: "minio"
|
||||||
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_DEV
|
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_DEV
|
||||||
REDIS_HOST: "redis.develop.sprinthub.ru"
|
REDIS_HOST: "redis.dev.chocomarsh.com"
|
||||||
REDIS_PASSWORD: $REDIS_PASSWORD_DEV
|
REDIS_PASSWORD: $REDIS_PASSWORD_DEV
|
||||||
RABBITMQ_HOST: "rabbitmq.develop.sprinthub.ru"
|
|
||||||
RABBITMQ_PASSWORD: $RABBITMQ_PASSWORD_DEV
|
|
||||||
VK_SERVICE_TOKEN: $VK_SERVICE_TOKEN
|
VK_SERVICE_TOKEN: $VK_SERVICE_TOKEN
|
||||||
YANDEX_SERVICE_TOKEN: $YANDEX_SERVICE_TOKEN
|
YANDEX_SERVICE_TOKEN: $YANDEX_SERVICE_TOKEN
|
||||||
PLATFORM_SECURITY_TOKEN: $PLATFORM_SECURITY_TOKEN
|
PLATFORM_SECURITY_TOKEN: $PLATFORM_SECURITY_TOKEN
|
||||||
@@ -59,11 +61,19 @@ services:
|
|||||||
|
|
||||||
migrate:
|
migrate:
|
||||||
image: mathwave/sprint-repo:platform
|
image: mathwave/sprint-repo:platform
|
||||||
|
networks:
|
||||||
|
- postgres-development
|
||||||
|
- minio-development
|
||||||
environment:
|
environment:
|
||||||
DB_HOST: "pg.develop.sprinthub.ru"
|
DB_HOST: "postgres"
|
||||||
DB_PASSWORD: $DB_PASSWORD_DEV
|
DB_PASSWORD: $DB_PASSWORD_DEV
|
||||||
MINIO_HOST: "minio.develop.sprinthub.ru"
|
MINIO_HOST: "minio"
|
||||||
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_DEV
|
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_DEV
|
||||||
|
REDIS_HOST: "redis.dev.chocomarsh.com"
|
||||||
|
REDIS_PASSWORD: $REDIS_PASSWORD_DEV
|
||||||
|
VK_SERVICE_TOKEN: $VK_SERVICE_TOKEN
|
||||||
|
YANDEX_SERVICE_TOKEN: $YANDEX_SERVICE_TOKEN
|
||||||
|
PLATFORM_SECURITY_TOKEN: $PLATFORM_SECURITY_TOKEN
|
||||||
command: migrate
|
command: migrate
|
||||||
deploy:
|
deploy:
|
||||||
mode: replicated
|
mode: replicated
|
||||||
@@ -74,5 +84,11 @@ services:
|
|||||||
order: start-first
|
order: start-first
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
common-infra-nginx:
|
common-infra-nginx-development:
|
||||||
external: true
|
external: true
|
||||||
|
configurator-development:
|
||||||
|
external: true
|
||||||
|
postgres-development:
|
||||||
|
external: true
|
||||||
|
minio-development:
|
||||||
|
external: true
|
||||||
|
|||||||
@@ -7,18 +7,20 @@ services:
|
|||||||
image: mathwave/sprint-repo:platform
|
image: mathwave/sprint-repo:platform
|
||||||
networks:
|
networks:
|
||||||
- common-infra-nginx
|
- common-infra-nginx
|
||||||
|
- configurator
|
||||||
|
- postgres
|
||||||
|
- minio
|
||||||
environment:
|
environment:
|
||||||
DB_HOST: "pg.sprinthub.ru"
|
DB_HOST: "postgres"
|
||||||
DB_PASSWORD: $DB_PASSWORD_PROD
|
DB_PASSWORD: $DB_PASSWORD_PROD
|
||||||
MINIO_HOST: "minio.sprinthub.ru"
|
MINIO_HOST: "minio"
|
||||||
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_PROD
|
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_PROD
|
||||||
REDIS_HOST: "redis.sprinthub.ru"
|
REDIS_HOST: "redis.chocomarsh.com"
|
||||||
REDIS_PASSWORD: $REDIS_PASSWORD_PROD
|
REDIS_PASSWORD: $REDIS_PASSWORD_PROD
|
||||||
RABBITMQ_HOST: "rabbitmq.sprinthub.ru"
|
RABBITMQ_HOST: "rabbitmq.chocomarsh.com"
|
||||||
RABBITMQ_PASSWORD: $RABBITMQ_PASSWORD_PROD
|
RABBITMQ_PASSWORD: $RABBITMQ_PASSWORD_PROD
|
||||||
VK_SERVICE_TOKEN: $VK_SERVICE_TOKEN
|
VK_SERVICE_TOKEN: $VK_SERVICE_TOKEN
|
||||||
YANDEX_SERVICE_TOKEN: $YANDEX_SERVICE_TOKEN
|
YANDEX_SERVICE_TOKEN: $YANDEX_SERVICE_TOKEN
|
||||||
TELEGRAM_TOKEN: $TELEGRAM_TOKEN
|
|
||||||
PLATFORM_SECURITY_TOKEN: $PLATFORM_SECURITY_TOKEN
|
PLATFORM_SECURITY_TOKEN: $PLATFORM_SECURITY_TOKEN
|
||||||
command: runserver 0.0.0.0:1238
|
command: runserver 0.0.0.0:1238
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -31,24 +33,23 @@ services:
|
|||||||
mode: replicated
|
mode: replicated
|
||||||
restart_policy:
|
restart_policy:
|
||||||
condition: any
|
condition: any
|
||||||
placement:
|
|
||||||
constraints:
|
|
||||||
- node.role == worker
|
|
||||||
- node.labels.zone == ru
|
|
||||||
update_config:
|
update_config:
|
||||||
parallelism: 1
|
parallelism: 1
|
||||||
order: start-first
|
order: start-first
|
||||||
|
|
||||||
fetch_stats:
|
fetch_stats:
|
||||||
image: mathwave/sprint-repo:platform
|
image: mathwave/sprint-repo:platform
|
||||||
|
networks:
|
||||||
|
- postgres
|
||||||
|
- minio
|
||||||
environment:
|
environment:
|
||||||
DB_HOST: "pg.sprinthub.ru"
|
DB_HOST: "postgres"
|
||||||
DB_PASSWORD: $DB_PASSWORD_PROD
|
DB_PASSWORD: $DB_PASSWORD_PROD
|
||||||
MINIO_HOST: "minio.sprinthub.ru"
|
MINIO_HOST: "minio"
|
||||||
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_PROD
|
MINIO_SECRET_KEY: $MINIO_SECRET_KEY_PROD
|
||||||
REDIS_HOST: "redis.sprinthub.ru"
|
REDIS_HOST: "redis.chocomarsh.com"
|
||||||
REDIS_PASSWORD: $REDIS_PASSWORD_PROD
|
REDIS_PASSWORD: $REDIS_PASSWORD_PROD
|
||||||
RABBITMQ_HOST: "rabbitmq.sprinthub.ru"
|
RABBITMQ_HOST: "rabbitmq.chocomarsh.com"
|
||||||
RABBITMQ_PASSWORD: $RABBITMQ_PASSWORD_PROD
|
RABBITMQ_PASSWORD: $RABBITMQ_PASSWORD_PROD
|
||||||
VK_SERVICE_TOKEN: $VK_SERVICE_TOKEN
|
VK_SERVICE_TOKEN: $VK_SERVICE_TOKEN
|
||||||
YANDEX_SERVICE_TOKEN: $YANDEX_SERVICE_TOKEN
|
YANDEX_SERVICE_TOKEN: $YANDEX_SERVICE_TOKEN
|
||||||
@@ -64,12 +65,14 @@ services:
|
|||||||
|
|
||||||
migrate:
|
migrate:
|
||||||
image: mathwave/sprint-repo:platform
|
image: mathwave/sprint-repo:platform
|
||||||
|
networks:
|
||||||
|
- postgres
|
||||||
|
- minio
|
||||||
environment:
|
environment:
|
||||||
DB_HOST: "pg.sprinthub.ru"
|
DB_HOST: "postgres"
|
||||||
DB_PASSWORD: $DB_PASSWORD_PROD
|
DB_PASSWORD: $DB_PASSWORD_PROD
|
||||||
MINIO_HOST: "minio.sprinthub.ru"
|
MINIO_HOST: "minio"
|
||||||
MINIO_SECRET_KEY: $MINIO _SECRET_KEY_PROD
|
MINIO_SECRET_KEY: $MINIO _SECRET_KEY_PROD
|
||||||
TELEGRAM_TOKEN: $TELEGRAM_TOKEN
|
|
||||||
command: migrate
|
command: migrate
|
||||||
deploy:
|
deploy:
|
||||||
mode: replicated
|
mode: replicated
|
||||||
@@ -82,3 +85,9 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
common-infra-nginx:
|
common-infra-nginx:
|
||||||
external: true
|
external: true
|
||||||
|
configurator:
|
||||||
|
external: true
|
||||||
|
postgres:
|
||||||
|
external: true
|
||||||
|
minio:
|
||||||
|
external: true
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
run: docker push mathwave/sprint-repo:platform
|
run: docker push mathwave/sprint-repo:platform
|
||||||
deploy-dev:
|
deploy-dev:
|
||||||
name: Deploy dev
|
name: Deploy dev
|
||||||
runs-on: [dev]
|
runs-on: [prod]
|
||||||
needs: push
|
needs: push
|
||||||
steps:
|
steps:
|
||||||
- name: login
|
- name: login
|
||||||
@@ -46,4 +46,4 @@ jobs:
|
|||||||
RABBITMQ_PASSWORD: ${{ secrets.RABBITMQ_PASSWORD_DEV }}
|
RABBITMQ_PASSWORD: ${{ secrets.RABBITMQ_PASSWORD_DEV }}
|
||||||
VK_SERVICE_TOKEN: ${{ secrets.VK_SERVICE_TOKEN }}
|
VK_SERVICE_TOKEN: ${{ secrets.VK_SERVICE_TOKEN }}
|
||||||
YANDEX_SERVICE_TOKEN: ${{ secrets.YANDEX_SERVICE_TOKEN }}
|
YANDEX_SERVICE_TOKEN: ${{ secrets.YANDEX_SERVICE_TOKEN }}
|
||||||
run: docker stack deploy --with-registry-auth -c ./.deploy/deploy-dev.yaml platform
|
run: docker stack deploy --with-registry-auth -c ./.deploy/deploy-dev.yaml platform-development
|
||||||
|
|||||||
58
BaseLib/configurator.py
Normal file
58
BaseLib/configurator.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
from requests import get, put, post, delete
|
||||||
|
from json import dumps
|
||||||
|
|
||||||
|
|
||||||
|
URL_CONFIGS = 'http://configurator/api/v1/configs'
|
||||||
|
URL_EXPERIMENTS = 'http://configurator/api/v1/experiments'
|
||||||
|
|
||||||
|
|
||||||
|
def get_configs(project, stage):
|
||||||
|
response = get(URL_CONFIGS, params={'project': project, 'stage': stage})
|
||||||
|
if response.status_code != 200:
|
||||||
|
return []
|
||||||
|
data = response.json()
|
||||||
|
for config in data:
|
||||||
|
config['value_pretty'] = dumps(config['value'], indent=4, ensure_ascii=False)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def create_config(project, stage, name):
|
||||||
|
post(URL_CONFIGS, json={'project': project, 'stage': stage, 'name': name})
|
||||||
|
|
||||||
|
|
||||||
|
def update_config(id, value):
|
||||||
|
put(URL_CONFIGS, json={'id': id, 'value': value})
|
||||||
|
|
||||||
|
|
||||||
|
def delete_config(id):
|
||||||
|
delete(URL_CONFIGS, json={'id': id})
|
||||||
|
|
||||||
|
|
||||||
|
def get_experiments(project, stage):
|
||||||
|
response = get(URL_EXPERIMENTS, params={'project': project, 'stage': stage})
|
||||||
|
if response.status_code != 200:
|
||||||
|
return []
|
||||||
|
data = response.json()
|
||||||
|
for exp in data:
|
||||||
|
if exp['condition'] == 'False':
|
||||||
|
exp['exp_type'] = 0
|
||||||
|
elif exp['condition'] == 'user.is_superuser':
|
||||||
|
exp['exp_type'] = 1
|
||||||
|
elif exp['condition'] == 'user.platform_staff':
|
||||||
|
exp['exp_type'] = 2
|
||||||
|
elif exp['condition'] == 'True':
|
||||||
|
exp['exp_type'] = 3
|
||||||
|
else:
|
||||||
|
exp['exp_type'] = 4
|
||||||
|
return data
|
||||||
|
|
||||||
|
def create_experiment(project, stage, name):
|
||||||
|
post(URL_EXPERIMENTS, json={'project': project, 'stage': stage, 'name': name})
|
||||||
|
|
||||||
|
|
||||||
|
def update_experiment(id, enabled, condition):
|
||||||
|
put(URL_EXPERIMENTS, json={'id': id, 'enabled': enabled, 'condition': condition})
|
||||||
|
|
||||||
|
|
||||||
|
def delete_experiment(id):
|
||||||
|
delete(URL_CONFIGS, json={'id': id})
|
||||||
@@ -48,7 +48,8 @@ INSTALLED_APPS = [
|
|||||||
'web.apps.WebConfig',
|
'web.apps.WebConfig',
|
||||||
'configs.apps.ConfigsConfig',
|
'configs.apps.ConfigsConfig',
|
||||||
'experiments.apps.ExperimentsConfig',
|
'experiments.apps.ExperimentsConfig',
|
||||||
'stats.apps.StatsConfig'
|
'stats.apps.StatsConfig',
|
||||||
|
'schemas.apps.SchemasConfig',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
|||||||
@@ -21,5 +21,6 @@ urlpatterns = [
|
|||||||
path('configs/', include('configs.urls')),
|
path('configs/', include('configs.urls')),
|
||||||
path('experiments/', include('experiments.urls')),
|
path('experiments/', include('experiments.urls')),
|
||||||
path('stats/', include('stats.urls')),
|
path('stats/', include('stats.urls')),
|
||||||
|
path('schemas/', include('schemas.urls')),
|
||||||
path('', include('web.urls'))
|
path('', include('web.urls'))
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from json import loads
|
|||||||
from django.http import HttpResponse, JsonResponse
|
from django.http import HttpResponse, JsonResponse
|
||||||
|
|
||||||
from BaseLib.BaseView import BaseView
|
from BaseLib.BaseView import BaseView
|
||||||
|
from BaseLib.configurator import *
|
||||||
from Platform import settings
|
from Platform import settings
|
||||||
from configs.models import Config
|
from configs.models import Config
|
||||||
|
|
||||||
@@ -20,31 +21,35 @@ class ConfigsView(BaseView):
|
|||||||
return '/configs/?stage=production'
|
return '/configs/?stage=production'
|
||||||
self.stage = self.request.GET['stage']
|
self.stage = self.request.GET['stage']
|
||||||
self.context['stage'] = self.stage
|
self.context['stage'] = self.stage
|
||||||
self.context['configs'] = Config.objects.filter(project=self.request.user.selected_project,
|
# self.context['configs'] = Config.objects.filter(project=self.request.user.selected_project,
|
||||||
stage=self.stage).order_by('name')
|
# stage=self.stage).order_by('name')
|
||||||
|
self.context['configs'] = get_configs(self.request.user.selected_project.name, self.stage)
|
||||||
|
|
||||||
def post_create_config(self):
|
def post_create_config(self):
|
||||||
Config.objects.create(name=self.request.POST['name'], project=self.request.user.selected_project, stage=self.stage)
|
create_config(self.request.user.selected_project.name, self.stage, self.request.POST['name'])
|
||||||
|
# Config.objects.create(name=self.request.POST['name'], project=self.request.user.selected_project, stage=self.stage)
|
||||||
return '/configs/?stage=' + self.stage
|
return '/configs/?stage=' + self.stage
|
||||||
|
|
||||||
def post_delete(self):
|
def post_delete(self):
|
||||||
config = Config.objects.get(id=self.request.POST['config'])
|
# config = Config.objects.get(id=self.request.POST['config'])
|
||||||
config.delete()
|
# config.delete()
|
||||||
return '/configs/?stage=' + config.stage
|
delete_config(self.request.POST['config'])
|
||||||
|
return '/configs/?stage=' + self.stage
|
||||||
|
|
||||||
def post_save(self):
|
def post_save(self):
|
||||||
data = self.request.POST['data']
|
data = self.request.POST['data']
|
||||||
config = Config.objects.get(id=self.request.POST['config'])
|
# config = Config.objects.get(id=self.request.POST['config'])
|
||||||
try:
|
try:
|
||||||
data = loads(data)
|
data = loads(data)
|
||||||
except:
|
except:
|
||||||
self.context['incorrect_config'] = config
|
self.context['incorrect_config'] = self.request.POST['config']
|
||||||
self.context['incorrect_data'] = data
|
self.context['incorrect_data'] = data
|
||||||
self.context['error'] = True
|
self.context['error'] = True
|
||||||
return
|
return
|
||||||
config.data = data
|
update_config(self.request.POST['config'], data)
|
||||||
config.save()
|
# config.data = data
|
||||||
return '/configs/?stage=' + config.stage
|
# config.save()
|
||||||
|
return '/configs/?stage=' + self.stage
|
||||||
|
|
||||||
|
|
||||||
def get_config(request):
|
def get_config(request):
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from django.http import HttpResponse, JsonResponse
|
from django.http import HttpResponse, JsonResponse
|
||||||
|
|
||||||
from BaseLib.BaseView import BaseView
|
from BaseLib.BaseView import BaseView
|
||||||
|
from BaseLib.configurator import *
|
||||||
from Platform import settings
|
from Platform import settings
|
||||||
from experiments.models import Experiment
|
from experiments.models import Experiment
|
||||||
|
|
||||||
@@ -17,31 +18,48 @@ class ExperimentsView(BaseView):
|
|||||||
self.context['stage'] = self.stage
|
self.context['stage'] = self.stage
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
self.context['experiments'] = Experiment.objects.filter(project=self.request.user.selected_project,
|
# self.context['experiments'] = Experiment.objects.filter(project=self.request.user.selected_project,
|
||||||
stage=self.stage).order_by('name')
|
# stage=self.stage).order_by('name')
|
||||||
|
self.context['experiments'] = get_experiments(self.request.user.selected_project.name, self.stage)
|
||||||
|
|
||||||
def post_create(self):
|
def post_create(self):
|
||||||
Experiment.objects.create(project=self.request.user.selected_project, stage=self.stage, name=self.request.POST['name'])
|
# Experiment.objects.create(project=self.request.user.selected_project, stage=self.stage, name=self.request.POST['name'])
|
||||||
|
create_experiment(self.request.user.selected_project.name, self.stage, self.request.POST['name'])
|
||||||
return '/experiments/?stage=' + self.stage
|
return '/experiments/?stage=' + self.stage
|
||||||
|
|
||||||
def post_delete(self):
|
def post_delete(self):
|
||||||
Experiment.objects.get(id=self.request.POST['experiment_id']).delete()
|
# Experiment.objects.get(id=self.request.POST['experiment_id']).delete()
|
||||||
|
delete_experiment(self.request.POST['experiment_id'])
|
||||||
return '/experiments/?stage=' + self.stage
|
return '/experiments/?stage=' + self.stage
|
||||||
|
|
||||||
def post_change(self):
|
def post_change(self):
|
||||||
exp = Experiment.objects.get(id=self.request.POST['experiment_id'])
|
# exp = Experiment.objects.get(id=self.request.POST['experiment_id'])
|
||||||
exp.enabled = 'enabled' in self.request.POST
|
# exp.enabled = 'enabled' in self.request.POST
|
||||||
|
# condition = self.request.POST['condition_select']
|
||||||
|
# if condition == 'Другое (только для техлидов)':
|
||||||
|
# exp.condition = self.request.POST['condition']
|
||||||
|
# elif condition == 'Никому':
|
||||||
|
# exp.condition = 'False'
|
||||||
|
# elif condition == 'Только админам':
|
||||||
|
# exp.condition = 'user.is_superuser'
|
||||||
|
# elif condition == 'Только сотрудникам':
|
||||||
|
# exp.condition = 'user.platform_staff'
|
||||||
|
# else:
|
||||||
|
# exp.condition = 'True'
|
||||||
|
# exp.save()
|
||||||
|
enabled = 'enabled' in self.request.POST
|
||||||
condition = self.request.POST['condition_select']
|
condition = self.request.POST['condition_select']
|
||||||
if condition == 'Другое (только для техлидов)':
|
if condition == 'Другое (только для техлидов)':
|
||||||
exp.condition = self.request.POST['condition']
|
condition = self.request.POST['condition']
|
||||||
elif condition == 'Никому':
|
elif condition == 'Никому':
|
||||||
exp.condition = 'False'
|
condition = 'False'
|
||||||
elif condition == 'Только админам':
|
elif condition == 'Только админам':
|
||||||
exp.condition = 'user.is_superuser'
|
condition = 'user.is_superuser'
|
||||||
elif condition == 'Только сотрудникам':
|
elif condition == 'Только сотрудникам':
|
||||||
exp.condition = 'user.platform_staff'
|
condition = 'user.platform_staff'
|
||||||
else:
|
else:
|
||||||
exp.condition = 'True'
|
condition = 'True'
|
||||||
exp.save()
|
update_experiment(self.request.POST['experiment_id'], enabled, condition)
|
||||||
return '/experiments/?stage=' + self.stage
|
return '/experiments/?stage=' + self.stage
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
37
generator.py
Normal file
37
generator.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import json
|
||||||
|
import urllib.request
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
|
||||||
|
projects = {
|
||||||
|
'queues': 'tasks.proto'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.rmtree('schemas')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.mkdir('schemas')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for project in projects:
|
||||||
|
response = urllib.request.urlopen(f'https://platform.sprinthub.ru/schemas/get?project={project}').read()
|
||||||
|
data = json.loads(response)
|
||||||
|
os.mkdir(f'schemas/{project}')
|
||||||
|
for key, value in data.items():
|
||||||
|
with open(f'schemas/{project}/{key}', 'w+') as fp:
|
||||||
|
fp.write(value)
|
||||||
|
|
||||||
|
|
||||||
|
for key, value in projects.items():
|
||||||
|
os.system(f'python -m grpc_tools.protoc --proto_path schemas --python_out=. --pyi_out=. --grpc_python_out=. ./schemas/{key}/{value}')
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.rmtree('schemas')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
0
schemas/__init__.py
Normal file
0
schemas/__init__.py
Normal file
6
schemas/admin.py
Normal file
6
schemas/admin.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
from .models import Schema
|
||||||
|
|
||||||
|
admin.site.register(Schema)
|
||||||
6
schemas/apps.py
Normal file
6
schemas/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class SchemasConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'schemas'
|
||||||
28
schemas/migrations/0001_initial.py
Normal file
28
schemas/migrations/0001_initial.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-08 11:56
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('web', '0007_customuser_telegram_id_customuser_telegram_username'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Schema',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.TextField()),
|
||||||
|
('data', models.BinaryField(blank=True, null=True)),
|
||||||
|
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='web.project')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'indexes': [models.Index(fields=['project'], name='schemas_sch_project_18fee8_idx')],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
18
schemas/migrations/0002_alter_schema_data.py
Normal file
18
schemas/migrations/0002_alter_schema_data.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-08 12:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('schemas', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='schema',
|
||||||
|
name='data',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
schemas/migrations/0003_alter_schema_data.py
Normal file
18
schemas/migrations/0003_alter_schema_data.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-08 12:15
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('schemas', '0002_alter_schema_data'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='schema',
|
||||||
|
name='data',
|
||||||
|
field=models.TextField(blank=True, default=''),
|
||||||
|
),
|
||||||
|
]
|
||||||
0
schemas/migrations/__init__.py
Normal file
0
schemas/migrations/__init__.py
Normal file
14
schemas/models.py
Normal file
14
schemas/models.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
|
|
||||||
|
|
||||||
|
class Schema(models.Model):
|
||||||
|
project = models.ForeignKey('web.Project', on_delete=models.CASCADE)
|
||||||
|
name = models.TextField()
|
||||||
|
data = models.TextField(default='', blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=['project'])
|
||||||
|
]
|
||||||
3
schemas/tests.py
Normal file
3
schemas/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
9
schemas/urls.py
Normal file
9
schemas/urls.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import *
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path(*SchemasView.as_path()),
|
||||||
|
path('get', get_schemas)
|
||||||
|
]
|
||||||
46
schemas/views.py
Normal file
46
schemas/views.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
from json import loads
|
||||||
|
|
||||||
|
from django.http import HttpResponse, JsonResponse
|
||||||
|
|
||||||
|
from BaseLib.BaseView import BaseView
|
||||||
|
from BaseLib.configurator import *
|
||||||
|
from Platform import settings
|
||||||
|
from schemas.models import Schema
|
||||||
|
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
|
|
||||||
|
|
||||||
|
class SchemasView(BaseView):
|
||||||
|
required_login = True
|
||||||
|
endpoint = ''
|
||||||
|
view_file = 'schemas.html'
|
||||||
|
|
||||||
|
def pre_handle(self):
|
||||||
|
self.context['schemas'] = Schema.objects.filter(project=self.request.user.selected_project)
|
||||||
|
|
||||||
|
def post_create_schema(self):
|
||||||
|
Schema.objects.create(project=self.request.user.selected_project, name=self.request.POST['name'])
|
||||||
|
return '/schemas'
|
||||||
|
|
||||||
|
def post_delete(self):
|
||||||
|
Schema.objects.get(id=self.request.POST['schema']).delete()
|
||||||
|
return '/schemas'
|
||||||
|
|
||||||
|
|
||||||
|
def post_save(self):
|
||||||
|
schema = Schema.objects.get(id=self.request.POST['schema'])
|
||||||
|
schema.data = self.request.POST['data']
|
||||||
|
schema.save()
|
||||||
|
return '/schemas'
|
||||||
|
|
||||||
|
|
||||||
|
def get_schemas(request):
|
||||||
|
project = request.GET.get('project')
|
||||||
|
if project is None:
|
||||||
|
return HttpResponse('', status=400)
|
||||||
|
data = {
|
||||||
|
schema.name: schema.data
|
||||||
|
for schema in Schema.objects.filter(project__name=project)
|
||||||
|
}
|
||||||
|
return JsonResponse(data, safe=False)
|
||||||
@@ -24,6 +24,8 @@ class Command(BaseCommand):
|
|||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
continue
|
continue
|
||||||
Snapshot.objects.create(project=project, data=response.json())
|
Snapshot.objects.create(project=project, data=response.json())
|
||||||
|
if not project.stats_cron:
|
||||||
|
continue
|
||||||
cron = croniter.croniter(project.stats_cron, timezone.now())
|
cron = croniter.croniter(project.stats_cron, timezone.now())
|
||||||
next_date = cron.get_next(datetime.datetime)
|
next_date = cron.get_next(datetime.datetime)
|
||||||
project.next_stats_fetch_time = next_date
|
project.next_stats_fetch_time = next_date
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% if error %}
|
{% if error %}
|
||||||
<div class="alert alert-danger" role="alert">
|
<div class="alert alert-danger" role="alert">
|
||||||
Конфиг {{ incorrect_config.name }} не имеет вид JSON!
|
Конфиг не имеет вид JSON!
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<table class="table">
|
<table class="table">
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<textarea style="width: 100%; height: 800px;{% if config.id == incorrect_config.id %}border: 1px solid #f00;{% endif %}" name="data">{% if config.id == incorrect_config.id %}{{ incorrect_data }}{% else %}{{ config.data_pretty }}{% endif %}</textarea>
|
<textarea style="width: 100%; height: 800px;{% if config.id == incorrect_config %}border: 1px solid #f00;{% endif %}" name="data">{% if config.id == incorrect_config %}{{ incorrect_data }}{% else %}{{ config.value_pretty }}{% endif %}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="submit" name="action" value="save" class="btn btn-secondary">Сохранить</button>
|
<button type="submit" name="action" value="save" class="btn btn-secondary">Сохранить</button>
|
||||||
|
|||||||
@@ -98,6 +98,14 @@
|
|||||||
<span class="sidebar-text">Статистика</span>
|
<span class="sidebar-text">Статистика</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="/schemas" class="nav-link">
|
||||||
|
<span class="sidebar-icon">
|
||||||
|
<i class="fa fa-file-code-o"></i>
|
||||||
|
</span>
|
||||||
|
<span class="sidebar-text">Схемы</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<button class="btn btn-secondary d-flex align-items-center justify-content-center btn-upgrade-pro">
|
<button class="btn btn-secondary d-flex align-items-center justify-content-center btn-upgrade-pro">
|
||||||
{{ user.selected_project.name }}
|
{{ user.selected_project.name }}
|
||||||
|
|||||||
61
templates/schemas.html
Normal file
61
templates/schemas.html
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{% extends 'layouts/base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Схемы <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#create_config">+</button></h1>
|
||||||
|
<div class="modal fade" id="create_config" tabindex="-1" aria-labelledby="modal-default" style="display: none;" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<form method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 class="h6 modal-title">Создать схему</h2>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<input type="text" name="name" placeholder="Имя файла" style="width: 100%;" />
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="submit" name="action" value="create_schema" class="btn btn-secondary">Создать</button>
|
||||||
|
<button type="button" class="btn btn-link text-gray-600 ms-auto" data-bs-dismiss="modal">Закрыть</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<th>Название</th>
|
||||||
|
<th>Действие</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for schema in schemas %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ schema.name }}</td>
|
||||||
|
<td><button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#edit_{{ schema.id }}">Редактировать</button></td>
|
||||||
|
<div class="modal fade" id="edit_{{ schema.id }}" tabindex="-1" aria-labelledby="modal-default" style="display: none;" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<form method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="schema" value="{{ schema.id }}" />
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 class="h6 modal-title">Редактировать схему {{ config.name }}</h2>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<textarea style="width: 100%; height: 800px;" name="data">{{ schema.data }}</textarea>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="submit" name="action" value="save" class="btn btn-secondary">Сохранить</button>
|
||||||
|
<button type="submit" name="action" value="delete" class="btn btn-danger" onclick="return confirm('Подтверди удаление. Это действие необратимо.');">Удалить</button>
|
||||||
|
<button type="button" class="btn btn-link text-gray-600 ms-auto" data-bs-dismiss="modal">Закрыть</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2024-12-08 12:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('web', '0007_customuser_telegram_id_customuser_telegram_username'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='project',
|
||||||
|
name='next_stats_fetch_time',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='project',
|
||||||
|
name='stats_cron',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='project',
|
||||||
|
name='stats_link',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -3,10 +3,10 @@ from django.db import models
|
|||||||
|
|
||||||
class Project(models.Model):
|
class Project(models.Model):
|
||||||
name = models.TextField()
|
name = models.TextField()
|
||||||
stats_link = models.TextField(null=True)
|
stats_link = models.TextField(null=True, blank=True)
|
||||||
stats_cron = models.TextField(null=True)
|
stats_cron = models.TextField(null=True, blank=True)
|
||||||
stats_enabled = models.BooleanField(default=False)
|
stats_enabled = models.BooleanField(default=False)
|
||||||
next_stats_fetch_time = models.DateTimeField(null=True)
|
next_stats_fetch_time = models.DateTimeField(null=True, blank=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
indexes = [
|
indexes = [
|
||||||
|
|||||||
@@ -15,4 +15,5 @@ urlpatterns = [
|
|||||||
path(*YandexAuthView.as_path()),
|
path(*YandexAuthView.as_path()),
|
||||||
path('is_staff', is_staff),
|
path('is_staff', is_staff),
|
||||||
path('fetch', fetch),
|
path('fetch', fetch),
|
||||||
|
path('generator', generator),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ from .vk_auth import VKAuthView
|
|||||||
from .yandex_auth import YandexAuthView
|
from .yandex_auth import YandexAuthView
|
||||||
from .is_staff import is_staff
|
from .is_staff import is_staff
|
||||||
from .fetch import fetch
|
from .fetch import fetch
|
||||||
|
from .generator import generator
|
||||||
|
|||||||
5
web/views/generator.py
Normal file
5
web/views/generator.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from django.http import HttpResponse
|
||||||
|
|
||||||
|
|
||||||
|
def generator(request):
|
||||||
|
return HttpResponse(open('generator.py', 'rb').read())
|
||||||
Reference in New Issue
Block a user