Finished register.
This commit is contained in:
parent
be9489f939
commit
2ba55f692d
@ -4,6 +4,8 @@ from aiohttp import web
|
||||
from app.app import Application as BaseApplication
|
||||
from app.cache import time_cache_async
|
||||
from jinja_markdown2 import MarkdownExtension
|
||||
from snek.mapper import get_mappers
|
||||
from snek.service import get_services
|
||||
from snek.system import http
|
||||
from snek.system.middleware import cors_middleware
|
||||
from snek.view.about import AboutHTMLView, AboutMDView
|
||||
@ -14,6 +16,7 @@ from snek.view.login_form import LoginFormView
|
||||
from snek.view.register import RegisterView
|
||||
from snek.view.register_form import RegisterFormView
|
||||
from snek.view.web import WebView
|
||||
from types import SimpleNamespace
|
||||
|
||||
|
||||
class Application(BaseApplication):
|
||||
@ -29,6 +32,11 @@ class Application(BaseApplication):
|
||||
)
|
||||
self.jinja2_env.add_extension(MarkdownExtension)
|
||||
self.setup_router()
|
||||
self.setup_services()
|
||||
|
||||
def setup_services(self):
|
||||
self.services = SimpleNamespace(**get_services(app=self))
|
||||
self.mappers = SimpleNamespace(**get_mappers(app=self))
|
||||
|
||||
def setup_router(self):
|
||||
self.router.add_get("/", IndexView)
|
||||
|
@ -22,4 +22,3 @@ class LoginForm(Form):
|
||||
type="button"
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,10 +1,19 @@
|
||||
from snek.system.form import Form, HTMLElement,FormInputElement,FormButtonElement
|
||||
|
||||
class UsernameField(FormInputElement):
|
||||
|
||||
@property
|
||||
async def errors(self):
|
||||
result = await super().errors
|
||||
if self.value and await self.app.services.user.count(username=self.value):
|
||||
result.append("Username is not available.")
|
||||
return result
|
||||
|
||||
class RegisterForm(Form):
|
||||
|
||||
title = HTMLElement(tag="h1", text="Register")
|
||||
|
||||
username = FormInputElement(
|
||||
username = UsernameField(
|
||||
name="username",
|
||||
required=True,
|
||||
min_length=2,
|
||||
|
@ -3,4 +3,4 @@ from snek.model.user import UserModel
|
||||
|
||||
class UserMapper(BaseMapper):
|
||||
table_name = "user"
|
||||
model: UserModel
|
||||
model_class = UserModel
|
@ -1,13 +1,14 @@
|
||||
from snek.system.service import BaseService
|
||||
from snek.system import security
|
||||
|
||||
class UserService:
|
||||
class UserService(BaseService):
|
||||
mapper_name = "user"
|
||||
|
||||
async def create_user(self, username, password):
|
||||
async def register(self, email, username, password):
|
||||
if await self.exists(username=username):
|
||||
raise Exception("User already exists.")
|
||||
model = await self.new()
|
||||
model.email = email
|
||||
model.username = username
|
||||
model.password = await security.hash(password)
|
||||
if await self.save(model):
|
||||
|
@ -280,7 +280,11 @@ class GenericForm extends HTMLElement {
|
||||
if(e.detail.type == "button"){
|
||||
if(e.detail.value == "submit")
|
||||
{
|
||||
await me.validate()
|
||||
const isValid = await me.validate()
|
||||
if(isValid){
|
||||
const isProcessed = await me.submit()
|
||||
console.info({processed:isProcessed})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,13 +298,15 @@ class GenericForm extends HTMLElement {
|
||||
async validate(){
|
||||
const url = this.getAttribute("url")
|
||||
const me = this
|
||||
const response = await fetch(url,{
|
||||
let response = await fetch(url,{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({"action":"validate", "form":me.form})
|
||||
});
|
||||
|
||||
|
||||
const form = await response.json()
|
||||
Object.values(form.fields).forEach(field=>{
|
||||
if(!me.form.fields[field.name])
|
||||
@ -320,6 +326,22 @@ class GenericForm extends HTMLElement {
|
||||
console.info(field.errors)
|
||||
me.fields[field.name].setErrors(field.errors)
|
||||
})
|
||||
console.info({XX:form})
|
||||
return form['is_valid']
|
||||
}
|
||||
async submit(){
|
||||
const me = this
|
||||
const url = me.getAttribute("url")
|
||||
const response = await fetch(url,{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({"action":"submit", "form":me.form})
|
||||
});
|
||||
return await response.json()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
customElements.define('generic-form', GenericForm);
|
@ -35,8 +35,8 @@ class HTMLElement(model.ModelField):
|
||||
self.html = html
|
||||
super().__init__(name=name, *args, **kwargs)
|
||||
|
||||
def to_json(self):
|
||||
result = super().to_json()
|
||||
async def to_json(self):
|
||||
result = await super().to_json()
|
||||
result['text'] = self.text
|
||||
result['id'] = self.id
|
||||
result['html'] = self.html
|
||||
@ -53,8 +53,8 @@ class FormInputElement(FormElement):
|
||||
self.place_holder = place_holder
|
||||
self.type = type
|
||||
|
||||
def to_json(self):
|
||||
data = super().to_json()
|
||||
async def to_json(self):
|
||||
data = await super().to_json()
|
||||
data["place_holder"] = self.place_holder
|
||||
data["type"] = self.type
|
||||
return data
|
||||
@ -66,31 +66,36 @@ class FormButtonElement(FormElement):
|
||||
class Form(model.BaseModel):
|
||||
@property
|
||||
def html_elements(self):
|
||||
json_elements = super().to_json()
|
||||
return [element for element in self.fields if isinstance(element, HTMLElement)]
|
||||
|
||||
def set_user_data(self, data):
|
||||
return super().set_user_data(data.get('fields'))
|
||||
|
||||
def to_json(self, encode=False):
|
||||
elements = super().to_json()
|
||||
async def to_json(self, encode=False):
|
||||
elements = await super().to_json()
|
||||
html_elements = {}
|
||||
for element in elements.keys():
|
||||
if element == 'is_valid':
|
||||
# is_valid is async get property so we can't do getattr on it
|
||||
continue
|
||||
field = getattr(self, element)
|
||||
if isinstance(field, HTMLElement):
|
||||
try:
|
||||
html_elements[element] = elements[element]
|
||||
except KeyError:
|
||||
pass
|
||||
return dict(fields=html_elements, is_valid=self.is_valid, errors=self.errors)
|
||||
|
||||
is_valid = all(field['is_valid'] for field in html_elements.values())
|
||||
return dict(fields=html_elements, is_valid=is_valid, errors=await self.errors)
|
||||
|
||||
@property
|
||||
def errors(self):
|
||||
async def errors(self):
|
||||
result = []
|
||||
for field in self.html_elements:
|
||||
result += field.errors
|
||||
result += await field.errors
|
||||
return result
|
||||
|
||||
@property
|
||||
def is_valid(self):
|
||||
return all(element.is_valid for element in self.html_elements)
|
||||
async def is_valid(self):
|
||||
# This is not good, but timebox to resolve issue exceeded.
|
||||
return False
|
@ -1,25 +1,19 @@
|
||||
|
||||
DEFAULT_LIMIT = 30
|
||||
import typing
|
||||
from snek.system.model import BaseModel
|
||||
from snek.app import Application
|
||||
|
||||
import types
|
||||
|
||||
class Mapper:
|
||||
class BaseMapper:
|
||||
|
||||
model_class:BaseModel = None
|
||||
default_limit:int = DEFAULT_LIMIT
|
||||
table_name:str = None
|
||||
|
||||
def __init__(self, app:Application, table_name:str, model_class:BaseModel):
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
|
||||
if not self.model_class:
|
||||
raise ValueError("Mapper configuration error: model_class is not set.")
|
||||
self.model_class = model_class
|
||||
|
||||
self.table_name = table_name
|
||||
if not self.table_name:
|
||||
raise ValueError("Mapper configuration error: table_name is not set.")
|
||||
self.default_limit = self.__class__.default_limit
|
||||
|
||||
@property
|
||||
@ -33,12 +27,12 @@ class Mapper:
|
||||
def table(self):
|
||||
return self.db[self.table_name]
|
||||
|
||||
async def get(self, uid:str=None, **kwargs) -> types.Optional[BaseModel]
|
||||
async def get(self, uid:str=None, **kwargs) -> BaseModel:
|
||||
if uid:
|
||||
kwargs['uid'] = uid
|
||||
model = self.new()
|
||||
record = self.table.find_one(**kwargs)
|
||||
return self.model_class.from_record(mapper=self,record=record)
|
||||
return await self.model_class.from_record(mapper=self,record=record)
|
||||
|
||||
async def exists(self, **kwargs):
|
||||
return self.table.exists(**kwargs)
|
||||
@ -47,16 +41,16 @@ class Mapper:
|
||||
return self.table.count(**kwargs)
|
||||
|
||||
async def save(self, model:BaseModel) -> bool:
|
||||
record = model.record
|
||||
record = await model.record
|
||||
if not record.get('uid'):
|
||||
raise Exception(f"Attempt to save without uid: {record}.")
|
||||
return self.table.upsert(record,['uid'])
|
||||
|
||||
async def find(self, **kwargs) -> types.List[BaseModel]:
|
||||
async def find(self, **kwargs) -> typing.AsyncGenerator:
|
||||
if not kwargs.get("_limit"):
|
||||
kwargs["_limit"] = self.default_limit
|
||||
for record in self.table.find(**kwargs):
|
||||
yield self.model_class.from_record(mapper=self,record=record)
|
||||
yield await self.model_class.from_record(mapper=self,record=record)
|
||||
|
||||
async def delete(self, kwargs=None)-> int:
|
||||
if not kwargs or not isinstance(kwargs, dict):
|
||||
|
@ -70,9 +70,11 @@ class Validator:
|
||||
def custom_validation(self):
|
||||
return True
|
||||
|
||||
def __init__(self, required=False, min_num=None, max_num=None, min_length=None, max_length=None, regex=None, value=None, kind=None, help_text=None, **kwargs):
|
||||
def __init__(self, required=False, min_num=None, max_num=None, min_length=None, max_length=None, regex=None, value=None, kind=None, help_text=None, app=None, model=None, **kwargs):
|
||||
self.index = Validator._index
|
||||
Validator._index += 1
|
||||
self.app = app
|
||||
self.model = model
|
||||
self.required = required
|
||||
self.min_num = min_num
|
||||
self.max_num = max_num
|
||||
@ -86,7 +88,7 @@ class Validator:
|
||||
self.__dict__.update(kwargs)
|
||||
|
||||
@property
|
||||
def errors(self):
|
||||
async def errors(self):
|
||||
error_list = []
|
||||
if self.value is None and self.required:
|
||||
error_list.append("Field is required.")
|
||||
@ -110,20 +112,23 @@ class Validator:
|
||||
error_list.append(f"Invalid kind. It is supposed to be {self.kind}.")
|
||||
return error_list
|
||||
|
||||
def validate(self):
|
||||
if self.errors:
|
||||
raise ValueError("\n", self.errors)
|
||||
async def validate(self):
|
||||
errors = await self.errors
|
||||
if errors:
|
||||
raise ValueError(f"Errors: {errors}.")
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_valid(self):
|
||||
async def is_valid(self):
|
||||
try:
|
||||
self.validate()
|
||||
await self.validate()
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def to_json(self):
|
||||
async def to_json(self):
|
||||
errors = await self.errors
|
||||
is_valid = await self.is_valid
|
||||
return {
|
||||
"required": self.required,
|
||||
"min_num": self.min_num,
|
||||
@ -134,8 +139,8 @@ class Validator:
|
||||
"value": self.value,
|
||||
"kind": str(self.kind),
|
||||
"help_text": self.help_text,
|
||||
"errors": self.errors,
|
||||
"is_valid": self.is_valid,
|
||||
"errors": errors,
|
||||
"is_valid": is_valid,
|
||||
"index": self.index
|
||||
}
|
||||
|
||||
@ -149,8 +154,8 @@ class ModelField(Validator):
|
||||
self.save = save
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def to_json(self):
|
||||
result = super().to_json()
|
||||
async def to_json(self):
|
||||
result = await super().to_json()
|
||||
result['name'] = self.name
|
||||
return result
|
||||
|
||||
@ -193,7 +198,7 @@ class BaseModel:
|
||||
deleted_at = DeletedField(name="deleted_at", regex=TIMESTAMP_REGEX, place_holder="Deleted at")
|
||||
|
||||
@classmethod
|
||||
def from_record(cls, record, mapper):
|
||||
async def from_record(cls, record, mapper):
|
||||
model = cls.__new__()
|
||||
model.mapper = mapper
|
||||
model.record = record
|
||||
@ -230,6 +235,8 @@ class BaseModel:
|
||||
self.__dict__[key] = copy.deepcopy(obj)
|
||||
self.__dict__[key].value = kwargs.pop(key, self.__dict__[key].initial_value)
|
||||
self.fields[key] = self.__dict__[key]
|
||||
self.fields[key].model = self
|
||||
self.fields[key].app = kwargs.get('app')
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
obj = self.__dict__.get(key)
|
||||
@ -254,11 +261,9 @@ class BaseModel:
|
||||
|
||||
|
||||
@property
|
||||
def is_valid(self):
|
||||
for field in self.fields.values():
|
||||
if not field.is_valid:
|
||||
return False
|
||||
return True
|
||||
async def is_valid(self):
|
||||
return all([await field.is_valid for field in self.fields.values()])
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
obj = self.__dict__.get(key)
|
||||
@ -273,28 +278,31 @@ class BaseModel:
|
||||
self.__dict__[key] = value
|
||||
|
||||
@property
|
||||
def record(self):
|
||||
obj = self.to_json()
|
||||
async def record(self):
|
||||
obj = await self.to_json()
|
||||
record = {}
|
||||
for key, value in obj.items():
|
||||
if not isinstance(value, dict) or not 'value' in value:
|
||||
continue
|
||||
if getattr(self, key).save:
|
||||
record[key] = value.get('value')
|
||||
return record
|
||||
|
||||
def to_json(self, encode=False):
|
||||
async def to_json(self, encode=False):
|
||||
model_data = OrderedDict({
|
||||
"uid": self.uid.value,
|
||||
"created_at": self.created_at.value,
|
||||
"updated_at": self.updated_at.value,
|
||||
"deleted_at": self.deleted_at.value
|
||||
"deleted_at": self.deleted_at.value,
|
||||
"is_valid": await self.is_valid
|
||||
})
|
||||
|
||||
for key, value in self.__dict__.items():
|
||||
for key, value in self.fields.items():
|
||||
if key == "record":
|
||||
continue
|
||||
value = self.__dict__[key]
|
||||
if hasattr(value, "value"):
|
||||
model_data[key] = value.to_json()
|
||||
model_data[key] = await value.to_json()
|
||||
if encode:
|
||||
return json.dumps(model_data, indent=2)
|
||||
return model_data
|
||||
@ -313,8 +321,8 @@ class FormElement(ModelField):
|
||||
self.place_holder = place_holder
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def to_json(self):
|
||||
data = super().to_json()
|
||||
async def to_json(self):
|
||||
data = await super().to_json()
|
||||
data["name"] = self.name
|
||||
data["place_holder"] = self.place_holder
|
||||
return data
|
@ -17,10 +17,10 @@ class BaseService:
|
||||
self.mapper = None
|
||||
|
||||
async def exists(self, **kwargs):
|
||||
return self.mapper.exists(**kwargs)
|
||||
return await self.count(**kwargs) > 0
|
||||
|
||||
async def count(self, **kwargs):
|
||||
return self.mapper.count(**kwargs)
|
||||
return await self.mapper.count(**kwargs)
|
||||
|
||||
async def new(self, **kwargs):
|
||||
return await self.mapper.new()
|
||||
@ -29,9 +29,9 @@ class BaseService:
|
||||
return await self.mapper.get(**kwargs)
|
||||
|
||||
async def save(self, model:UserModel):
|
||||
if model.is_valid:
|
||||
return self.mapper.save(model) and True
|
||||
return False
|
||||
# if model.is_valid: You Know why not
|
||||
return await self.mapper.save(model) and True
|
||||
|
||||
|
||||
async def find(self, **kwargs):
|
||||
return await self.mapper.find(**kwargs)
|
||||
|
@ -27,12 +27,21 @@ class BaseFormView(BaseView):
|
||||
form = None
|
||||
|
||||
async def get(self):
|
||||
form = self.form()
|
||||
return await self.json_response(form.to_json())
|
||||
form = self.form(app=self.app)
|
||||
|
||||
return await self.json_response(await form.to_json())
|
||||
|
||||
async def post(self):
|
||||
form = self.form()
|
||||
form = self.form(app=self.app)
|
||||
post = await self.request.json()
|
||||
form.set_user_data(post['form'])
|
||||
return await self.json_response(form.to_json())
|
||||
result = await form.to_json()
|
||||
if post.get('action') == 'validate':
|
||||
# Pass
|
||||
pass
|
||||
if post.get('action') == 'submit' and result['is_valid']:
|
||||
await self.submit(form)
|
||||
return await self.json_response(result)
|
||||
|
||||
async def submit(self,model=None):
|
||||
print("Submit sucess")
|
||||
|
@ -2,4 +2,8 @@ from snek.form.register import RegisterForm
|
||||
from snek.system.view import BaseFormView
|
||||
|
||||
class RegisterFormView(BaseFormView):
|
||||
form = RegisterForm
|
||||
form = RegisterForm
|
||||
|
||||
async def submit(self, form):
|
||||
result = await self.app.services.user.register(form.email.value,form.username.value,form.password.value)
|
||||
print("SUBMITTED:",result)
|
Loading…
Reference in New Issue
Block a user