From 7c178982f586a5468c499b634a2d5a354b5cff62 Mon Sep 17 00:00:00 2001 From: topilski Date: Mon, 10 Jun 2019 04:36:05 -0400 Subject: [PATCH] Send subscribers to service --- app/service/service_client.py | 2 + app/service/service_entry.py | 13 +++ app/service/view.py | 21 ++++- app/subscriber/forms.py | 26 ++++++ app/subscriber/subscriber_entry.py | 98 ++++++++++++++++++++++ app/templates/service/subscriber/add.html | 4 + app/templates/service/subscriber/base.html | 45 ++++++++++ app/templates/service/subscriber/edit.html | 4 + app/templates/service/user/edit.html | 2 +- app/templates/user/settings.html | 37 +++++++- 10 files changed, 247 insertions(+), 5 deletions(-) create mode 100644 app/subscriber/forms.py create mode 100644 app/subscriber/subscriber_entry.py create mode 100644 app/templates/service/subscriber/add.html create mode 100644 app/templates/service/subscriber/base.html create mode 100644 app/templates/service/subscriber/edit.html diff --git a/app/service/service_client.py b/app/service/service_client.py index 61ffcbf..9d0f5ef 100644 --- a/app/service/service_client.py +++ b/app/service/service_client.py @@ -78,6 +78,8 @@ class ServiceClient(IClientHandler): streams.append(stream.config()) subscribers = [] + for subscriber in self._service_settings.subscribers: + subscribers.append(subscriber.to_service()) return self._client.sync_service(self._gen_request_id(), streams, subscribers) def get_http_host(self) -> str: diff --git a/app/service/service_entry.py b/app/service/service_entry.py index bfceb2a..1ed339d 100644 --- a/app/service/service_entry.py +++ b/app/service/service_entry.py @@ -20,6 +20,7 @@ class ServiceSettings(Document, ServerSettings): streams = ListField(EmbeddedDocumentField(Stream), default=[]) users = ListField(EmbeddedDocumentField(UserPair), default=[]) + subscribers = ListField(ReferenceField('Subscriber'), default=[]) def generate_playlist(self) -> str: result = '#EXTM3U\n' @@ -47,4 +48,16 @@ class ServiceSettings(Document, ServerSettings): for user in self.users: if user.id == uid: self.users.remove(user) + break + self.save() + + def add_subscriber(self, sid): + self.subscribers.append(sid) + self.save() + + def remove_subscriber(self, sid): + for subscriber in self.subscribers: + if subscriber == sid: + self.subscribers.remove(subscriber) + break self.save() diff --git a/app/service/view.py b/app/service/view.py index f0b9d27..c8e97d3 100644 --- a/app/service/view.py +++ b/app/service/view.py @@ -6,9 +6,11 @@ from flask_login import login_required, current_user from app import get_runtime_folder from app.service.forms import ServiceSettingsForm, ActivateForm, UploadM3uForm, UserServerForm +from app.subscriber.forms import SubscriberForm from app.service.service_entry import ServiceSettings, UserPair from app.utils.m3u_parser import M3uParser from app.home.user_loging_manager import User +from app.subscriber.subscriber_entry import Subscriber import app.constants as constants @@ -157,11 +159,26 @@ class ServiceView(FlaskView): return render_template('service/user/add.html', form=form) + @login_required + @route('/subscriber/add/', methods=['GET', 'POST']) + def subscriber_add(self, sid): + form = SubscriberForm(obj=Subscriber()) + if request.method == 'POST' and form.validate_on_submit(): + server = ServiceSettings.objects(id=sid).first() + if server: + new_entry = form.make_entry() + new_entry.save() + + server.add_subscriber(new_entry.id) + new_entry.add_server(server) + return jsonify(status='ok'), 200 + + return render_template('service/subscriber/add.html', form=form) + @login_required @route('/add', methods=['GET', 'POST']) def add(self): - model = ServiceSettings() - form = ServiceSettingsForm(obj=model) + form = ServiceSettingsForm(obj=ServiceSettings()) if request.method == 'POST' and form.validate_on_submit(): new_entry = form.make_entry() admin = UserPair(current_user.id, constants.Roles.ADMIN) diff --git a/app/subscriber/forms.py b/app/subscriber/forms.py new file mode 100644 index 0000000..3c7ee3d --- /dev/null +++ b/app/subscriber/forms.py @@ -0,0 +1,26 @@ +from flask_wtf import FlaskForm +from flask_babel import lazy_gettext + +from wtforms.fields import StringField, PasswordField, SubmitField, SelectField +from wtforms.validators import InputRequired, Length, Email + +from app.subscriber.subscriber_entry import Subscriber + + +class SubscriberForm(FlaskForm): + AVAILABLE_COUNTRIES = [('UK', 'United kingdom'), ('RU', 'Russian'), ('BY', 'Belarus')] + email = StringField(lazy_gettext(u'Email:'), + validators=[InputRequired(), Email(message=lazy_gettext(u'Invalid email')), Length(max=30)]) + password = PasswordField(lazy_gettext(u'Password:'), validators=[InputRequired(), Length(min=6, max=80)]) + country = SelectField(lazy_gettext(u'Locale:'), coerce=str, validators=[InputRequired()], + choices=AVAILABLE_COUNTRIES) + apply = SubmitField(lazy_gettext(u'Apply')) + + def make_entry(self): + return self.update_entry(Subscriber()) + + def update_entry(self, subscriber: Subscriber): + subscriber.email = self.email.data + subscriber.password = Subscriber.make_md5_hash_from_password(self.password.data) + subscriber.country = self.country.data + return subscriber diff --git a/app/subscriber/subscriber_entry.py b/app/subscriber/subscriber_entry.py new file mode 100644 index 0000000..959eec5 --- /dev/null +++ b/app/subscriber/subscriber_entry.py @@ -0,0 +1,98 @@ +from datetime import datetime +from hashlib import md5 +from bson.objectid import ObjectId +from enum import IntEnum + +from mongoengine import Document, EmbeddedDocument, StringField, DateTimeField, IntField, ListField, ReferenceField, \ + PULL, ObjectIdField + +from app.service.service_entry import ServiceSettings +from app.stream.stream_entry import Stream + + +class Device(EmbeddedDocument): + DEFAULT_DEVICE_NAME = 'Device' + MIN_DEVICE_NAME_LENGTH = 3 + MAX_DEVICE_NAME_LENGTH = 32 + + meta = {'allow_inheritance': False, 'auto_create_index': True} + id = ObjectIdField(required=True, default=ObjectId, unique=True, primary_key=True) + created_date = DateTimeField(default=datetime.now) + name = StringField(default=DEFAULT_DEVICE_NAME, min_length=MIN_DEVICE_NAME_LENGTH, + max_length=MAX_DEVICE_NAME_LENGTH, + required=True) + + +class Subscriber(Document): + ID_FIELD = "id" + EMAIL_FIELD = "login" + PASSWORD_FIELD = "password" + STATUS_FIELD = "status" + DEVICES_FIELD = "devices" + STREAMS_FIELD = "streams" + + class Status(IntEnum): + NO_ACTIVE = 0 + ACTIVE = 1 + BANNED = 2 + + class Type(IntEnum): + USER = 0, + SUPPORT = 1 + + SUBSCRIBER_HASH_LENGHT = 32 + + meta = {'collection': 'subscribers', 'auto_create_index': False} + + email = StringField(max_length=30, required=True) + password = StringField(min_length=SUBSCRIBER_HASH_LENGHT, max_length=SUBSCRIBER_HASH_LENGHT, required=True) + created_date = DateTimeField(default=datetime.now) + status = IntField(default=Status.ACTIVE) + type = IntField(default=Type.USER) + country = StringField(min_length=2, max_length=3, required=True) + servers = ListField(ReferenceField(ServiceSettings, reverse_delete_rule=PULL), default=[]) + devices = ListField(Device, default=[]) + streams = ListField(ReferenceField(Stream, reverse_delete_rule=PULL), default=[]) + + def add_server(self, server: ServiceSettings): + self.servers.append(server) + self.save() + + def add_stream(self, sid): + self.streams.append(sid) + self.save() + + def remove_stream(self, sid): + for stream in self.streams: + if stream == sid: + self.streams.remove(stream) + break + self.save() + + def to_service(self) -> dict: + devices = [] + for dev in self.devices: + devices.append(str(dev.id)) + + streams = [] + for stream in self.streams: + streams.append(str(stream)) + + conf = { + Subscriber.ID_FIELD: str(self.id), Subscriber.EMAIL_FIELD: self.email, + Subscriber.PASSWORD_FIELD: self.password, Subscriber.STATUS_FIELD: self.status, + Subscriber.DEVICES_FIELD: devices, Subscriber.STREAMS_FIELD: streams} + return conf + + @staticmethod + def make_md5_hash_from_password(password: str) -> str: + m = md5() + m.update(password.encode()) + return m.hexdigest() + + @classmethod + def md5_user(cls, email: str, password: str, country: str): + return cls(email=email, password=Subscriber.make_md5_hash_from_password(password), country=country) + + +Subscriber.register_delete_rule(ServiceSettings, "subscribers", PULL) diff --git a/app/templates/service/subscriber/add.html b/app/templates/service/subscriber/add.html new file mode 100644 index 0000000..7082fe3 --- /dev/null +++ b/app/templates/service/subscriber/add.html @@ -0,0 +1,4 @@ +{% extends 'service/subscriber/base.html' %} +{% block title %} +Add subscriber to server +{% endblock %} \ No newline at end of file diff --git a/app/templates/service/subscriber/base.html b/app/templates/service/subscriber/base.html new file mode 100644 index 0000000..2300f37 --- /dev/null +++ b/app/templates/service/subscriber/base.html @@ -0,0 +1,45 @@ +{% from 'bootstrap/wtf.html' import form_field %} +{% macro render_bootstrap_field(field) %} +
+ +
+ {{ field(class='form-control')|safe }} +
+
+{% endmacro %} + +{% macro render_bootstrap_form(form) %} +
+ +
+ {{ form() }} +
+
+{% endmacro %} + +
+ + + +
diff --git a/app/templates/service/subscriber/edit.html b/app/templates/service/subscriber/edit.html new file mode 100644 index 0000000..4b8aba8 --- /dev/null +++ b/app/templates/service/subscriber/edit.html @@ -0,0 +1,4 @@ +{% extends 'service/subscriber/base.html' %} +{% block title %} +Edit subscriber +{% endblock %} \ No newline at end of file diff --git a/app/templates/service/user/edit.html b/app/templates/service/user/edit.html index f81b63c..97c665a 100644 --- a/app/templates/service/user/edit.html +++ b/app/templates/service/user/edit.html @@ -1,4 +1,4 @@ -{% extends 'service/base.html' %} +{% extends 'service/user/base.html' %} {% block title %} Edit service {% endblock %} \ No newline at end of file diff --git a/app/templates/user/settings.html b/app/templates/user/settings.html index b7628f6..df91fbe 100644 --- a/app/templates/user/settings.html +++ b/app/templates/user/settings.html @@ -74,6 +74,10 @@ Settings | {{ config['PUBLIC_CONFIG'].site.title }} onclick="add_user_to_server('{{ server.id }}')"> {% trans %}Add user{% endtrans %} +