#!/usr/bin/python
"""ノード定義
* UserとGroupのモデル定義を書きます。
* 関係テーブルのモデル実装は別モジュールにしようかと思ってる
* sqlalchemyのベースクラスを拡張したNodeクラスに共通のプロパティを載せて、そいつらをUserとGroupに継承させてます。
Todo:
* sqlalchemy用にUser型とGroup型を作って、↓のクラスをそのまま使ってDB呼び出しできるようにしたい
"""
import base64
import hashlib
import random
import secrets
import smtplib
import bcrypt
import jwt
import magic
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.schema import UniqueConstraint
from sqlalchemy import event
from mitama.db import BaseDatabase, func, ForeignKey, relationship, Table, backref
from mitama.db.types import Column, Group, Integer, LargeBinary
from mitama.db.types import Node as NodeType
from mitama.db.types import String
from mitama.db.model import UUID
from mitama.noimage import load_noimage_group, load_noimage_user
from mitama.conf import get_from_project_dir
from mitama._extra import _classproperty
class Database(BaseDatabase):
pass
db = Database(prefix='mitama')
secret = secrets.token_hex(32)
class AuthorizationError(Exception):
INVALID_TOKEN = 0
WRONG_PASSWORD = 1
USER_NOT_FOUND= 2
def __init__(self, code):
self.code = code
@property
def message(self):
return [
"トークンが不正です",
"パスワードが間違っています",
"ユーザーが見つかりません"
][self.code]
pass
user_group = Table(
"mitama_user_group",
db.metadata,
Column("_id", String(64), default=UUID(), primary_key=True),
Column("group_id", String(64), ForeignKey("mitama_group._id", ondelete="CASCADE")),
Column("user_id", String(64), ForeignKey("mitama_user._id", ondelete="CASCADE")),
)
class UserGroup(db.Model):
__table__ = user_group
_id = user_group.c._id
group_id= user_group.c.group_id
user_id = user_group.c.user_id
user = relationship("User")
group = relationship("Group")
class Node(object):
_icon = Column(LargeBinary)
_name = Column("name", String(255))
_screen_name = Column("screen_name", String(255))
_name_proxy = list()
_screen_name_proxy = list()
_icon_proxy = list()
@property
def id(self):
return self._id
@property
def name(self):
name = self._name
for fn in self._name_proxy:
name = fn(name)
return name
@property
def screen_name(self):
screen_name = self._screen_name
for fn in self._screen_name_proxy:
screen_name = fn(screen_name)
return screen_name
def to_dict(self):
return {
"_id": self._id,
"name": self.name,
"screen_name": self.screen_name,
}
@property
def icon(self):
if self._icon != None:
icon = self._icon
else:
icon = self.load_noimage()
for fn in self._icon_proxy:
icon = fn(icon)
return icon
@name.setter
def name(self, value):
self._name = value
@screen_name.setter
def screen_name(self, value):
self._screen_name = value
@icon.setter
def icon(self, value):
self._icon = value
def icon_to_dataurl(self):
f = magic.Magic(mime=True, uncompress=True)
mime = f.from_buffer(self.icon)
return "data:" + mime + ";base64," + base64.b64encode(self.icon).decode()
@classmethod
def add_name_proxy(cls, fn):
cls._name_proxy.append(fn)
@classmethod
def add_screen_name_proxy(cls, fn):
cls._screen_name_proxy.append(fn)
@classmethod
def add_icon_proxy(cls, fn):
cls._icon_proxy.append(fn)
@classmethod
def retrieve(cls, _id=None, screen_name=None, **kwargs):
if _id is not None:
return super().retrieve(_id = _id)
elif screen_name is not None:
return super().retrieve(_screen_name = screen_name)
else:
return super().retrieve(**kwargs)
def __eq__(self, other):
return self._id == other._id
class User(Node, db.Model):
"""ユーザーのモデルクラスです
:param _id: 固有のID
:param screen_name: ログイン名
:param name: 名前
:param password: パスワード
:param icon: アイコン
"""
__tablename__ = "mitama_user"
_id = Column(String(64), default=UUID("user"), primary_key = True, nullable=False)
_project = None
_token = Column(String(64))
email = Column(String(64), nullable=False)
password = Column(String(255))
groups = relationship(
"Group",
secondary=user_group,
)
def to_dict(self, only_profile=False):
profile = super().to_dict()
if not only_profile:
profile["groups"] = [p.to_dict(True) for p in self.groups()]
return profile
def load_noimage(self):
return load_noimage_user()
def delete(self):
"""ユーザーを削除します"""
from mitama.app.hook import HookRegistry
hook_registry = HookRegistry()
hook_registry.delete_user(self)
super().delete()
def update(self):
"""ユーザー情報を更新します"""
super().update()
from mitama.app.hook import HookRegistry
hook_registry = HookRegistry()
hook_registry.update_user(self)
def create(self):
"""ユーザーを作成します"""
super().create()
from mitama.app.hook import HookRegistry
hook_registry = HookRegistry()
hook_registry.create_user(self)
def password_check(self, password):
password = base64.b64encode(hashlib.sha256(password.encode() * 10).digest())
return bcrypt.checkpw(password, self.password)
@classmethod
def password_auth(cls, screen_name, password):
"""ログイン名とパスワードで認証します
:param screen_name: ログイン名
:param password: パスワード
:return: Userインスタンス
"""
try:
user = cls.retrieve(_screen_name=screen_name)
if user is None:
raise AuthorizationError(AuthorizationError.USER_NOT_FOUND)
except:
raise AuthorizationError(AuthorizationError.USER_NOT_FOUND)
password = base64.b64encode(hashlib.sha256(password.encode() * 10).digest())
if bcrypt.checkpw(password, user.password):
return user
else:
raise AuthorizationError(AuthorizationError.WRONG_PASSWORD)
def valid_password(self, password):
"""パスワードが安全か検証します
:param password: パスワードのプレーンテキスト
:return: 検証済みパスワード
"""
if self._project is None:
return password
config = self._project.config
MIN_PASSWORD_LEN = config.password_validation.get('MIN_PASSWORD_LEN', None)
COMPLICATED_PASSWORD = config.password_validation.get('COMPLICATED_PASSWORD', False)
if MIN_PASSWORD_LEN and len(password) < MIN_PASSWORD_LEN:
raise ValueError('パスワードは{}文字以上である必要があります'.format(MIN_PASSWORD_LEN))
if COMPLICATED_PASSWORD and (not any(c.isdigit() for c in password)) or (not any(c.isalpha() for c in password)):
raise ValueError('パスワードは数字とアルファベットの両方を含む必要があります')
return password
def set_password(self, password):
"""パスワードをハッシュ化します
:param password: パスワードのプレーンテキスト
:return: パスワードハッシュ
"""
password = self.valid_password(password
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
PyPI 官网下载 | mitama-4.1.0.tar.gz (114个子文件)
simplemde.min.css 11KB
style.css 10KB
mitama-style.css 7KB
entrance-style.css 2KB
settings.html 9KB
update.html 5KB
forms.macro.html 3KB
lists.macro.html 3KB
update.html 3KB
create.html 2KB
create.html 2KB
welcome.html 2KB
signup.html 2KB
header.html 2KB
list.html 1KB
retrieve.html 1KB
list.html 1KB
list.html 1KB
update.html 1KB
retrieve.html 1KB
home.html 782B
setup.html 714B
login.html 711B
snippets.macro.html 470B
login_base.html 241B
confirm.html 227B
404.html 217B
403.html 196B
403.html 196B
404.html 181B
delete.html 154B
base.html 154B
delete.html 154B
401.html 0B
footers.macro.html 0B
navs.macro.html 0B
headers.macro.html 0B
503.html 0B
500.html 0B
400.html 0B
502.html 0B
simplemde.min.js 263KB
mitama.json 85B
LICENSE 34KB
login 1KB
style.css.map 2KB
mitama-style.css.map 1KB
entrance-style.css.map 493B
PKG-INFO 930B
plain 1KB
noimage_app.png 8KB
noimage_group.png 7KB
icon.png 4KB
noimage_user.png 3KB
__init__.py 23KB
controller.py 22KB
controllers.py 8KB
method.py 8KB
fields.py 7KB
app.py 6KB
request.py 6KB
response.py 6KB
session.py 5KB
project.py 5KB
router.py 5KB
registry.py 4KB
main.py 4KB
__init__.py 3KB
model.py 3KB
__init__.py 2KB
forms.py 2KB
middlewares.py 2KB
types.py 2KB
routers.py 2KB
setup.py 2KB
conf.py 2KB
noimage.py 2KB
hook.py 1KB
__init__.py 1KB
builder.py 1KB
errors.py 1KB
run.py 936B
debug.py 878B
__init__.py 847B
install.py 812B
uninstall.py 755B
__init__.py 723B
model.py 626B
_extra.py 617B
mkapp.py 613B
new.py 566B
init.py 553B
sqlite3.py 493B
help.py 464B
main.py 386B
__init__.py 372B
middleware.py 370B
controller.py 240B
__project__.py 209B
version.py 168B
共 114 条
- 1
- 2
资源评论
挣扎的蓝藻
- 粉丝: 13w+
- 资源: 15万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功