Initial commit

main
Antonio De Lucreziis 4 years ago
commit 88d26d1e5c

1
.gitignore vendored

@ -0,0 +1 @@
node_modules/

@ -0,0 +1,7 @@
# Posti DM
Prototipo di applicazione web per prenotare posti in dipartimento.
- FrontEnd: Vite + VanillaJS
- BackEnd: Golang + go-chi + sqlite3 (?)

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Posti DM</title>
<script type="module" src="./src/index.js"></script>
</head>
<body>
<header>
<div class="nav-cell left"></div>
<div class="nav-cell center">
<div class="nav-item">Prenota Posti DM</div>
</div>
<div class="nav-cell right">
<div class="nav-item">Login</div>
</div>
</header>
<main>
<div class="room-name">AulaStud</div>
<div class="room-main">
<div class="room-diagram">
<img src="./diargamma-posti.jpg" alt="diargamma-posti" />
</div>
<div class="room-bookings">
<div class="seat-list">
<div class="seat">
<div class="name">Posto 1</div>
<button disabled>Prenotato</button>
</div>
<div class="seat">
<div class="name">Posto 2</div>
<button disabled>Prenotato</button>
</div>
<div class="seat">
<div class="name">Posto 3</div>
<button>Prenota</button>
</div>
<div class="seat">
<div class="name">Posto 4</div>
<button>Prenota</button>
</div>
<div class="seat">
<div class="name">Posto 5</div>
<button disabled>Prenotato</button>
</div>
<div class="seat">
<div class="name">Posto 6</div>
<button disabled>Prenotato</button>
</div>
<div class="seat">
<div class="name">Posto 7</div>
<button>Prenota</button>
</div>
<div class="seat">
<div class="name">Posto 8</div>
<button>Prenota</button>
</div>
<div class="seat">
<div class="name">Posto 9</div>
<button disabled>Prenotato</button>
</div>
<div class="seat">
<div class="name">Posto 10</div>
<button>Prenota</button>
</div>
</div>
</div>
</div>
</main>
</body>
</html>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,18 @@
{
"name": "client",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"sass": "^1.49.9",
"vite": "^2.8.6"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@ -0,0 +1 @@
import './style.scss'

@ -0,0 +1,74 @@
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
}
/* Remove default margin */
body,
h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd {
margin: 0;
}
/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
ul[role='list'],
ol[role='list'] {
list-style: none;
}
/* Set core root defaults */
html:focus-within {
scroll-behavior: smooth;
}
/* Set core body defaults */
body {
min-height: 100vh;
text-rendering: optimizeSpeed;
line-height: 1.5;
}
/* A elements that don't have a class get default styles */
a:not([class]) {
text-decoration-skip-ink: auto;
}
/* Make images easier to work with */
img,
picture {
max-width: 100%;
display: block;
}
/* Inherit fonts for inputs and buttons */
input,
button,
textarea,
select {
font: inherit;
}
/* Remove all animations, transitions and smooth scroll for people that prefer not to see them */
@media (prefers-reduced-motion: reduce) {
html:focus-within {
scroll-behavior: auto;
}
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}

@ -0,0 +1,119 @@
@use './reset.scss';
body {
background: #f0f0f0;
display: flex;
flex-direction: column;
align-items: center;
}
header {
width: 100%;
height: 3rem;
position: relative;
background: #fff;
border-bottom: 1px solid #ddd;
.nav-item {
height: 3rem;
display: flex;
align-items: center;
justify-content: center;
}
.left {
position: absolute;
left: 0;
padding-left: 1rem;
display: flex;
gap: 1rem;
}
.center {
position: absolute;
left: 50%;
transform: translate(-50%, 0);
display: flex;
gap: 1rem;
}
.right {
position: absolute;
right: 0;
padding-right: 1rem;
display: flex;
gap: 1rem;
}
}
main {
display: flex;
flex-direction: column;
gap: 2rem;
align-items: center;
padding: 2rem 1rem 2rem;
.room-name {
display: flex;
align-items: center;
justify-content: center;
font-size: 26px;
font-weight: bold;
}
.room-main {
display: flex;
flex-direction: row;
gap: 1rem;
@media screen and (max-width: 1000px) {
flex-direction: column;
}
.room-diagram {
display: flex;
flex-direction: column;
border: 1px solid #ddd;
background: #fff;
padding: 1rem;
}
.room-bookings {
display: flex;
flex-direction: column;
border: 1px solid #ddd;
background: #fff;
min-width: 15rem;
padding: 0.5rem;
.seat-list {
display: flex;
flex-direction: column;
gap: 0.5rem;
.seat {
display: grid;
grid-template-columns: 1fr auto;
}
}
}
}
}

