Agregar configuración

This commit is contained in:
Mauricio Baeza 2017-09-21 23:24:18 -05:00
parent 3a4cede680
commit 85c0804ecd
14 changed files with 277 additions and 103 deletions

View File

@ -1,8 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import falcon import falcon
from . import util
from middleware import get_template from middleware import get_template
@ -19,11 +17,11 @@ class AppLogin(object):
def on_post(self, req, resp): def on_post(self, req, resp):
session = req.env['beaker.session'] session = req.env['beaker.session']
values = req.params values = req.params
result = self._db.authenticate(values['user'], values['pass']) result = self._db.authenticate(values)
resp.body = util.dumps(result)
if result['login']: if result['login']:
session.save() session.save()
session['user'] = result['user'] session['user'] = result['user']
req.context['result'] = result
resp.status = falcon.HTTP_200 resp.status = falcon.HTTP_200
@ -39,6 +37,17 @@ class AppLogout(object):
raise falcon.HTTPTemporaryRedirect('/') 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): class AppMain(object):
template = 'main.html' template = 'main.html'

View File

@ -5,40 +5,36 @@ from beaker.middleware import SessionMiddleware
from middleware import AuthMiddleware, JSONTranslator, static, handle_404 from middleware import AuthMiddleware, JSONTranslator, static, handle_404
from models.db import StorageEngine from models.db import StorageEngine
from controllers.main import AppLogin, AppLogout, AppMain, AppPartners from controllers.main import (
from controllers.helper import AppPostalCode AppLogin, AppLogout, AppAdmin, AppMain,
from settings import DEBUG, WITH_LOGIN )
from settings import DEBUG
db = StorageEngine() db = StorageEngine()
pc = AppPostalCode() #~ partners = AppPartners(db)
login = AppLogin(db)
logout = AppLogout(db)
main = AppMain(db)
partners = AppPartners(db)
api = falcon.API(middleware=[AuthMiddleware(), JSONTranslator()]) api = falcon.API(middleware=[AuthMiddleware(), JSONTranslator()])
api.req_options.auto_parse_form_urlencoded = True api.req_options.auto_parse_form_urlencoded = True
api.add_sink(handle_404, '') api.add_sink(handle_404, '')
if WITH_LOGIN:
api.add_route('/', login) api.add_route('/', AppLogin(db))
api.add_route('/logout', logout) api.add_route('/logout', AppLogout(db))
api.add_route('/main', main) api.add_route('/admin', AppAdmin(db))
api.add_route('/partners', partners) api.add_route('/main', AppMain(db))
api.add_route('/pc', pc)
#~ api.add_route('/partners', partners)
if DEBUG: if DEBUG:
api.add_sink(static, '/static') api.add_sink(static, '/static')
session_opts = { session_options = {
'session.type': 'file', 'session.type': 'file',
'session.cookie_expires': True, 'session.cookie_expires': True,
'session.data_dir': '/tmp/cache/data', 'session.data_dir': '/tmp/cache/data',
'session.lock_dir': '/tmp/cache/lock', 'session.lock_dir': '/tmp/cache/lock',
#~ 'session.httponly': True,
#~ 'session.secure': True,
} }
app = SessionMiddleware(api, session_opts) app = SessionMiddleware(api, session_options)

View File

@ -31,12 +31,9 @@ def static(req, res):
class AuthMiddleware(object): class AuthMiddleware(object):
#~ def process_request(self, req, resp):
def process_resource(self, req, resp, resource, params): def process_resource(self, req, resp, resource, params):
paths = ('/main', '/partners', '/cp')
id_session = req.cookies.get('beaker.session.id', '') 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('/') raise falcon.HTTPTemporaryRedirect('/')
@ -46,5 +43,3 @@ class JSONTranslator(object):
if 'result' not in req.context: if 'result' not in req.context:
return return
resp.body = util.dumps(req.context['result']) resp.body = util.dumps(req.context['result'])

View File

