do some frontend crap
This commit is contained in:
parent
588cac6e95
commit
aa26e70fbd
8 changed files with 226 additions and 41 deletions
32
main.pl
32
main.pl
|
@ -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
8
routes/cart.pl
Normal 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).
|
||||
|
|
@ -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).
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
65
style.css
Normal 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
64
views/login.pl
Normal 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
57
views/products.pl
Normal 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))
|
||||
])
|
||||
]
|
||||
).
|
Loading…
Reference in a new issue