Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
svera committed Nov 3, 2023
1 parent 2722bdc commit 214120e
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 20 deletions.
10 changes: 3 additions & 7 deletions internal/controller/auth.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controller

import (
"errors"
"fmt"
"net/mail"
"strings"
Expand Down Expand Up @@ -97,11 +98,8 @@ func (a *Auth) SignIn(c *fiber.Ctx) error {

// If username or password are incorrect, do not allow access.
user, err = a.repository.FindByEmail(c.FormValue("email"))
if err != nil {
return fiber.ErrInternalServerError
}

if user.Password != model.Hash(c.FormValue("password")) {
if errors.Is(err, gorm.ErrRecordNotFound) || user.Password != model.Hash(c.FormValue("password")) {
return c.Status(fiber.StatusUnauthorized).Render("auth/login", fiber.Map{
"Title": "Login",
"Error": "Wrong email or password",
Expand All @@ -111,9 +109,7 @@ func (a *Auth) SignIn(c *fiber.Ctx) error {
// Send back JWT as a cookie.
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"userdata": model.User{
Model: gorm.Model{
ID: user.ID,
},
ID: user.ID,
Name: user.Name,
Email: user.Email,
Role: user.Role,
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/highlights.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (h *Highlights) Highlights(c *fiber.Ctx) error {

user, err := h.usrRepository.FindByUuid(c.Params("uuid"))
if err != nil {
return fiber.ErrBadRequest
return fiber.ErrNotFound
}

highlights, err := h.hlRepository.Highlights(int(user.ID), page, model.ResultsPerPage)
Expand Down
17 changes: 17 additions & 0 deletions internal/infrastructure/sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ func Connect(path string, wordsPerMinute float64) *gorm.DB {
log.Printf("Created database at %s\n", path)
}

// Use the following line to connect whe
//db, err := gorm.Open(sqlite.Open(fmt.Sprintf("%s?_pragma=foreign_keys(1)", path)), &gorm.Config{})
db, err := gorm.Open(sqlite.Open(path), &gorm.Config{})
if err != nil {
log.Fatal(err)
Expand All @@ -27,6 +29,21 @@ func Connect(path string, wordsPerMinute float64) *gorm.DB {
if err := db.AutoMigrate(&model.User{}, &model.Highlight{}); err != nil {
log.Fatal(err)
}
// The next block is temporary, used to add constraints to an en existing highlights table
// Remove when the new format is established
if !db.Migrator().HasConstraint(&model.User{}, "Highlights") {
err := db.Migrator().CreateConstraint(&model.User{}, "Highlights")
if err != nil {
log.Fatal(err)
}
err = db.Migrator().CreateConstraint(&model.User{}, "fk_users_highlights")
if err != nil {
log.Fatal(err)
}
}
if res := db.Exec("PRAGMA foreign_keys(1)", nil); res.Error != nil {
log.Fatal(err)
}
addDefaultAdmin(db, wordsPerMinute)
return db
}
Expand Down
8 changes: 4 additions & 4 deletions internal/model/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package model
import (
"net/mail"
"time"

"gorm.io/gorm"
)

const (
Expand All @@ -13,7 +11,9 @@ const (
)

type User struct {
gorm.Model
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
Uuid string `gorm:"uniqueIndex"`
Name string
Email string `gorm:"uniqueIndex"`
Expand All @@ -23,7 +23,7 @@ type User struct {
WordsPerMinute float64
RecoveryUUID string
RecoveryValidUntil time.Time
Highlights []Highlight
Highlights []Highlight `gorm:"constraint:OnDelete:CASCADE;"`
}

// Validate checks all user's fields to ensure they are in the required format
Expand Down
9 changes: 2 additions & 7 deletions internal/model/user_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,8 @@ func Hash(s string) string {

func (u *UserRepository) find(field, value string) (User, error) {
var (
err error
user User
)
result := u.DB.Limit(1).Where(fmt.Sprintf("%s = ?", field), value).Find(&user)
if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
err = result.Error
log.Printf("error retrieving user: %s\n", result.Error)
}
return user, err
result := u.DB.Where(fmt.Sprintf("%s = ?", field), value).First(&user)
return user, result.Error
}
1 change: 1 addition & 0 deletions internal/webserver/embedded/translations/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,4 @@
"%s highlights": "Destacados de %s"
"Remove from highlights": "Quitar de destacados"
"%d highlighted documents": "%d documentos destacados"
"Method not allowed": "Método no permitido"
1 change: 1 addition & 0 deletions internal/webserver/embedded/translations/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,4 @@
"%s highlights": "Favoris du %s"
"Remove from highlights": "Retirer des favoris"
"%d highlighted documents": "%d documents favoris"
"Method not allowed": "Méthode Non Autorisée"
3 changes: 3 additions & 0 deletions internal/webserver/embedded/views/errors/405.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="px-4 py-5 my-5 text-center">
<h2>{{t .Lang "Method not allowed"}}</h2>
</div>
69 changes: 69 additions & 0 deletions internal/webserver/highlights_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,25 @@ func TestHighlights(t *testing.T) {
adminUser := model.User{}
db.Where("email = ?", "[email protected]").First(&adminUser)

regularUserData := url.Values{
"name": {"Test user"},
"email": {"[email protected]"},
"password": {"test"},
"confirm-password": {"test"},
"role": {fmt.Sprint(model.RoleRegular)},
"words-per-minute": {"250"},
}

adminCookie, err := login(app, "[email protected]", "admin")
if err != nil {
t.Fatalf("Unexpected error: %v", err.Error())
}

response, err := addUser(regularUserData, adminCookie, app)
if response == nil {
t.Fatalf("Unexpected error: %v", err.Error())
}

t.Run("Try to highlight a document without an active session", func(t *testing.T) {
response, err := highlight(&http.Cookie{}, app, strings.NewReader(data.Encode()), fiber.MethodPost)
if err != nil {
Expand Down Expand Up @@ -56,6 +70,46 @@ func TestHighlights(t *testing.T) {

assertHighlights(app, t, adminCookie, adminUser.Uuid, 0)
})

t.Run("Deleting a user also remove his/her highlights", func(t *testing.T) {
regularUser := model.User{}
db.Where("email = ?", "[email protected]").First(&regularUser)

regularUserCookie, err := login(app, "[email protected]", "test")
if err != nil {
t.Fatalf("Unexpected error: %v", err.Error())
}

response, err := highlight(regularUserCookie, app, strings.NewReader(data.Encode()), fiber.MethodPost)
if err != nil {
t.Fatalf("Unexpected error: %v", err.Error())
}

mustReturnStatus(response, fiber.StatusOK, t)

assertHighlights(app, t, regularUserCookie, regularUser.Uuid, 1)

adminCookie, err = login(app, "[email protected]", "admin")
if err != nil {
t.Fatalf("Unexpected error: %v", err.Error())
}

data = url.Values{
"uuid": {regularUser.Uuid},
}

_, err = deleteUser(data, adminCookie, app)
if err != nil {
t.Fatalf("Unexpected error: %v", err.Error())
}

assertNoHighlights(app, t, adminCookie, regularUser.Uuid)
var total int64
db.Table("highlights").Where("user_id = ?", regularUser.ID).Count(&total)
if total != 0 {
t.Errorf("Expected no highlights in DB for deleted user, got %d", total)
}
})
}

func highlight(cookie *http.Cookie, app *fiber.App, reader *strings.Reader, method string) (*http.Response, error) {
Expand Down Expand Up @@ -92,3 +146,18 @@ func assertHighlights(app *fiber.App, t *testing.T, cookie *http.Cookie, uuid st
t.Errorf("Expected %d results, got %d", expectedResults, actualResults)
}
}

func assertNoHighlights(app *fiber.App, t *testing.T, cookie *http.Cookie, uuid string) {
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("/en/highlights/%s", uuid), nil)
req.AddCookie(cookie)
if err != nil {
t.Fatalf("Unexpected error: %v", err.Error())
}
response, err := app.Test(req)
if err != nil {
t.Fatalf("Unexpected error: %v", err.Error())
}
if expectedStatus := http.StatusNotFound; response.StatusCode != expectedStatus {
t.Errorf("Expected status %d, received %d", expectedStatus, response.StatusCode)
}
}
2 changes: 1 addition & 1 deletion internal/webserver/user_management_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestUserManagement(t *testing.T) {
"email": {"[email protected]"},
"password": {"test"},
"confirm-password": {"test"},
"role": {"1"},
"role": {fmt.Sprint(model.RoleRegular)},
"words-per-minute": {"250"},
}

Expand Down

0 comments on commit 214120e

Please sign in to comment.