@ -6,10 +6,10 @@ from . import main
class StorageEngine(object): class StorageEngine(object):
def __init__(self): def __init__(self):
main.connect() main.conectar()
def authenticate(self, username, password): def authenticate(self, args):
return main.authenticate(username, password) return main.authenticate(args['usuario'], args['contra'])
def get_partners(self, values): def get_partners(self, values):
return main.get_partners(values) return main.get_partners(values)

View File

@ -3,12 +3,15 @@
import sqlite3 import sqlite3
import click import click
from peewee import * from peewee import *
from playhouse.fields import PasswordField, ManyToManyField
if __name__ == '__main__': if __name__ == '__main__':
import os, sys import os, sys
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, parent_dir) sys.path.insert(0, parent_dir)
from controllers import util from controllers import util
from conf import DATABASE, __version__ from conf import DATABASE, __version__
from settings import log, PATH_CP from settings import log, PATH_CP
@ -20,50 +23,95 @@ class BaseModel(Model):
database = database database = database
def connect(): def conectar():
global database global database
database.connect() database.connect()
log.info('Conectado a la BD...') log.info('Conectado a la BD...')
return return
class Configuration(BaseModel): class Configuracion(BaseModel):
key = FixedCharField(max_length=50) clave = TextField()
value = FixedCharField(max_length=100) valor = TextField()
class Meta: class Meta:
order_by = ('key',) order_by = ('clave',)
indexes = ( indexes = (
(('key', 'value'), True), (('clave', 'valor'), True),
) )
class Tags(BaseModel): class Tags(BaseModel):
tag = FixedCharField(max_length=25, index=True) tag = TextField(index=True, unique=True)
class Meta: class Meta:
order_by = ('tag',) order_by = ('tag',)
class Users(BaseModel): class Usuarios(BaseModel):
username = CharField(max_length=50, unique=True) usuario = TextField(unique=True)
first_name = CharField(max_length=50, default='') nombre = TextField(default='')
last_name = CharField(max_length=50, default='') apellidos = TextField(default='')
email = CharField(max_length=200, default='') correo = TextField(default='')
password = CharField(max_length=100) contraseña = PasswordField()
is_superuser = BooleanField(default=False) es_superusuario = BooleanField(default=False)
is_admin = BooleanField(default=False) es_admin = BooleanField(default=False)
is_staff = BooleanField(default=False) es_activo = BooleanField(default=True)
is_active = BooleanField(default=True) fecha_ingreso = DateTimeField(default=util.now)
date_joined = DateTimeField(default=util.now) ultimo_ingreso = DateTimeField(null=True)
last_login = DateTimeField(null=True)
def __str__(self): def __str__(self):
t = '{} {} ({})' t = '{} {} ({})'
return t.format(self.first_name, self.last_name, self.username) return t.format(self.nombre, self.apellidos, self.usuario)
class Meta: 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): class Clients(BaseModel):
@ -114,22 +162,23 @@ class ClientsTags(BaseModel):
) )
def authenticate(username, password): def authenticate(usuario, contraseña):
data = {'login': False, 'msg': 'No Autorizado', 'user': ''} respuesta = {'login': False, 'msg': 'No Autorizado', 'user': ''}
try: try:
obj = Users.get(Users.username==username, Users.is_active==True) obj = Usuarios.get(usuario=usuario, es_activo=True)
except Users.DoesNotExist: except Usuarios.DoesNotExist:
return data return respuesta
if not util.validate_password(obj.password, password): if not obj.contraseña.check_password(contraseña):
return data return respuesta
obj.last_login = util.now() obj.ultimo_ingreso = util.now()
obj.save() obj.save()
data['msg'] = '' respuesta['msg'] = ''
data['login'] = True respuesta['login'] = True
data['user'] = str(obj) respuesta['user'] = str(obj)
return data respuesta['super'] = obj.es_superusuario
return respuesta
def get_partners(values): def get_partners(values):
@ -199,12 +248,12 @@ def _init_values():
return return
def create_tables(): def _crear_tablas():
connect() conectar()
tables = [Configuration, Tags, Users, Clients, ClientsTags] tablas = [Configuracion, Tags, Usuarios,
database.create_tables(tables, True) Certificado, Emisor, Emisor.regimenes.get_through_model()]
database.create_tables(tablas, True)
log.info('Tablas creadas correctamente...') log.info('Tablas creadas correctamente...')
_init_values()
return return
@ -214,19 +263,20 @@ def migrate_tables():
return return
def create_superuser(): def _agregar_superusuario():
connect() conectar()
username = input('Introduce el nuevo nombre para el superusuario: ').strip() usuario = input('Introduce el nuevo nombre para el superusuario: ').strip()
if not username: if not usuario:
msg = 'El nombre de usuario es requerido' msg = 'El nombre de usuario es requerido'
log.erro(msg) log.erro(msg)
return return
ok, password = util.get_pass() ok, contraseña = util.get_pass()
if not ok: if not ok:
log.error(password) log.error(contraseña)
return return
try: 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: except IntegrityError:
msg = 'El usuario ya existe' msg = 'El usuario ya existe'
log.error(msg) log.error(msg)
@ -236,27 +286,27 @@ def create_superuser():
return return
def change_password(): def _cambiar_contraseña():
connect() conectar()
username = input('Introduce el nombre de usuario: ').strip() usuario = input('Introduce el nombre de usuario: ').strip()
if not username: if not usuario:
msg = 'El nombre de usuario es requerido' msg = 'El nombre de usuario es requerido'
log.error(msg) log.error(msg)
return return
try: try:
obj = Users.get(username=username) obj = Usuarios.get(usuario=usuario)
except Users.DoesNotExist: except Usuarios.DoesNotExist:
msg = 'El usuario no existe' msg = 'El usuario no existe'
log.error(msg) log.error(msg)
return return
ok, password = util.get_pass() ok, contraseña = util.get_pass()
if not ok: if not ok:
log.error(password) log.error(contraseña)
return return
obj.password = password obj.contraseña = contraseña
obj.save() obj.save()
log.info('Contraseña cambiada correctamente...') log.info('Contraseña cambiada correctamente...')
@ -282,7 +332,7 @@ def main(iniciar_bd, migrar_bd, nuevo_superusuario, cambiar_contraseña):
opt = locals() opt = locals()
if opt['iniciar_bd']: if opt['iniciar_bd']:
create_tables() _crear_tablas()
sys.exit(0) sys.exit(0)
if opt['migrar_bd']: if opt['migrar_bd']:
@ -290,11 +340,11 @@ def main(iniciar_bd, migrar_bd, nuevo_superusuario, cambiar_contraseña):
sys.exit(0) sys.exit(0)
if opt['nuevo_superusuario']: if opt['nuevo_superusuario']:
create_superuser() _agregar_superusuario()
sys.exit(0) sys.exit(0)
if opt['cambiar_contraseña']: if opt['cambiar_contraseña']:
change_password() _cambiar_contraseña()
return return