@ -0,0 +1,128 @@
package auth
import (
"fmt"
"net/http"
"time"
)
var SessionCookieName = "session" // TODO: Make configurable
type AuthMiddlewareConfig struct {
IsLogged bool
WithPermissions []string
}
type Authenticator interface {
// Login adds a session cookie to the user
Login(w http.ResponseWriter, userID string)
// Logout clears the user session cookies (by setting the session cookie timeout to 0)
Logout(w http.ResponseWriter)
// Middleware is a configurable middleware to authenticate http routes based on logged status and permissions
Middleware(*AuthMiddlewareConfig) func(http.Handler) http.Handler
// LoggedMiddleware accepts all logged users without checking for specific permissions
LoggedMiddleware() func(http.Handler) http.Handler
// UserFromSession returns the userID for this cookie session token
UserFromSession(r http.Request) (string, error)
}
type AuthService struct {
// CheckUserPassword
CheckUserPassword func(userID string, password string) bool
// GetUserPermissions gets the list of permissions for this user
UserPermissions func(userID string) []string
// SessionTokenFromUser returns a session token that represents this user
SessionTokenFromUser func(userID string) string
// UserFromSessionToken returns the corresponing user for this session token
UserFromSessionToken func(session string) (string, bool)
// AuthenticationFailed handles failed authentications
AuthenticationFailed http.Handler
}
func (auth *AuthService) Login(w http.ResponseWriter, userID string) {
http.SetCookie(w, &http.Cookie{
Name: SessionCookieName,
Value: auth.SessionTokenFromUser(userID),
Expires: time.Now().Add(10 * time.Minute), // TODO: Make configurable
})
}
func (auth *AuthService) Logout(w http.ResponseWriter) {
http.SetCookie(w, &http.Cookie{
Name: SessionCookieName,
Value: "",
Expires: time.Now(),
})
}
func (auth *AuthService) Middleware(config *AuthMiddlewareConfig) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie(SessionCookieName)
if err == http.ErrNoCookie && !config.IsLogged {
next.ServeHTTP(w, r)
return
}
if err != nil {
auth.AuthenticationFailed.ServeHTTP(w, r)
return
}
userID, exists := auth.UserFromSessionToken(cookie.Value)
if !exists {
auth.Logout(w)
w.WriteHeader(http.StatusBadRequest)
return
}
if config.IsLogged {
userPerms := map[string]bool{}
for _, perm := range auth.UserPermissions(userID) {
userPerms[perm] = true
}
// check the user has all the permissions to access the route
hasAll := true
for _, perm := range config.WithPermissions {
if _, present := userPerms[perm]; !present {
hasAll = false
break
}
}
if !hasAll {
auth.AuthenticationFailed.ServeHTTP(w, r)
return
}
}
next.ServeHTTP(w, r)
})
}
}
func (auth *AuthService) LoggedMiddleware() func(http.Handler) http.Handler {
return auth.Middleware(&AuthMiddlewareConfig{
IsLogged: true,
WithPermissions: []string{},
})
}
func (auth *AuthService) UserFromSession(r http.Request) (string, error) {
cookie, err := r.Cookie(SessionCookieName)
if err != nil {
return "", err
}
userID, exists := auth.UserFromSessionToken(cookie.Value)
if !exists {
return "", fmt.Errorf(`no user for this session token`)
}
return userID, nil
}

@ -0,0 +1,50 @@
package db
// Entities
type Utente struct {
ID string
Username string
Permissions []string
}
type Stanza struct {
ID string
Posti []string
}
// Actions
type AzioneBase struct {
Tipo string
}
type AzioneStanza struct {
AzioneBase
UserID string
StanzaID string
}
type AzioneOccupaPosto struct {
AzioneStanza
PostoID string
}
type AzioneLiberaPosto struct {
AzioneStanza
PostoID string
}
// Database Interfaces
type Store interface {
// Entities
GetUtente(userID string) *Utente
GetStanza(stanzaID string) *Stanza
// Available Seats
GetPostiOccupati(stanzaID string) []string
GetPostiLiberi(stanzaID string) []string
}

@ -0,0 +1,7 @@
module git.phc.dm.unipi.it/aziis98/posti-dm/server
go 1.17
require github.com/go-chi/chi/v5 v5.0.7
require github.com/mattn/go-sqlite3 v1.14.12 // indirect

@ -0,0 +1,4 @@
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=

@ -0,0 +1,26 @@
package main
import (
"log"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
var HOST = ":3000"
func main() {
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
log.Printf(`Starting server on %s...`, HOST)
err := http.ListenAndServe(HOST, r)
if err != nil {
panic(err)
}
}
Loading…
Cancel
Save