do some frontend crap

This commit is contained in:
Sijmen 2019-11-03 02:05:33 +01:00
parent 588cac6e95
commit aa26e70fbd
Signed by: vijfhoek
GPG key ID: DAF7821E067D9C48
8 changed files with 226 additions and 41 deletions

32
main.pl
View file

@ -1,16 +1,28 @@
:- use_module(library(http/http_server)).
:- use_module(library(http/html_head)).
:- use_module(library(http/html_write)).
:- use_module(library(http/http_client)).
:- use_module(library(http/http_json)).
:- use_module(library(http/http_header)).
:- use_module(library(http/json_convert)).
:- use_module(library(http/http_json)).
:- use_module(library(http/http_server)).
:- use_module(library(http/http_session)).
:- use_module(library(http/js_write)).
:- use_module(library(http/json)).
:- use_module(library(http/json_convert)).
:- use_module(library(persistency)).
:- consult('routes/products.pl').
:- consult('routes/login.pl').
:- consult('routes/users.pl').
:- consult('routes/cart.pl').
:- consult('views/products.pl').
:- consult('views/login.pl').
:- initialization
http_server([port(8080)]).
:- initialization
absolute_file_name('database.db', File, [access(write)]),
db_attach(File, []).
db_attach(File, []),
db_sync_all(gc(always)).
:- json_object
product(name:atom, price:integer).
@ -30,9 +42,15 @@
:- persistent
token(username:atom, token:atom).
:- persistent
session(session:atom, username:atom).
:- persistent
cart_entry(session:atom, items:atom).
:- json_object
error(error:atom).
:- consult('routes/products.pl').
:- consult('routes/login.pl').
:- consult('routes/users.pl').
reply_prolog(Term) :-
prolog_to_json(Term, Json),
reply_json(Json).

8
routes/cart.pl Normal file
View file

@ -0,0 +1,8 @@
:- http_handler(root(cart/add/ProductName), cart_add(ProductName), []).
% GET /cart/add/ProductName
cart_add(ProductName, Request) :-
http_session_id(SessionId),
assert_cart_entry(SessionId, ProductName),
http_redirect(see_other, root(.), Request).

View file

@ -1,25 +1,4 @@
:- http_handler(
root(login),
login_route,
[]
).
% Handles logging in, returning the correct Json in Reply.
handle_login(Username, Password, Reply) :-
user(Username, Hash),
crypto_password_hash(Password, Hash), !,
crypto_n_random_bytes(16, Bytes),
hex_bytes(Token, Bytes),
assert_token(Username, Token),
prolog_to_json(token(Username, Token), Reply).
handle_login(Username, _, Reply) :-
user(Username, _), !,
prolog_to_json(error(incorrect_password), Reply).
handle_login(_, _, Reply) :-
prolog_to_json(error(unknown_user), Reply).
:- http_handler(root(api/login), login_route, []).
% POST /login
login_route(Request) :-
@ -27,4 +6,4 @@ login_route(Request) :-
http_read_data(Request, Json, []),
json_to_prolog(Json, login(Username, Password)),
handle_login(Username, Password, Reply),
reply_json(Reply).
reply_prolog(Reply).

View file

@ -1,8 +1,4 @@
:- http_handler(
root(products),
products_page,
[]
).
:- http_handler(root(api/products), products_page, []).
% POST /products
products_page(Request) :-
@ -10,10 +6,9 @@ products_page(Request) :-
http_read_data(Request, Json, []),
json_to_prolog(Json, product(Name, Price)),
assert_product(Name, Price),
reply_json(Json).
reply_prolog(product(Name, Price)).
% GET /products
products_page(_Request) :-
bagof(product(Name, Price), product(Name, Price), Products),
prolog_to_json(Products, Json),
reply_json(Json, []).
reply_prolog(Products).

View file

@ -1,7 +1,6 @@
:- http_handler(root(users), users_route, []).
:- http_handler(root(api/users), users_route, []).
% GET /users
users_route(_Request) :-
bagof(user(Username), user(Username, _), Users),
prolog_to_json(Users, Json),
reply_json(Json).
reply_prolog(Users).

65
style.css Normal file
View file

@ -0,0 +1,65 @@
body {
font-family: sans-serif;
}
main {
display: flex;
}
.products {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
grid-gap: 10px;
flex: 1;
}
.cart {
width: 300px;
}
.product {
height: 110px;
display: flex;
flex-flow: column;
border: 1px solid rgba(0, 0, 0, .2);
border-radius: 5px;
color: rgba(0, 0, 0, .87);
text-decoration: none;
}
.product__name {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
}
.product__price {
display: flex;
justify-content: center;
align-items: center;
background-color: #27ae60;
color: #fff;
height: 30px;
}
.cart__entry {
border-top: 1px solid rgba(0, 0, 0, .12);
display: flex;
}
.cart__entry:last-child {
border-bottom: 1px solid rgba(0, 0, 0, .12);
}
.cart__entry > div {
margin: 12px;
}
.cart__name {
flex: 1;
}
.cart__price {
width: 65px;
}

64
views/login.pl Normal file
View file

@ -0,0 +1,64 @@
:- http_handler(root(login), login_view(Method), [method(Method), methods([get, post])]).
:- http_handler(root('style.css'), http_reply_file('style.css', []), []).
login_view(get, _Request) :-
reply_html_page(
[
title('point of shit'),
link([
type('text/css'),
rel('stylesheet'),
href('style.css')
])
],
[
h1('Login'),
form([method=post], [
div([
label(for=username, 'Username'),
input([
type=text,
placeholder='Username',
name=username,
id=username
])
]),
div([
label(for=password, 'Password'),
input([
type=password,
placeholder='Username',
name=password,
id=password
])
]),
div(
input([
type=submit,
value='Log in'
])
)
])
]
).
login_view(post, Request) :-
http_read_data(Request, [username=Username, password=Password], []),
handle_login(Username, Password, Reply),
reply_prolog(Reply).
% Handles logging in, returning the correct Json in Reply.
handle_login(Username, Password, Reply) :-
user(Username, Hash),
crypto_password_hash(Password, Hash), !,
assert_session(Username, Token),
Reply = true.
handle_login(Username, _, Reply) :-
user(Username, _), !,
Reply = incorrect_password.
handle_login(_, _, incorrect_user).

57
views/products.pl Normal file
View file

@ -0,0 +1,57 @@
:- http_handler(root(.), products_view, []).
:- http_handler(root('style.css'), http_reply_file('style.css', []), []).
price_str(Price, PriceStr) :-
Euro is Price / 100,
format(atom(PriceStr), '€ ~2f', Euro).
products_list([]) --> [].
products_list([product(Name, Price)|Products]) -->
{price_str(Price, PriceStr)},
html([
a([
class(product),
'data-name'(Name),
href('/cart/add/'+Name)
], [
div(class(product__name), [Name]),
div(class(product__price), [PriceStr])
])
]),
products_list(Products).
cart([]) --> [].
cart([Name|Items]) -->
{
product(Name, Cents),
price_str(Cents, Price)
},
html([
div(class(cart__entry), [
div(class(cart__name), Name),
div(class(cart__price), Price)
])
]),
cart(Items).
products_view(_Request) :-
http_session_id(SessionId),
bagof(product(X, Y), product(X, Y), Products),
(bagof(Name, cart_entry(SessionId, Name), CartEntries); CartEntries = []),
reply_html_page(
[
title('point of shit'),
link([
type('text/css'),
rel('stylesheet'),
href('style.css')
])
],
[
h1('Products'),
main([
div(class(products), \products_list(Products)),
div(class(cart), \cart(CartEntries))
])
]
).