mirror of
https://github.com/MikroWizard/mikroman.git
synced 2025-07-01 17:44:32 +02:00
170 lines
4.6 KiB
Python
170 lines
4.6 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# db_user_tasks.py: Models and functions for accsessing db
|
|
# MikroWizard.com , Mikrotik router management solution
|
|
# Author: Tomi.Mickelsson@iki.fi modified by sepehr.ha@gmail.com
|
|
|
|
from peewee import *
|
|
from playhouse.shortcuts import model_to_dict
|
|
from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE
|
|
|
|
from flask import abort
|
|
import config
|
|
|
|
import logging
|
|
log = logging.getLogger("db")
|
|
|
|
if config.IS_SQLITE:
|
|
# config.DATABASE_HOST is full path to sqlite file
|
|
database = SqliteDatabase(config.DATABASE_HOST, pragmas={})
|
|
else:
|
|
from playhouse.postgres_ext import PostgresqlExtDatabase, ArrayField, BinaryJSONField, BooleanField, JSONField
|
|
# support for arrays of uuid
|
|
import psycopg2.extras
|
|
psycopg2.extras.register_uuid()
|
|
|
|
database = PostgresqlExtDatabase(config.DATABASE_NAME,
|
|
user=config.DATABASE_USER, password=config.DATABASE_PASSWORD,
|
|
host=config.DATABASE_HOST, port=config.DATABASE_PORT , isolation_level=ISOLATION_LEVEL_SERIALIZABLE)
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
# Base model and common methods
|
|
|
|
class BaseModel(Model):
|
|
"""Base class for all database models."""
|
|
|
|
# exclude these fields from the serialized dict
|
|
EXCLUDE_FIELDS = []
|
|
|
|
def serialize(self):
|
|
"""Serialize the model into a dict."""
|
|
d = model_to_dict(self, recurse=False, exclude=self.EXCLUDE_FIELDS)
|
|
d["id"] = str(d["id"]) # unification: id is always a string
|
|
return d
|
|
|
|
class Meta:
|
|
database = database
|
|
|
|
|
|
def get_object_or_404(model, **kwargs):
|
|
"""Retrieve a single object or abort with 404."""
|
|
|
|
try:
|
|
return model.get(**kwargs)
|
|
except model.DoesNotExist:
|
|
log.warning("NO OBJECT {} {}".format(model, kwargs))
|
|
abort(200)
|
|
|
|
def get_object_or_none(model, **kwargs):
|
|
"""Retrieve a single object or return None."""
|
|
|
|
try:
|
|
return model.get(**kwargs)
|
|
except model.DoesNotExist:
|
|
return None
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
# USER
|
|
|
|
class User(BaseModel):
|
|
|
|
# Should user.id be an integer or uuid? Both have pros and cons.
|
|
# Since user.id is sensitive data, I selected uuid here.
|
|
if not config.IS_SQLITE:
|
|
id = UUIDField(primary_key=True)
|
|
id.auto_increment = True # is auto generated by server
|
|
|
|
username = TextField()
|
|
password = TextField()
|
|
hash = TextField()
|
|
first_name = TextField()
|
|
last_name = TextField()
|
|
role = TextField()
|
|
email = TextField()
|
|
adminperms = TextField()
|
|
if not config.IS_SQLITE:
|
|
tags = ArrayField(TextField)
|
|
else:
|
|
tags = TextField()
|
|
|
|
created = DateTimeField()
|
|
modified = DateTimeField()
|
|
|
|
EXCLUDE_FIELDS = [password,hash] # never expose password
|
|
|
|
|
|
def is_superuser(self):
|
|
return self.role == "superuser"
|
|
|
|
def full_name(self):
|
|
return "{} {}".format(self.first_name, self.last_name or '')
|
|
|
|
def serialize(self):
|
|
"""Serialize this object to dict/json."""
|
|
|
|
d = super(User, self).serialize()
|
|
|
|
# add extra data
|
|
d["fullname"] = self.full_name()
|
|
d["tags"] = self.tags or [] # never None
|
|
return d
|
|
|
|
def __str__(self):
|
|
return "<User {}, {}, role={}>".format(self.id,
|
|
self.username, self.role)
|
|
|
|
class Meta:
|
|
db_table = 'users'
|
|
|
|
|
|
def get_user(uid):
|
|
"""Return user object or throw."""
|
|
return get_object_or_404(User, id=uid)
|
|
|
|
|
|
def get_user_by_username(username):
|
|
"""Return user object or None"""
|
|
|
|
if not username:
|
|
return None
|
|
|
|
try:
|
|
# return User.select().where(User.username == username).get()
|
|
# case insensitive query
|
|
if config.IS_SQLITE:
|
|
sql = "SELECT * FROM users where username = ? LIMIT 1"
|
|
args = username.lower()
|
|
else:
|
|
sql = "SELECT * FROM users where LOWER(username) = LOWER(%s) LIMIT 1"
|
|
args = (username,)
|
|
return list(User.raw(sql, args))[0]
|
|
|
|
except IndexError:
|
|
return None
|
|
|
|
|
|
def query_users(page=0, limit=1000, search=None):
|
|
"""Return list of users. Desc order"""
|
|
|
|
page = int(page or 0)
|
|
limit = int(limit or 1000)
|
|
|
|
q = User.select()
|
|
if search:
|
|
search = "%"+search+"%"
|
|
q = q.where(User.first_name ** search | User.last_name ** search |
|
|
User.username ** search)
|
|
q = q.paginate(page, limit).order_by(User.id.desc())
|
|
return q
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
|
|
if __name__ == '__main__':
|
|
|
|
# quick adhoc tests
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|