Browse Source

List your own invites

merge-requests/9/head
meskio 3 years ago
parent
commit
a6bc5992e0
Signed by: meskio
GPG Key ID: 52B8F5AC97A2DA86
  1. 46
      db/invite.go
  2. 17
      db/invite_test.go
  3. 36
      server/add_user.go
  4. 2
      server/server.go
  5. 1
      server/template.go
  6. 36
      tmpl/invites.html
  7. 3
      tmpl/navbar.html

46
db/invite.go

@ -1,33 +1,43 @@
package db
import (
"encoding/json"
"log"
"time"
"go.etcd.io/bbolt"
)
var (
inviteBucket = []byte("invite")
)
type invite struct {
// Invite holds the data of an invite
type Invite struct {
Code string
CreationDate time.Time
}
type inviteValue struct {
User string
CreationDate time.Time
}
// AddInvite stores in the db the invite code generated by user
// AddInvite stores in the db the inviteValue code generated by user
func (db *DB) AddInvite(code string, user string) error {
return db.put(inviteBucket, code, invite{user, time.Now()})
return db.put(inviteBucket, code, inviteValue{user, time.Now()})
}
// IsInviteValid checks if the invite code is in the database
// IsInviteValid checks if the inviteValue code is in the database
func (db *DB) IsInviteValid(code string) bool {
var inv invite
var inv inviteValue
err := db.get(inviteBucket, code, &inv)
return err == nil
}
// InviteHost returns the user name that created the invite
// InviteHost returns the user name that created the inviteValue
func (db *DB) InviteHost(code string) (string, error) {
var inv invite
var inv inviteValue
err := db.get(inviteBucket, code, &inv)
return inv.User, err
}
@ -41,3 +51,25 @@ func (db *DB) DelInvite(code string) error {
func (db *DB) ExpireInvites(duration time.Duration) error {
return db.expire(inviteBucket, duration)
}
// ListUserInvites returns all the inviteValue codes generated by a user
func (db *DB) ListUserInvites(user string) ([]Invite, error) {
var invites []Invite
err := db.bolt.View(func(tx *bbolt.Tx) error {
b := tx.Bucket(inviteBucket)
return b.ForEach(func(k, v []byte) error {
var inv inviteValue
err := json.Unmarshal(v, &inv)
if err != nil {
log.Printf("Error unmarshalling invite %s: %v", string(k), err)
return nil
}
if inv.User == user {
invites = append(invites, Invite{string(k), inv.CreationDate})
}
return nil
})
})
return invites, err
}

17
db/invite_test.go

@ -54,3 +54,20 @@ func TestExpireInvites(t *testing.T) {
t.Errorf("Got valid invite after expiring it")
}
}
func TestListUserInvites(t *testing.T) {
db := initTestDB(t)
defer delTestDB(db)
err := db.AddInvite(code, "user")
if err != nil {
t.Fatalf("Got an error adding invite: %v", err)
}
invites, err := db.ListUserInvites("user")
if err != nil {
t.Fatalf("Got an error listing invites: %v", err)
}
if len(invites) != 1 && invites[0] != code {
t.Fatalf("Code not in list of user invites: %v", invites)
}
}

36
server/add_user.go

@ -61,6 +61,42 @@ func getReservedNames() map[string]bool {
}
}
func (s *server) listInvitesHandler(w http.ResponseWriter, r *http.Request) {
response := s.newResponse("invites", w, r)
invites, err := s.db.ListUserInvites(response.User)
if err != nil {
log.Printf("An error has ocurred listing invites: %v", err)
s.errorHandler(w, r)
return
}
response.execute(invites)
}
func (s *server) deleteInviteHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
invite := vars["invite"]
response := s.newResponse("invites", w, r)
user, err := s.db.InviteHost(invite)
if err != nil {
log.Printf("An error has ocurred getting invite: %v", err)
s.errorHandler(w, r)
return
}
if user != response.User {
log.Printf("No owner attemp to delete an invite, user: %s, invite: %s", response.User, invite)
s.forbiddenHandler(w, r)
return
}
err = s.db.DelInvite(invite)
if err != nil {
log.Printf("An error has ocurred deleting invite %s: %v", invite, err)
s.errorHandler(w, r)
return
}
http.Redirect(w, r, r.Referer(), http.StatusFound)
}
func (s *server) createInviteHandler(w http.ResponseWriter, r *http.Request) {
response := s.newResponse("invite", w, r)
if response.Role != ldap.Sindominante {

2
server/server.go

@ -44,6 +44,8 @@ func Serve(addr string, l *ldap.Ldap, m *mail.Mail, ldb *db.DB, usersAskRole []s
r.HandleFunc("/users/{name}/role/", s.roleHandler).Methods("POST")
r.HandleFunc("/users/{name}/password/", s.passwdadmHandler).Methods("POST")
r.HandleFunc("/users/{name}/shell/", s.shellHandler).Methods("POST")
r.HandleFunc("/invites/", s.listInvitesHandler)
r.HandleFunc("/invites/{invite}/del/", s.deleteInviteHandler)
r.HandleFunc("/adduser/", s.createInviteHandler)
r.HandleFunc("/adduser/{invite}", s.addUserHandler)
r.HandleFunc("/groups/", s.groupsHandler)

1
server/template.go

@ -36,6 +36,7 @@ func initTemplate() *template.Template {
"tmpl/user.html",
"tmpl/users.html",
"tmpl/invite.html",
"tmpl/invites.html",
"tmpl/adduser.html",
"tmpl/adduser_success.html",
"tmpl/group.html",

36
tmpl/invites.html

@ -0,0 +1,36 @@
{{template "header.html"}}
{{template "header_close.html"}}
{{template "navbar.html" .}}
<div class="container">
<br />
<h1 class="row justify-content-center">Lista de invitaciones pendientes</h1>
<br />
<div class="row justify-content-center">
<div class="col-md-8">
<p class="float-right"><a href="/adduser/">Invitar a una amiga</a></p>
<br />
<table class="table table-hover">
<thead>
<tr>
<th scope="col">code</th>
<th scope="col">date</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{{range .Data}}
<tr>
<th scope="row">{{.Code}}</th>
<td>{{.CreationDate}}</td>
<td><a href="/invites/{{.Code}}/del/"><button type="button" class="btn btn-danger">Eliminar</button></a></td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
{{template "footer.html"}}

3
tmpl/navbar.html

@ -16,6 +16,9 @@
</ul>
{{if eq (printf "%v" .Role) "sindominante"}}
<ul class="navbar-nav ml-mr-auto">
<li class="nav-item {{if eq .Section "invites"}}active{{end}}">
<a class="nav-link" href="/invites/">Invitaciones</a>
</li>
<li class="nav-item {{if eq .Section "adduser"}}active{{end}}">
<a class="nav-link" href="/adduser/">Invitar amiga</a>
</li>

Loading…
Cancel
Save