Compare commits
16 Commits
Author | SHA1 | Date |
---|---|---|
|
12687ba08c | 3 years ago |
|
1430c57423 | 3 years ago |
|
1682cdca81 | 3 years ago |
|
7387307ad9 | 3 years ago |
|
6d4c742d4c | 3 years ago |
|
3d10f70d71 | 3 years ago |
|
44ffecbdd2 | 3 years ago |
|
f670c78337 | 3 years ago |
|
d5aa7c0ba2 | 3 years ago |
|
2a76e0621b | 3 years ago |
|
35d42b8316 | 3 years ago |
|
10704d946f | 3 years ago |
|
ff0e0a5dcc | 3 years ago |
|
1495a5e45b | 3 years ago |
|
a970cea91a | 3 years ago |
|
fb2db34a9b | 3 years ago |
@ -0,0 +1,178 @@
|
|||||||
|
<!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>
|
||||||
|
|
||||||
|
<link href="https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
<div class="nav-group left">
|
||||||
|
<div class="nav-item" id="clock">14:23</div>
|
||||||
|
</div>
|
||||||
|
<div class="nav-group center">
|
||||||
|
<div class="nav-item">
|
||||||
|
<a href="/">Posti DM</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<a href="/stanze">Stanze</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nav-group right">
|
||||||
|
<div id="login-label" class="nav-item">
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
</div>
|
||||||
|
<div id="logged-label" class="nav-item hidden">
|
||||||
|
<!-- @username -->
|
||||||
|
</div>
|
||||||
|
<div id="logout-label" class="nav-item hidden">
|
||||||
|
<button id="logout-button">Logout</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<main>
|
||||||
|
<div id="orari-time-table" class="time-table">
|
||||||
|
<div class="controls">
|
||||||
|
<div class="current-range">Settimana, 21 Marzo — 27 Marzo</div>
|
||||||
|
<div class="group">
|
||||||
|
<div class="previous">
|
||||||
|
<button class="square">
|
||||||
|
<i class="bx bx-chevron-left bx-sm"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="today">
|
||||||
|
<button class="square">
|
||||||
|
<i class="bx bxs-home"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="next">
|
||||||
|
<button class="square">
|
||||||
|
<i class="bx bx-chevron-right bx-sm"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="weekly">
|
||||||
|
<div class="day">
|
||||||
|
<div class="title">Lun 21</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">8:30 – 11:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">11:00 – 13:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">13:30 – 16:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">16:00 – 19:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="day">
|
||||||
|
<div class="title">Mar 21</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">8:30 – 11:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">11:00 – 13:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">13:30 – 16:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">16:00 – 19:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="day">
|
||||||
|
<div class="title">Mer 21</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">8:30 – 11:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">11:00 – 13:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">13:30 – 16:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">16:00 – 19:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="day">
|
||||||
|
<div class="title">Gio 21</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">8:30 – 11:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">11:00 – 13:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">13:30 – 16:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">16:00 – 19:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="day">
|
||||||
|
<div class="title">Ven 21</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">8:30 – 11:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">11:00 – 13:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">13:30 – 16:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">16:00 – 19:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="day">
|
||||||
|
<div class="title">Sab 21</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">8:30 – 11:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">11:00 – 13:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">13:30 – 16:00</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
<div class="slot">
|
||||||
|
<div class="range">16:00 – 19:30</div>
|
||||||
|
<div class="counter">100/100</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<script type="module" src="./src/pages/orari.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,44 @@
|
|||||||
|
<!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>
|
||||||
|
|
||||||
|
<link href="https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
<div class="nav-group left">
|
||||||
|
<div class="nav-item" id="clock">14:23</div>
|
||||||
|
</div>
|
||||||
|
<div class="nav-group center">
|
||||||
|
<div class="nav-item">
|
||||||
|
<a href="/">Posti DM</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<a href="/stanze">Stanze</a>
|
||||||
|
</div>
|
||||||
|
<div class="nav-item">
|
||||||
|
<a href="/orari">Orari</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nav-group right">
|
||||||
|
<div id="login-label" class="nav-item">
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
</div>
|
||||||
|
<div id="logged-label" class="nav-item hidden">
|
||||||
|
<!-- @username -->
|
||||||
|
</div>
|
||||||
|
<div id="logout-label" class="nav-item hidden">
|
||||||
|
<button id="logout-button">Logout</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<main>
|
||||||
|
<p>Prenota</p>
|
||||||
|
</main>
|
||||||
|
<script type="module" src="./src/pages/prenota.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,117 @@
|
|||||||
|
import './style.scss'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `BASE_URL` string from environment file without final slash (for more readable interpolated strings)
|
||||||
|
*/
|
||||||
|
export const BASE_URL = import.meta.env.BASE_URL.replace(/\/$/, '')
|
||||||
|
|
||||||
|
//
|
||||||
|
// User
|
||||||
|
//
|
||||||
|
|
||||||
|
const NotCached = Symbol('not cached')
|
||||||
|
let userSession = NotCached
|
||||||
|
|
||||||
|
export const User = {
|
||||||
|
async getLogged() {
|
||||||
|
if (userSession === NotCached) {
|
||||||
|
console.log('Caching user data...')
|
||||||
|
|
||||||
|
const res = await fetch(`${BASE_URL}/api/user`)
|
||||||
|
const user = await res.json()
|
||||||
|
|
||||||
|
userSession = user
|
||||||
|
}
|
||||||
|
|
||||||
|
return userSession
|
||||||
|
},
|
||||||
|
async login(username, password) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${BASE_URL}/api/login`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json, text/plain, */*',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ username, password }),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return { error: await response.text() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// If successful redirect to homepage
|
||||||
|
location.href = `${BASE_URL}/`
|
||||||
|
} catch (e) {
|
||||||
|
return { error: e }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async logout() {
|
||||||
|
await fetch(`${BASE_URL}/api/logout`, { method: 'POST' })
|
||||||
|
location.href = `${BASE_URL}/`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Room Event Source
|
||||||
|
//
|
||||||
|
|
||||||
|
export function createRoomEventStream(roomId) {
|
||||||
|
return new EventSource(`${BASE_URL}/api/room_events?id=${roomId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Database
|
||||||
|
//
|
||||||
|
|
||||||
|
export const Database = {
|
||||||
|
async getSeats(roomId) {
|
||||||
|
const seatList = await (await fetch(`${BASE_URL}/api/room/seats?id=${roomId}`)).json()
|
||||||
|
const seats = {}
|
||||||
|
|
||||||
|
seatList.forEach(seat => {
|
||||||
|
seats[seat.id] = seat
|
||||||
|
})
|
||||||
|
|
||||||
|
return seats
|
||||||
|
},
|
||||||
|
async occupySeat(seatId) {
|
||||||
|
const response = await fetch(`${BASE_URL}/api/seat/occupy?id=${seatId}`, {
|
||||||
|
method: 'POST',
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(await response.text())
|
||||||
|
}
|
||||||
|
|
||||||
|
await response.json()
|
||||||
|
},
|
||||||
|
async leaveSeat(seatId) {
|
||||||
|
const response = await fetch(`${BASE_URL}/api/seat/leave?id=${seatId}`, {
|
||||||
|
method: 'POST',
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(await response.text())
|
||||||
|
}
|
||||||
|
|
||||||
|
await response.json()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fix page links
|
||||||
|
//
|
||||||
|
|
||||||
|
// TODO: It might actually be better to just create a <page-link> custom element
|
||||||
|
// Always append BASE_URL to all <a> links in the page (in development mode links should point to html files)
|
||||||
|
document.querySelectorAll('a').forEach($a => {
|
||||||
|
const url = $a.getAttribute('href')
|
||||||
|
let newUrl = BASE_URL + url
|
||||||
|
|
||||||
|
if (import.meta.env.MODE === 'development') {
|
||||||
|
newUrl += newUrl.endsWith('/') ? 'index.html' : '.html'
|
||||||
|
}
|
||||||
|
|
||||||
|
$a.href = newUrl
|
||||||
|
})
|
@ -0,0 +1,40 @@
|
|||||||
|
import { User } from '../common.js'
|
||||||
|
|
||||||
|
function elements(el) {
|
||||||
|
return {
|
||||||
|
elLoggedLabel: el.querySelector('.logged-label'),
|
||||||
|
elLoginLabel: el.querySelector('.login-label'),
|
||||||
|
elLogoutLabel: el.querySelector('.logout-label'),
|
||||||
|
elLogoutButton: el.querySelector('.logout-button'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup(el) {
|
||||||
|
const { elLogoutButton } = elements(el)
|
||||||
|
|
||||||
|
elLogoutButton.addEventListener('click', () => User.logout())
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(el, { user }) {
|
||||||
|
const { elLoggedLabel, elLoginLabel, elLogoutLabel } = elements(el)
|
||||||
|
|
||||||
|
elLoginLabel.classList.toggle('hidden', user)
|
||||||
|
|
||||||
|
const roleString =
|
||||||
|
user && user.permissions.length > 0 ? ` (${user.permissions.join(', ')})` : ''
|
||||||
|
|
||||||
|
elLoggedLabel.innerText = user ? `@${user.id}${roleString}` : ''
|
||||||
|
|
||||||
|
elLoggedLabel.classList.toggle('hidden', !user)
|
||||||
|
elLogoutLabel.classList.toggle('hidden', !user)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createNavUser(el) {
|
||||||
|
setup(el)
|
||||||
|
|
||||||
|
// Load current user
|
||||||
|
;(async () => {
|
||||||
|
const user = await User.getLogged()
|
||||||
|
update(el, { user })
|
||||||
|
})()
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
import { BASE_URL, Database } from '../common'
|
||||||
|
|
||||||
|
export function createTimeTable(el) {}
|
@ -1,52 +0,0 @@
|
|||||||
import './style.scss'
|
|
||||||
|
|
||||||
export const BASE_URL = import.meta.env.BASE_URL.replace(/\/$/, '')
|
|
||||||
|
|
||||||
let USER = false
|
|
||||||
export async function getLoggedUser() {
|
|
||||||
if (USER === false) {
|
|
||||||
console.log('Caching user data...')
|
|
||||||
USER = await (await fetch(`${BASE_URL}/api/user`)).json()
|
|
||||||
}
|
|
||||||
|
|
||||||
return USER
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createRoomEventStream(roomId) {
|
|
||||||
return new EventSource(`${BASE_URL}/api/room_events?id=${roomId}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Database = {
|
|
||||||
async getSeats(roomId) {
|
|
||||||
const seatList = await (await fetch(`${BASE_URL}/api/room/seats?id=${roomId}`)).json()
|
|
||||||
const seats = {}
|
|
||||||
|
|
||||||
seatList.forEach(seat => {
|
|
||||||
seats[seat.id] = seat
|
|
||||||
})
|
|
||||||
|
|
||||||
return seats
|
|
||||||
},
|
|
||||||
async occupySeat(seatId) {
|
|
||||||
const response = await fetch(`${BASE_URL}/api/seat/occupy?id=${seatId}`, {
|
|
||||||
method: 'POST',
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(await response.text())
|
|
||||||
}
|
|
||||||
|
|
||||||
await response.json()
|
|
||||||
},
|
|
||||||
async leaveSeat(seatId) {
|
|
||||||
const response = await fetch(`${BASE_URL}/api/seat/leave?id=${seatId}`, {
|
|
||||||
method: 'POST',
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(await response.text())
|
|
||||||
}
|
|
||||||
|
|
||||||
await response.json()
|
|
||||||
},
|
|
||||||
}
|
|
@ -0,0 +1,10 @@
|
|||||||
|
import '../common'
|
||||||
|
import { createTimeTable } from '../components/time-table.js'
|
||||||
|
|
||||||
|
const elTimeTable = document.querySelector('#orari-time-table')
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
createTimeTable(elTimeTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
@ -0,0 +1,7 @@
|
|||||||
|
import '../common.js'
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// TODO: ...
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
@ -0,0 +1,111 @@
|
|||||||
|
//
|
||||||
|
// Prelude
|
||||||
|
//
|
||||||
|
|
||||||
|
type Natural = number
|
||||||
|
type Integer = number
|
||||||
|
type Rational = [number, number]
|
||||||
|
type Real = number
|
||||||
|
|
||||||
|
type Datetime = string
|
||||||
|
type Time = string
|
||||||
|
|
||||||
|
type Maybe<T> = { present: false } | { present: true; value: T }
|
||||||
|
|
||||||
|
//
|
||||||
|
// PostiDM
|
||||||
|
//
|
||||||
|
|
||||||
|
type UserID = string
|
||||||
|
type BookingID = string
|
||||||
|
type SlotID = string
|
||||||
|
type SeatID = string
|
||||||
|
type RoomID = string
|
||||||
|
|
||||||
|
type UserPermission = 'basic' | 'helper' | 'moderator' | 'admin'
|
||||||
|
|
||||||
|
type PostiDM = {
|
||||||
|
users: Map<UserID, User>
|
||||||
|
rooms: Map<RoomID, Room>
|
||||||
|
seats: Map<SeatID, Seat>
|
||||||
|
|
||||||
|
slots: Map<SlotID, Slot>
|
||||||
|
getCurrentWeekSlots(): Slot[]
|
||||||
|
|
||||||
|
bookings: Map<BookingID, Booking>
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Tutte le funzioni "getCurrentSomething()" in realtà sono da pensare meglio in modo da poter passare un range temporale o qualcosa del genere
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Un utente loggato con credenziali di ateneo
|
||||||
|
*/
|
||||||
|
type User = {
|
||||||
|
id: UserID
|
||||||
|
permissions: Set<UserPermission>
|
||||||
|
|
||||||
|
getBookings(): Booking[]
|
||||||
|
getCurrentSeat(): Maybe<Seat>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Una prenotazione di un utente per un certo slot orario
|
||||||
|
*/
|
||||||
|
type Booking = {
|
||||||
|
id: BookingID
|
||||||
|
timestamp: Datetime
|
||||||
|
slotID: SlotID
|
||||||
|
userID: UserID // cioè ok c'è User.bookings però pensando in SQL è sempre meglio avere comunque un id qui (forse)
|
||||||
|
|
||||||
|
getSlot(): Slot // giusto per comodità per parlare direttamente dell'oggetto "Slot" relativo ad un "Booking"
|
||||||
|
getSeat(): Seat // ".getSlot().getSeat()"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Slot rappresenta uno slot orario prenotabile per un certo posto
|
||||||
|
*/
|
||||||
|
type Slot = {
|
||||||
|
id: SlotID
|
||||||
|
seatID: SeatID
|
||||||
|
// Magari invece di eliminare uno slot, in quanto ricrearlo potrebbe essere complicato e forse è meglio che i moderatori semplicemente disabilitino uno slot se vogliono non renderlo prenotabile (?)
|
||||||
|
// disabled: boolean
|
||||||
|
range: {
|
||||||
|
from: Datetime
|
||||||
|
to: Datetime
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentBooking(): Maybe<Booking>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seat rappresenta un posto in dipartimento in una certa stanza
|
||||||
|
*/
|
||||||
|
type Seat = {
|
||||||
|
id: SeatID
|
||||||
|
diagram: {
|
||||||
|
x: Natural
|
||||||
|
y: Natural
|
||||||
|
width: Natural
|
||||||
|
height: Natural
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Forse per ora è meglio fare che più utenti possono prenotare lo stesso posto così inizialmente possiamo fare che in ogni stanza c'è solo un posto e la gente può prenotarsi solo "alla stanza" e non al posto specifico, altrimenti facciamo "getCurrentBookedUser(): Maybe<User>"
|
||||||
|
getCurrentlyBookedUsers(): User[]
|
||||||
|
getRoom(): Room
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Room rappresenta una stanza in dipartimento e contiene dei posti
|
||||||
|
*/
|
||||||
|
type Room = {
|
||||||
|
id: RoomID
|
||||||
|
name: string
|
||||||
|
diagram: {
|
||||||
|
gridRows: Natural
|
||||||
|
gridCols: Natural
|
||||||
|
}
|
||||||
|
|
||||||
|
getSeats(): Seat[]
|
||||||
|
getTotalSeatCount(): Natural // ".seatIDs.length"
|
||||||
|
getCurrentBookedSeatCount(): Natural
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.phc.dm.unipi.it/aziis98/posti-dm/server/auth"
|
||||||
|
"git.phc.dm.unipi.it/aziis98/posti-dm/server/db"
|
||||||
|
"git.phc.dm.unipi.it/aziis98/posti-dm/server/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// simpleAuthenticator holds an in memory map of session tokens and a reference to the main database interface
|
||||||
|
type simpleAuthenticator struct {
|
||||||
|
// sessions is a map from a sessionToken to userID
|
||||||
|
sessions map[string]string
|
||||||
|
database db.Database
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service *simpleAuthenticator) CheckUserPassword(userID, password string) error {
|
||||||
|
if password != "phc" {
|
||||||
|
return fmt.Errorf(`invalid password`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: al momento quando la password è giusta creiamo tutti gli account necessari
|
||||||
|
err := service.database.CreateUser(&db.User{
|
||||||
|
ID: userID,
|
||||||
|
Permissions: make(util.Set[string]),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(`got "%v" while trying to log as @%s`, err, userID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service *simpleAuthenticator) UserPermissions(userID string) ([]string, error) {
|
||||||
|
user, err := service.database.GetUser(userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.Permissions.Elements(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service *simpleAuthenticator) SessionTokenFromUser(userID string) (string, error) {
|
||||||
|
user, err := service.database.GetUser(userID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := util.RandomHash(20)
|
||||||
|
service.sessions[token] = user.ID
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service *simpleAuthenticator) UserFromSessionToken(session string) (*db.User, error) {
|
||||||
|
userID, present := service.sessions[session]
|
||||||
|
if !present {
|
||||||
|
return nil, auth.ErrNoUserForSession
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := service.database.GetUser(userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service *simpleAuthenticator) AuthenticationFailed(err error) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (service *simpleAuthenticator) OtherError(err error) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue