Aggiunte tante cose relative al profilo utente

main-old
Antonio De Lucreziis 2 years ago
parent 39ad130e81
commit 1d61efeda0

@ -4,32 +4,44 @@ import "fmt"
var ErrInvalidSession = fmt.Errorf(`invalid session token`) var ErrInvalidSession = fmt.Errorf(`invalid session token`)
type User interface { type User struct {
GetUsername() string Username string `json:"username"`
GetName() string Name string `json:"name"`
GetSurname() string Surname string `json:"surname"`
GetFullName() string FullName string `json:"fullName"`
Email string `json:"email"`
} }
type Session interface { func (u User) WithDefaultFullName() User {
GetUsername() string return User{
GetToken() string Username: u.Username,
Name: u.Name,
Surname: u.Surname,
Email: u.Email,
FullName: u.Username + " " + u.Surname,
}
}
type Session struct {
Username string `json:"username"`
Token string `json:"token"`
} }
type AuthenticatorService interface { type AuthenticatorService interface {
GetUser(username string) (User, error) GetUser(username string) (*User, error)
GetUsers() ([]User, error) GetUsers() ([]*User, error)
GetSession(token string) (Session, error) GetSession(token string) (*Session, error)
Login(username, password string) (Session, error) Login(username, password string) (*Session, error)
} }
func UserForSession(as AuthenticatorService, token string) (User, error) { func UserForSession(as AuthenticatorService, token string) (*User, error) {
session, err := as.GetSession(token) session, err := as.GetSession(token)
if err != nil { if err != nil {
return nil, err return nil, err
} }
user, err := as.GetUser(session.GetUsername()) user, err := as.GetUser(session.Username)
if err != nil { if err != nil {
return nil, err return nil, err
} }

@ -7,47 +7,24 @@ import (
"log" "log"
"net/http" "net/http"
"path" "path"
"time"
) )
type LDAPUser struct { type ldapUser struct {
Username string `json:"username"` User
NumericId int `json:"id"` NumericId int `json:"id"`
Name string `json:"name"`
Surname string `json:"surname"`
Email string `json:"email"`
Role string `json:"role"` Role string `json:"role"`
Gecos string `json:"gecos"` Gecos string `json:"gecos"`
} }
func (u LDAPUser) GetUsername() string { func (u ldapUser) AsUser() *User {
return u.Username return &User{
} Username: u.Username,
Name: u.Name,
func (u LDAPUser) GetName() string { Surname: u.Surname,
return u.Name Email: u.Email,
}
func (u LDAPUser) GetSurname() string {
return u.Surname
}
func (u LDAPUser) GetFullName() string {
return u.Gecos
}
type SimpleSession struct {
Token string `json:"token"`
Username string `json:"username"`
CreatedOn time.Time `json:"createdOn"`
}
func (s SimpleSession) GetUsername() string { FullName: u.Gecos,
return s.Username }
}
func (s SimpleSession) GetToken() string {
return s.Token
} }
type LDAPAuthService struct { type LDAPAuthService struct {
@ -99,31 +76,31 @@ func (a *LDAPAuthService) doPostRequest(url string, request interface{}, respons
return json.NewDecoder(res.Body).Decode(response) return json.NewDecoder(res.Body).Decode(response)
} }
func (a *LDAPAuthService) GetUser(username string) (User, error) { func (a *LDAPAuthService) GetUser(username string) (*User, error) {
var user LDAPUser var user ldapUser
if err := a.doGetRequest(fmt.Sprintf("/user/%s", username), &user); err != nil { if err := a.doGetRequest(fmt.Sprintf("/user/%s", username), &user); err != nil {
return nil, err return nil, err
} }
return &user, nil return user.AsUser(), nil
} }
func (a *LDAPAuthService) GetUsers() ([]User, error) { func (a *LDAPAuthService) GetUsers() ([]*User, error) {
ldapUsers := []*LDAPUser{} ldapUsers := []*ldapUser{}
if err := a.doGetRequest(fmt.Sprintf("/users"), &ldapUsers); err != nil { if err := a.doGetRequest(fmt.Sprintf("/users"), &ldapUsers); err != nil {
return nil, err return nil, err
} }
users := make([]User, len(ldapUsers)) users := make([]*User, len(ldapUsers))
for i, u := range ldapUsers { for i, u := range ldapUsers {
users[i] = u users[i] = u.AsUser()
} }
return users, nil return users, nil
} }
func (a *LDAPAuthService) GetSession(token string) (Session, error) { func (a *LDAPAuthService) GetSession(token string) (*Session, error) {
var response SimpleSession var response Session
if err := a.doGetRequest(fmt.Sprintf("/session/%s", token), &response); err != nil { if err := a.doGetRequest(fmt.Sprintf("/session/%s", token), &response); err != nil {
return nil, err return nil, err
} }
@ -131,14 +108,14 @@ func (a *LDAPAuthService) GetSession(token string) (Session, error) {
return &response, nil return &response, nil
} }
func (a *LDAPAuthService) Login(username, password string) (Session, error) { func (a *LDAPAuthService) Login(username, password string) (*Session, error) {
body := map[string]interface{}{ reqBody := map[string]interface{}{
"username": username, "username": username,
"password": password, "password": password,
} }
var response SimpleSession var response Session
if err := a.doPostRequest(fmt.Sprintf("/login"), body, &response); err != nil { if err := a.doPostRequest(fmt.Sprintf("/login"), reqBody, &response); err != nil {
return nil, err return nil, err
} }

@ -7,108 +7,102 @@ import (
) )
var exampleMemoryUsers = &Memory{ var exampleMemoryUsers = &Memory{
Users: map[string]*MemoryUser{ Users: map[string]*memoryUser{
"aziis98": { "aziis98": {
Username: "aziis98", User: User{
Name: "Antonio", Username: "aziis98",
Surname: "De Lucreziis", Name: "Antonio",
Surname: "De Lucreziis",
Email: "aziis98@example.org",
}.WithDefaultFullName(),
Password: "123", Password: "123",
}, },
"bachoseven": { "bachoseven": {
Username: "bachoseven", User: User{
Name: "Francesco", Username: "bachoseven",
Surname: "Minnocci", Name: "Francesco",
Surname: "Minnocci",
Email: "bachoseven@example.org",
}.WithDefaultFullName(),
Password: "234", Password: "234",
}, },
}, },
Sessions: map[string]*MemorySession{}, Sessions: map[string]*memorySession{},
} }
type MemoryUser struct { type memoryUser struct {
Username string `json:"username"` User
Name string `json:"name"`
Surname string `json:"surname"`
Password string `json:"-"` Password string `json:"-"`
} }
func (u *MemoryUser) GetUsername() string { func (u memoryUser) AsUser() *User {
return u.Username return &User{
} Username: u.Username,
Name: u.Name,
func (u *MemoryUser) GetName() string { Surname: u.Surname,
return u.Name FullName: u.FullName,
} Email: u.Email,
}
func (u *MemoryUser) GetSurname() string {
return u.Surname
}
func (u *MemoryUser) GetFullName() string {
return u.Name + " " + u.Surname
} }
type MemorySession struct { type memorySession struct {
Username string Username string
Token string Token string
} }
func (s *MemorySession) GetUsername() string { func (s memorySession) AsSession() *Session {
return s.Username return &Session{
} Username: s.Username,
Token: s.Token,
func (s *MemorySession) GetToken() string { }
return s.Token
} }
type Memory struct { type Memory struct {
Users map[string]*MemoryUser Users map[string]*memoryUser
Sessions map[string]*MemorySession Sessions map[string]*memorySession
} }
func (m *Memory) GetUser(username string) (User, error) { func (m *Memory) GetUser(username string) (*User, error) {
user, ok := m.Users[username] user, ok := m.Users[username]
if !ok { if !ok {
return nil, fmt.Errorf(`no user with that username`) return nil, fmt.Errorf(`no user with that username`)
} }
return user, nil return user.AsUser(), nil
} }
func (m *Memory) GetUsers() ([]User, error) { func (m *Memory) GetUsers() ([]*User, error) {
users := make([]User, len(m.Users)) users := make([]*User, len(m.Users))
i := 0 i := 0
for _, u := range m.Users { for _, u := range m.Users {
users[i] = u users[i] = u.AsUser()
i++ i++
} }
return users, nil return users, nil
} }
func (m *Memory) GetSession(token string) (Session, error) { func (m *Memory) GetSession(token string) (*Session, error) {
session, ok := m.Sessions[token] session, ok := m.Sessions[token]
if !ok { if !ok {
return nil, ErrInvalidSession return nil, ErrInvalidSession
} }
return session, nil return session.AsSession(), nil
} }
func (m *Memory) Login(username string, password string) (Session, error) { func (m *Memory) Login(username string, password string) (*Session, error) {
user, err := m.GetUser(username) user, ok := m.Users[username]
if err != nil { if !ok {
return nil, err return nil, fmt.Errorf(`no user with that username`)
} }
memUser := user.(*MemoryUser) if user.Password != password {
if memUser.Password != password {
return nil, fmt.Errorf(`invalid credentials`) return nil, fmt.Errorf(`invalid credentials`)
} }
session := &MemorySession{username, util.GenerateRandomString(15)} session := &memorySession{username, util.GenerateRandomString(15)}
m.Sessions[session.Token] = session m.Sessions[session.Token] = session
return session, nil return session.AsSession(), nil
} }

@ -1,14 +1,10 @@
JS_SOURCES = src/utenti.js JS_SOURCES = src/utenti.js src/profilo.js
JS_BUNDLES = $(patsubst src/%.js, dist/%.min.js, $(JS_SOURCES))
.PHONY: all .PHONY: all
all: $(JS_BUNDLES) all: $(JS_SOURCES)
rollup -c
dist/%.min.js: src/%.js
rollup -c rollup.config.js $<
.PHONY: debug .PHONY: debug
debug: debug:
@echo "JS_SOURCES = $(JS_SOURCES)" @echo "JS_SOURCES = $(JS_SOURCES)"
@echo "JS_BUNDLES = $(JS_BUNDLES)"

@ -1,6 +1,4 @@
import { defineConfig } from 'rollup' import { defineConfig } from 'rollup'
// import resolve from '@rollup/plugin-node-resolve'
import { terser } from 'rollup-plugin-terser' import { terser } from 'rollup-plugin-terser'
export default defineConfig([ export default defineConfig([
@ -16,9 +14,18 @@ export default defineConfig([
'fuse.js': 'Fuse', 'fuse.js': 'Fuse',
}, },
}, },
plugins: [ plugins: [terser()],
// resolve(), },
terser(), {
], input: 'src/profilo.js',
external: ['alpinejs'],
output: {
file: 'dist/profilo.min.js',
format: 'iife',
globals: {
alpinejs: 'Alpine',
},
},
plugins: [terser()],
}, },
]) ])

@ -0,0 +1,16 @@
import Alpine from 'alpinejs'
Alpine.data('profilo', () => ({
init() {
console.log('Profilo!')
},
}))
Alpine.data('passwordForm', () => ({
password: '',
passwordAgain: '',
passwordSame: true,
onUpdate() {
this.passwordSame = this.password === this.passwordAgain
},
}))

@ -81,6 +81,15 @@ func main() {
return c.JSON(utenti) return c.JSON(utenti)
}) })
app.Get("/api/profilo", func(c *fiber.Ctx) error {
user := c.Locals("user")
if user == nil {
return fmt.Errorf(`user not logged in`)
}
return c.JSON(user)
})
app.Get("/storia", func(c *fiber.Ctx) error { app.Get("/storia", func(c *fiber.Ctx) error {
storia, err := GetStoria() storia, err := GetStoria()
if err != nil { if err != nil {
@ -137,7 +146,7 @@ func main() {
c.Cookie(&fiber.Cookie{ c.Cookie(&fiber.Cookie{
Name: "session-token", Name: "session-token",
Path: "/", Path: "/",
Value: session.GetToken(), Value: session.Token,
Expires: inThreeDays, Expires: inThreeDays,
}) })
@ -145,7 +154,7 @@ func main() {
}) })
app.Get("/profilo", func(c *fiber.Ctx) error { app.Get("/profilo", func(c *fiber.Ctx) error {
user, ok := c.Locals("user").(auth.User) user, ok := c.Locals("user").(*auth.User)
if !ok || user == nil { if !ok || user == nil {
return fmt.Errorf(`user not logged in`) return fmt.Errorf(`user not logged in`)
} }

@ -29,6 +29,8 @@
--shadow-1: 0 0 16px 0 #00000018; --shadow-1: 0 0 16px 0 #00000018;
--text-input-bg: #fff; --text-input-bg: #fff;
--text-input-readonly-bg: #e4e4e4;
--text-input-readonly-fg: #777;
--bg-darker-2-1: #c8c8c8; --bg-darker-2-1: #c8c8c8;
--accent-2-lighter: #5cc969; --accent-2-lighter: #5cc969;
@ -401,11 +403,24 @@ li {
line-height: 1.8; line-height: 1.8;
} }
p + p {
padding-top: 0.5rem;
}
ul, ul,
ol { ol {
padding: 0 0 0 1.5rem; padding: 0 0 0 1.5rem;
} }
hr {
width: 50ch;
height: 1px;
margin: 0;
border: none;
background-color: var(--bg-darker-2);
}
pre { pre {
margin: 0.5rem 0; margin: 0.5rem 0;
@ -431,21 +446,27 @@ p.center {
/* Controls */ /* Controls */
a { a:not(.button) {
color: var(--accent-1-fg); color: var(--accent-1-fg);
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium);
text-decoration: none; text-decoration: none;
} }
a:hover { a:not(.button):hover {
color: var(--accent-1); color: var(--accent-1);
text-decoration: underline; text-decoration: underline;
} }
a.button {
text-decoration: none;
}
/* Buttons */ /* Buttons */
button, button,
.button { .button {
display: inline-block;
font-family: var(--font-sf); font-family: var(--font-sf);
font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium);
font-size: 17px; font-size: 17px;
@ -544,6 +565,19 @@ input[type='password'] {
font-family: caption; font-family: caption;
} }
input[type='text']:read-only,
input[type='password']:read-only {
background: var(--text-input-readonly-bg);
color: var(--text-input-readonly-fg);
box-shadow: 0 0 8px 0 #00000010;
}
input[type='text'].error,
input[type='password'].error {
background: #faa;
color: #311;
}
/* Compound Controls */ /* Compound Controls */
.compound { .compound {
@ -617,10 +651,16 @@ form .field-set {
padding: 1rem; padding: 1rem;
} }
form .field-set .fill {
grid-column: 1 / span 2;
}
form .field-set label { form .field-set label {
grid-column: 1 / 2; grid-column: 1 / 2;
align-self: center; align-self: center;
justify-self: end; justify-self: end;
font-weight: var(--font-weight-medium);
} }
form .field-set input { form .field-set input {

@ -1,4 +1,3 @@
body.dark-mode { body.dark-mode {
--bg: #282828; --bg: #282828;
--fg: #a6cc92; --fg: #a6cc92;
@ -24,8 +23,10 @@ body.dark-mode {
--font-weight-bold: 700; --font-weight-bold: 700;
--shadow-1: 0 0 16px 0 #16182077; --shadow-1: 0 0 16px 0 #16182077;
--text-input-bg: var(--bg-darker); --text-input-bg: var(--bg-darker);
--text-input-readonly-bg: hsl(10, 10%, 22%);
--text-input-readonly-fg: hsl(10, 10%, 40%);
--bg-darker-2-1: #c8c8c8; --bg-darker-2-1: #c8c8c8;
--accent-2-lighter: #5cc969; --accent-2-lighter: #5cc969;
@ -62,6 +63,19 @@ body.dark-mode {
background: #4b4342; background: #4b4342;
} }
.dark-mode input[type='text']:read-only,
.dark-mode input[type='password']:read-only {
background: var(--text-input-readonly-bg);
color: var(--text-input-readonly-fg);
box-shadow: 0 0 8px 0 #00000010;
}
.dark-mode input[type='text'].error,
.dark-mode input[type='password'].error {
background: #633;
color: #faa;
}
.dark-mode pre { .dark-mode pre {
background: var(--bg-darker); background: var(--bg-darker);
border: 1px solid var(--bg-darker-2); border: 1px solid var(--bg-darker-2);
@ -72,6 +86,7 @@ body.dark-mode {
filter: invert(1); filter: invert(1);
} }
.dark-mode table td, .dark-mode table th { .dark-mode table td,
.dark-mode table th {
border-color: var(--fg); border-color: var(--fg);
} }

@ -88,10 +88,12 @@
</div> </div>
</div> </div>
</section> </section>
<hr>
<section> <section>
<!-- <h2>Altro...</h2> -->
<div class="card"> <div class="card">
<div class="title">Vuoi diventare un macchinista?</div> <div class="title">Vuoi diventare un macchinista?</div>
<!-- <h3 style="font-weight: 500;">Vuoi diventare un macchinista?</h3> -->
<div class="description"> <div class="description">
<p> <p>
Ti interessa (o interesserebbe) smanettare al PC, montare e smontare i cose? Stai spesso in dipartimento? Allora Ti interessa (o interesserebbe) smanettare al PC, montare e smontare i cose? Stai spesso in dipartimento? Allora

@ -1,20 +1,105 @@
{{template "base" .}} {{template "base" .}}
{{define "title"}}Profilo di @{{ .User.Username }} &bull; PHC{{end}}
{{define "title"}}Profilo @{{ .User.Username }} &bull; PHC{{end}}
{{define "body"}} {{define "body"}}
<section> <script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script src="/public/js/profilo.min.js"></script>
<section x-data="profilo">
<h1>Profilo di @{{ .User.Username }}</h1> <h1>Profilo di @{{ .User.Username }}</h1>
<h2>Impostazioni</h2>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quae earum amet delectus cumque obcaecati minus quos aliquid fugiat reprehenderit voluptatum?
</p>
<p class="center"> <p class="center">
<a href="/logout">Logout</a> <a class="button" href="/logout">Logout</a>
</p> </p>
</section>
<section>
<h2>Appunti e Dispense</h2>
<p>
Per gestire i tuoi appunti e le tue dispense caricate nella sezione <a href="/appunti">Appunti</a> del sito vai
<a href="/appunti/condivisi">alla pagina appunti condivisi</a>.
</p>
</section>
<section>
<h2>Impostazioni</h2>
<div class="card-list">
<form class="card" action="/profile/impostazioni" method="POST">
<div class="title">
Sito PHC
</div>
<p>
Aggiorna i campi relativi al sito del PHC, l'immagine del profilo verrà visualizzata sulla tua pagina utente <a href="#">phc.dm.unipi.it/u/{{ .User.Username }}</a> e nella lista di <a href="/utenti">tutti gli utenti</a>.
</p>
<div class="field-set">
<label for="website-nickname">Nickname</label>
<input type="text" name="nickname" id="website-nickname" placeholder="{{ .User.Username }}">
<label for="website-profile-picture">Immagine Profilo</label>
<input type="file" name="picture" id="website-profile-picture">
</div>
<p>
Puoi anche aggiungere link ad altri tuoi profili su siti esterni (quando riempi l'ultimo campo se ne crea uno nuovo sotto)
</p>
<div class="field-set">
<label for="website-link-1">Link 1</label>
<input type="text" name="link" id="website-link-1"
placeholder="https://github.com/...">
<label for="website-link-2">Link 2</label>
<input type="text" name="link" id="website-link-2"
placeholder="https://twitter.com/...">
<label for="website-link-3">Link 3</label>
<input type="text" name="link" id="website-link-3"
placeholder="https://news.ycombinator.com/user?id=...">
</div>
<div class="field">
<button class="primary">Aggiorna</button>
</div>
</form>
<form class="card" action="/profile/impostazioni" method="POST">
<div class="title">
Informazioni Utente
</div>
<p>
Aggiorna i campi modificabili dell'account Poisson
</p>
<div class="field-set">
<label for="user-username">Username</label>
<input type="text" readonly name="username" id="user-username" value="{{ .User.Username }}">
<label for="user-name">Nome</label>
<input type="text" readonly name="name" id="user-name" value="{{ .User.Name }}">
<label for="user-surname">Cognome</label>
<input type="text" readonly name="surname" id="user-surname" value="{{ .User.Surname }}">
<label for="user-email">Email</label>
<input type="text" readonly name="email" id="user-email" value="{{ .User.Email }}">
</div>
<div class="field">
<button class="primary">Aggiorna</button>
</div>
</form>
<form x-data="passwordForm" class="card" action="/profile/impostazioni" method="POST">
<div class="title">
Modifica Password
</div>
<p>
Aggiorna la password di Poisson
</p>
<div class="field-set">
<label for="pass-username">Username</label>
<input type="text" readonly name="username" id="pass-username" value="{{ .User.Username }}">
<label for="pass-password">Password</label>
<input type="password" name="password" id="pass-password" :class="!passwordSame ? 'error' : ''"
x-model="password" @input="onUpdate" placeholder="In realtà anche questo non funge...">
<label for="pass-password-2">Ripeti Password</label>
<input type="password" name="password-2" id="pass-password-2" :class="!passwordSame ? 'error' : ''"
x-model="passwordAgain" @input="onUpdate" placeholder="In realtà anche questo non funge...">
</div>
<div class="field">
<button class="primary">Aggiorna Password</button>
</div>
</form>
</div>
</section>
<section>
<h2>Recupero Credenziali Poisson</h2> <h2>Recupero Credenziali Poisson</h2>
<p> <p>
Per il recupero credenziali vieni direttamente al PHC a parlarne con calma con noi altrimenti puoi inviaci una email all'indirizzo <a href="mailto:{{ .Config.Email }}">{{ .Config.Email }}</a> e poi recuperare le nuove credenziali sul sito <a href="https://credenziali.phc.dm.unipi.it/">credenziali.phc.dm.unipi.it</a>. Per il recupero credenziali vieni direttamente al PHC a parlarne con calma con noi altrimenti puoi inviaci una email
all'indirizzo <a href="mailto:{{ .Config.Email }}">{{ .Config.Email }}</a> e poi recuperare le nuove credenziali sul
sito <a href="https://credenziali.phc.dm.unipi.it/">credenziali.phc.dm.unipi.it</a>.
</p> </p>
</section> </section>
{{end}} {{end}}
Loading…
Cancel
Save