View File

@ -5,7 +5,7 @@ import os
import sys import sys
from mako.lookup import TemplateLookup from mako.lookup import TemplateLookup
from logbook import Logger, StreamHandler, RotatingFileHandler from logbook import Logger, StreamHandler, RotatingFileHandler
logbook.set_datetime_format("local") logbook.set_datetime_format('local')
from conf import DEBUG 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')) PATH_TEMPLATES = os.path.abspath(os.path.join(BASE_DIR, '..', 'templates'))
EMAIL_SUPPORT = ('soporte@empresalibre.net',) EMAIL_SUPPORT = ('soporte@empresalibre.net',)
WITH_LOGIN = True #~ WITH_LOGIN = True
DB_CP = 'cp.db' DB_CP = 'cp.db'
PATH_CP = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', DB_CP)) PATH_CP = os.path.abspath(os.path.join(BASE_DIR, '..', 'db', DB_CP))

View File

@ -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'
}

View File

@ -29,7 +29,7 @@ var controllers = {
$$("cmd_save_invoice").attachEvent("onItemClick", cmd_save_invoice_click); $$("cmd_save_invoice").attachEvent("onItemClick", cmd_save_invoice_click);
$$("cmd_cancel_invoice").attachEvent("onItemClick", cmd_cancel_invoice_click); $$("cmd_cancel_invoice").attachEvent("onItemClick", cmd_cancel_invoice_click);
get_partners() //~ get_partners()
} }
}; };

View File

@ -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,
]
}
]
};

View File

@ -1,12 +1,12 @@
var msg_user = 'El usuario es requerido' var msg_user = 'El usuario es requerido'
var msg_pass = 'La contraseña es requerida' var msg_pass = 'La contraseña es requerida'
var form_controls = [ var form_controls = [
{view: 'text', label: 'Usuario', name: 'user', labelPosition: 'top', {view: 'text', label: 'Usuario', id: 'txt_usuario', name: 'usuario',
required: true, invalidMessage: msg_user}, labelPosition: 'top', required: true, invalidMessage: msg_user},
{view: 'text', label: 'Contraseña', name: 'pass', type: 'password', {view: 'text', label: 'Contraseña', id: 'txt_contra', name: 'contra',
required: true, labelPosition: 'top', invalidMessage: msg_pass}, type: 'password', required: true, labelPosition: 'top',
invalidMessage: msg_pass},
{margin: 10, cols:[{}, {view: 'button', value: 'Iniciar Sesión', {margin: 10, cols:[{}, {view: 'button', value: 'Iniciar Sesión',
click: 'validate_login', hotkey: 'enter'}, {}]} click: 'validate_login', hotkey: 'enter'}, {}]}
] ]
@ -28,8 +28,8 @@ var ui_login = {
width: 400, width: 400,
elements: form_controls, elements: form_controls,
rules:{ rules:{
user:function(value){ return value.trim() != '';}, usuario:function(value){ return value.trim() != '';},
pass:function(value){ return value.trim() != '';}, contra:function(value){ return value.trim() != '';},
} }
}, },
]}, {}, ] ]}, {}, ]

View File

@ -1,5 +1,4 @@
var menu_data = [ var menu_data = [
{id: 'app_home', icon: 'dashboard', value: 'Inicio'}, {id: 'app_home', icon: 'dashboard', value: 'Inicio'},
{id: 'app_partners', icon: 'users', value: 'Clientes y Proveedores'}, {id: 'app_partners', icon: 'users', value: 'Clientes y Proveedores'},

View File

@ -0,0 +1,29 @@
<%inherit file="base.html"/>
<%block name="media">
<link rel="stylesheet" href="/static/css/sidebar_air.css" type="text/css">
<script src="/static/js/sidebar.js" type="text/javascript" ></script>
<script src="/static/js/controller/util.js" type="text/javascript" ></script>
<script src="/static/js/ui/admin.js" type="text/javascript" ></script>
<script src="/static/js/controller/admin.js" type="text/javascript" ></script>
</%block>
<%block name="content">
<input type=hidden id="username" value="${username}"/>
<script type="text/javascript" charset="utf-8">
webix.ready(function(){
webix.CustomScroll.init()
webix.ui(ui_admin)
controllers.init()
var user = document.getElementById("username").value
$$('menu_user').getMenu(0).updateItem(0, {value:user})
})
</script>
</%block>

View File

@ -9,7 +9,6 @@
<link rel="stylesheet" href="/static/css/app.css" type="text/css"> <link rel="stylesheet" href="/static/css/app.css" type="text/css">
<script src="/static/js/webix_debug.js" type="text/javascript" ></script> <script src="/static/js/webix_debug.js" type="text/javascript" ></script>
<script src="/static/js/es-MX.js" type="text/javascript" ></script> <script src="/static/js/es-MX.js" type="text/javascript" ></script>
<%block name="media"/> <%block name="media"/>
</head> </head>

View File

@ -18,14 +18,18 @@ function validate_login(){
return return
} }
var values = form.getValues(); var values = form.getValues()
webix.ajax().post("/", values, function(text, data, xhr) { webix.ajax().post("/", values, function(text, data, xhr) {
var values = data.json(); var values = data.json();
if (values.login) { if (values.login) {
window.location = "/main"; if (values.super) {
window.location = "/admin"
}else{
window.location = "/main"
}
} else { } else {
webix.message({ type:"error", text: values.msg }); webix.message({ type:"error", text: values.msg })
} }
}); });
}; };