From 85c0804ecd0f388934a5aae7f5389c27ee48694e Mon Sep 17 00:00:00 2001 From: Mauricio Baeza Date: Thu, 21 Sep 2017 23:24:18 -0500 Subject: [PATCH] =?UTF-8?q?Agregar=20configuraci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/app/controllers/main.py | 17 ++- source/app/main.py | 32 +++--- source/app/middleware.py | 7 +- source/app/models/db.py | 6 +- source/app/models/main.py | 164 +++++++++++++++++---------- source/app/settings.py | 4 +- source/static/js/controller/admin.js | 21 ++++ source/static/js/controller/main.js | 2 +- source/static/js/ui/admin.js | 72 ++++++++++++ source/static/js/ui/login.js | 14 +-- source/static/js/ui/main.js | 1 - source/templates/admin.html | 29 +++++ source/templates/base.html | 1 - source/templates/login.html | 10 +- 14 files changed, 277 insertions(+), 103 deletions(-) create mode 100644 source/static/js/controller/admin.js create mode 100644 source/static/js/ui/admin.js create mode 100644 source/templates/admin.html diff --git a/source/app/controllers/main.py b/source/app/controllers/main.py index 003ea1c..626c330 100644 --- a/source/app/controllers/main.py +++ b/source/app/controllers/main.py @@ -1,8 +1,6 @@ #!/usr/bin/env python3 import falcon - -from . import util from middleware import get_template @@ -19,11 +17,11 @@ class AppLogin(object): def on_post(self, req, resp): session = req.env['beaker.session'] values = req.params - result = self._db.authenticate(values['user'], values['pass']) - resp.body = util.dumps(result) + result = self._db.authenticate(values) if result['login']: session.save() session['user'] = result['user'] + req.context['result'] = result resp.status = falcon.HTTP_200 @@ -39,6 +37,17 @@ class AppLogout(object): raise falcon.HTTPTemporaryRedirect('/') +class AppAdmin(object): + template = 'admin.html' + + def __init__(self, db): + self._db = db + + @falcon.after(get_template) + def on_get(self, req, resp): + resp.status = falcon.HTTP_200 + + class AppMain(object): template = 'main.html' diff --git a/source/app/main.py b/source/app/main.py index bc8947e..f526622 100644 --- a/source/app/main.py +++ b/source/app/main.py @@ -5,40 +5,36 @@ from beaker.middleware import SessionMiddleware from middleware import AuthMiddleware, JSONTranslator, static, handle_404 from models.db import StorageEngine -from controllers.main import AppLogin, AppLogout, AppMain, AppPartners -from controllers.helper import AppPostalCode -from settings import DEBUG, WITH_LOGIN +from controllers.main import ( + AppLogin, AppLogout, AppAdmin, AppMain, +) +from settings import DEBUG db = StorageEngine() -pc = AppPostalCode() -login = AppLogin(db) -logout = AppLogout(db) -main = AppMain(db) -partners = AppPartners(db) +#~ partners = AppPartners(db) api = falcon.API(middleware=[AuthMiddleware(), JSONTranslator()]) api.req_options.auto_parse_form_urlencoded = True api.add_sink(handle_404, '') -if WITH_LOGIN: - api.add_route('/', login) -api.add_route('/logout', logout) -api.add_route('/main', main) -api.add_route('/partners', partners) -api.add_route('/pc', pc) + +api.add_route('/', AppLogin(db)) +api.add_route('/logout', AppLogout(db)) +api.add_route('/admin', AppAdmin(db)) +api.add_route('/main', AppMain(db)) + +#~ api.add_route('/partners', partners) if DEBUG: api.add_sink(static, '/static') -session_opts = { +session_options = { 'session.type': 'file', 'session.cookie_expires': True, 'session.data_dir': '/tmp/cache/data', 'session.lock_dir': '/tmp/cache/lock', - #~ 'session.httponly': True, - #~ 'session.secure': True, } -app = SessionMiddleware(api, session_opts) +app = SessionMiddleware(api, session_options) diff --git a/source/app/middleware.py b/source/app/middleware.py index 472f5dd..2ed77a8 100644 --- a/source/app/middleware.py +++ b/source/app/middleware.py @@ -31,12 +31,9 @@ def static(req, res): class AuthMiddleware(object): - #~ def process_request(self, req, resp): - def process_resource(self, req, resp, resource, params): - paths = ('/main', '/partners', '/cp') id_session = req.cookies.get('beaker.session.id', '') - if req.path in paths and not id_session: + if not id_session and req.path != '/': raise falcon.HTTPTemporaryRedirect('/') @@ -46,5 +43,3 @@ class JSONTranslator(object): if 'result' not in req.context: return resp.body = util.dumps(req.context['result']) - - diff --git a/source/app/models/db.py b/source/app/models/db.py index 658d543..ca7e420 100644 --- a/source/app/models/db.py +++ b/source/app/models/db.py @@ -6,10 +6,10 @@ from . import main class StorageEngine(object): def __init__(self): - main.connect() + main.conectar() - def authenticate(self, username, password): - return main.authenticate(username, password) + def authenticate(self, args): + return main.authenticate(args['usuario'], args['contra']) def get_partners(self, values): return main.get_partners(values) diff --git a/source/app/models/main.py b/source/app/models/main.py index 1a3fdeb..49ba136 100644 --- a/source/app/models/main.py +++ b/source/app/models/main.py @@ -3,12 +3,15 @@ import sqlite3 import click from peewee import * +from playhouse.fields import PasswordField, ManyToManyField + if __name__ == '__main__': import os, sys parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, parent_dir) + from controllers import util from conf import DATABASE, __version__ from settings import log, PATH_CP @@ -20,50 +23,95 @@ class BaseModel(Model): database = database -def connect(): +def conectar(): global database database.connect() log.info('Conectado a la BD...') return -class Configuration(BaseModel): - key = FixedCharField(max_length=50) - value = FixedCharField(max_length=100) +class Configuracion(BaseModel): + clave = TextField() + valor = TextField() class Meta: - order_by = ('key',) + order_by = ('clave',) indexes = ( - (('key', 'value'), True), + (('clave', 'valor'), True), ) class Tags(BaseModel): - tag = FixedCharField(max_length=25, index=True) + tag = TextField(index=True, unique=True) class Meta: order_by = ('tag',) -class Users(BaseModel): - username = CharField(max_length=50, unique=True) - first_name = CharField(max_length=50, default='') - last_name = CharField(max_length=50, default='') - email = CharField(max_length=200, default='') - password = CharField(max_length=100) - is_superuser = BooleanField(default=False) - is_admin = BooleanField(default=False) - is_staff = BooleanField(default=False) - is_active = BooleanField(default=True) - date_joined = DateTimeField(default=util.now) - last_login = DateTimeField(null=True) +class Usuarios(BaseModel): + usuario = TextField(unique=True) + nombre = TextField(default='') + apellidos = TextField(default='') + correo = TextField(default='') + contraseña = PasswordField() + es_superusuario = BooleanField(default=False) + es_admin = BooleanField(default=False) + es_activo = BooleanField(default=True) + fecha_ingreso = DateTimeField(default=util.now) + ultimo_ingreso = DateTimeField(null=True) def __str__(self): t = '{} {} ({})' - return t.format(self.first_name, self.last_name, self.username) + return t.format(self.nombre, self.apellidos, self.usuario) class Meta: - order_by = ('username',) + order_by = ('nombre', 'apellidos') + + +class SATRegimenes(BaseModel): + key = TextField(index=True, unique=True) + name = TextField(index=True) + activo = BooleanField(default=False) + default = BooleanField(default=False) + fisica = BooleanField(default=False) + moral = BooleanField(default=False) + + class Meta: + order_by = ('name',) + indexes = ( + (('key', 'name'), True), + ) + + +class Emisor(BaseModel): + rfc = TextField(index=True) + nombre = TextField() + codigo_postal = TextField(default='') + moral = BooleanField(default=False) + regimenes = ManyToManyField(SATRegimenes, related_name='emisores') + + def __str__(self): + t = '{} ({})' + return t.format(self.nombre, self.rfc) + + class Meta: + order_by = ('nombre',) + + +class Certificado(BaseModel): + key = BlobField() + key_enc = TextField(default='') + cer = BlobField() + cer_pem = TextField(default='') + cer_txt = TextField(default='') + p12 = BlobField() + serie = TextField(default='') + rfc = TextField(default='') + desde = DateTimeField() + hasta = DateTimeField() + + def __str__(self): + return self.serie class Clients(BaseModel): @@ -114,22 +162,23 @@ class ClientsTags(BaseModel): ) -def authenticate(username, password): - data = {'login': False, 'msg': 'No Autorizado', 'user': ''} +def authenticate(usuario, contraseña): + respuesta = {'login': False, 'msg': 'No Autorizado', 'user': ''} try: - obj = Users.get(Users.username==username, Users.is_active==True) - except Users.DoesNotExist: - return data + obj = Usuarios.get(usuario=usuario, es_activo=True) + except Usuarios.DoesNotExist: + return respuesta - if not util.validate_password(obj.password, password): - return data + if not obj.contraseña.check_password(contraseña): + return respuesta - obj.last_login = util.now() + obj.ultimo_ingreso = util.now() obj.save() - data['msg'] = '' - data['login'] = True - data['user'] = str(obj) - return data + respuesta['msg'] = '' + respuesta['login'] = True + respuesta['user'] = str(obj) + respuesta['super'] = obj.es_superusuario + return respuesta def get_partners(values): @@ -199,12 +248,12 @@ def _init_values(): return -def create_tables(): - connect() - tables = [Configuration, Tags, Users, Clients, ClientsTags] - database.create_tables(tables, True) +def _crear_tablas(): + conectar() + tablas = [Configuracion, Tags, Usuarios, + Certificado, Emisor, Emisor.regimenes.get_through_model()] + database.create_tables(tablas, True) log.info('Tablas creadas correctamente...') - _init_values() return @@ -214,19 +263,20 @@ def migrate_tables(): return -def create_superuser(): - connect() - username = input('Introduce el nuevo nombre para el superusuario: ').strip() - if not username: +def _agregar_superusuario(): + conectar() + usuario = input('Introduce el nuevo nombre para el superusuario: ').strip() + if not usuario: msg = 'El nombre de usuario es requerido' log.erro(msg) return - ok, password = util.get_pass() + ok, contraseña = util.get_pass() if not ok: - log.error(password) + log.error(contraseña) return try: - obj = Users.create(username=username, password=password, is_superuser=True) + obj = Usuarios.create( + usuario=usuario, contraseña=contraseña, es_superusuario=True) except IntegrityError: msg = 'El usuario ya existe' log.error(msg) @@ -236,27 +286,27 @@ def create_superuser(): return -def change_password(): - connect() - username = input('Introduce el nombre de usuario: ').strip() - if not username: +def _cambiar_contraseña(): + conectar() + usuario = input('Introduce el nombre de usuario: ').strip() + if not usuario: msg = 'El nombre de usuario es requerido' log.error(msg) return try: - obj = Users.get(username=username) - except Users.DoesNotExist: + obj = Usuarios.get(usuario=usuario) + except Usuarios.DoesNotExist: msg = 'El usuario no existe' log.error(msg) return - ok, password = util.get_pass() + ok, contraseña = util.get_pass() if not ok: - log.error(password) + log.error(contraseña) return - obj.password = password + obj.contraseña = contraseña obj.save() log.info('Contraseña cambiada correctamente...') @@ -282,7 +332,7 @@ def main(iniciar_bd, migrar_bd, nuevo_superusuario, cambiar_contraseña): opt = locals() if opt['iniciar_bd']: - create_tables() + _crear_tablas() sys.exit(0) if opt['migrar_bd']: @@ -290,11 +340,11 @@ def main(iniciar_bd, migrar_bd, nuevo_superusuario, cambiar_contraseña): sys.exit(0) if opt['nuevo_superusuario']: - create_superuser() + _agregar_superusuario() sys.exit(0) if opt['cambiar_contraseña']: - change_password() + _cambiar_contraseña() return diff --git a/source/app/settings.py b/source/app/settings.py index 639709f..7d06624 100644 --- a/source/app/settings.py +++ b/source/app/settings.py @@ -5,7 +5,7 @@ import os import sys from mako.lookup import TemplateLookup from logbook import Logger, StreamHandler, RotatingFileHandler -logbook.set_datetime_format("local") +logbook.set_datetime_format('local') from conf import DEBUG @@ -15,7 +15,7 @@ PATH_STATIC = os.path.abspath(os.path.join(BASE_DIR, '..')) PATH_TEMPLATES = os.path.abspath(os.path.join(BASE_DIR, '..', 'templates')) EMAIL_SUPPORT = ('soporte@empresalibre.net',) -WITH_LOGIN = True +#~ WITH_LOGIN = True DB_CP = 'cp.db' PATH_CP = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', DB_CP)) diff --git a/source/static/js/controller/admin.js b/source/static/js/controller/admin.js new file mode 100644 index 0000000..def8b71 --- /dev/null +++ b/source/static/js/controller/admin.js @@ -0,0 +1,21 @@ + + +var controllers = { + init: function(){ + //~ Admin + $$('menu_user').attachEvent('onMenuItemClick', menu_user_click) + } +} + + +function menu_user_click(id, e, node){ + if (id == 1){ + window.location = '/logout' + return + } +} + + +function cmd_home_click(){ + window.location = '/main' +} diff --git a/source/static/js/controller/main.js b/source/static/js/controller/main.js index 21182d4..a2868e7 100644 --- a/source/static/js/controller/main.js +++ b/source/static/js/controller/main.js @@ -29,7 +29,7 @@ var controllers = { $$("cmd_save_invoice").attachEvent("onItemClick", cmd_save_invoice_click); $$("cmd_cancel_invoice").attachEvent("onItemClick", cmd_cancel_invoice_click); - get_partners() + //~ get_partners() } }; diff --git a/source/static/js/ui/admin.js b/source/static/js/ui/admin.js new file mode 100644 index 0000000..71f3a8c --- /dev/null +++ b/source/static/js/ui/admin.js @@ -0,0 +1,72 @@ + +var menu_data = [ + {id: 'app_home', icon: 'dashboard', value: 'Inicio'}, + {id: 'app_emisor', icon: 'user-circle', value: 'Emisor'}, + {id: 'app_cert', icon: 'key', value: 'Certificado'}, +] + + +var sidebar = { + view: 'sidebar', + data: menu_data, + ready: function(){ + this.select('app_home'); + this.open(this.getParentId('app_home')); + }, + on:{ + onAfterSelect: function(id){ + $$('multi').setValue(id) + } + } +}; + + +var multi_main = { + id: 'multi', + animate: true, + cells:[ + { + id: 'app_home', + view: 'template', + template: 'HOME' + } + //~ app_emisor, + ] +}; + + +var menu_user = { + view: 'menu', + id: 'menu_user', + width: 150, + autowidth: true, + data: [ + {id: '0', value: 'User...', submenu:[{id:1, value:'Cerrar Sesión'}]}, + ], + type: { + subsign: true, + }, +}; + +var ui_admin = { + rows: [ + {view: 'toolbar', padding: 3, elements: [ + {view: 'button', type: 'icon', icon: 'bars', + width: 37, align: 'left', css: 'app_button', click: function(){ + $$('$sidebar1').toggle() + } + }, + {view: 'label', label: 'Empresa Libre - Configuración'}, + {}, + {view: 'button', type: 'icon', width: 40, css: 'app_button', + icon: 'home', click: 'cmd_home_click'}, + menu_user + ]}, + { + cols:[ + sidebar, + multi_main, + ] + } + ] +}; diff --git a/source/static/js/ui/login.js b/source/static/js/ui/login.js index c24ed0a..015e569 100644 --- a/source/static/js/ui/login.js +++ b/source/static/js/ui/login.js @@ -1,12 +1,12 @@ - var msg_user = 'El usuario es requerido' var msg_pass = 'La contraseña es requerida' var form_controls = [ - {view: 'text', label: 'Usuario', name: 'user', labelPosition: 'top', - required: true, invalidMessage: msg_user}, - {view: 'text', label: 'Contraseña', name: 'pass', type: 'password', - required: true, labelPosition: 'top', invalidMessage: msg_pass}, + {view: 'text', label: 'Usuario', id: 'txt_usuario', name: 'usuario', + labelPosition: 'top', required: true, invalidMessage: msg_user}, + {view: 'text', label: 'Contraseña', id: 'txt_contra', name: 'contra', + type: 'password', required: true, labelPosition: 'top', + invalidMessage: msg_pass}, {margin: 10, cols:[{}, {view: 'button', value: 'Iniciar Sesión', click: 'validate_login', hotkey: 'enter'}, {}]} ] @@ -28,8 +28,8 @@ var ui_login = { width: 400, elements: form_controls, rules:{ - user:function(value){ return value.trim() != '';}, - pass:function(value){ return value.trim() != '';}, + usuario:function(value){ return value.trim() != '';}, + contra:function(value){ return value.trim() != '';}, } }, ]}, {}, ] diff --git a/source/static/js/ui/main.js b/source/static/js/ui/main.js index b2e0537..f594323 100644 --- a/source/static/js/ui/main.js +++ b/source/static/js/ui/main.js @@ -1,5 +1,4 @@ - var menu_data = [ {id: 'app_home', icon: 'dashboard', value: 'Inicio'}, {id: 'app_partners', icon: 'users', value: 'Clientes y Proveedores'}, diff --git a/source/templates/admin.html b/source/templates/admin.html new file mode 100644 index 0000000..cd660d3 --- /dev/null +++ b/source/templates/admin.html @@ -0,0 +1,29 @@ +<%inherit file="base.html"/> + +<%block name="media"> + + + + + + + + + +<%block name="content"> + + + + + + diff --git a/source/templates/base.html b/source/templates/base.html index 4441f70..7038ef4 100644 --- a/source/templates/base.html +++ b/source/templates/base.html @@ -9,7 +9,6 @@ - <%block name="media"/> diff --git a/source/templates/login.html b/source/templates/login.html index 97ad63b..e1e2fcd 100644 --- a/source/templates/login.html +++ b/source/templates/login.html @@ -18,14 +18,18 @@ function validate_login(){ return } - var values = form.getValues(); + var values = form.getValues() webix.ajax().post("/", values, function(text, data, xhr) { var values = data.json(); if (values.login) { - window.location = "/main"; + if (values.super) { + window.location = "/admin" + }else{ + window.location = "/main" + } } else { - webix.message({ type:"error", text: values.msg }); + webix.message({ type:"error", text: values.msg }) } }); };