Compare commits
3 Commits
8b6ae897a5
...
b9842ddd5e
Author | SHA1 | Date | |
---|---|---|---|
b9842ddd5e | |||
d574dab3a7 | |||
1983662216 |
@ -17,3 +17,7 @@ func (app *application) home(w http.ResponseWriter, r *http.Request) {
|
|||||||
func (app *application) notImplemented(w http.ResponseWriter, r *http.Request) {
|
func (app *application) notImplemented(w http.ResponseWriter, r *http.Request) {
|
||||||
views.ComingSoon("Coming Soon", app.newCommonData(r)).Render(r.Context(), w)
|
views.ComingSoon("Coming Soon", app.newCommonData(r)).Render(r.Context(), w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ping(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("OK"))
|
||||||
|
}
|
||||||
|
60
cmd/web/handlers_guestbook_test.go
Normal file
60
cmd/web/handlers_guestbook_test.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.32bit.cafe/32bitcafe/guestbook/internal/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPing(t *testing.T) {
|
||||||
|
app := newTestApplication(t)
|
||||||
|
ts := newTestServer(t, app.routes())
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
code, _, body := ts.get(t, "/ping")
|
||||||
|
|
||||||
|
assert.Equal(t, code, http.StatusOK)
|
||||||
|
assert.Equal(t, body, "OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetGuestbookView(t *testing.T) {
|
||||||
|
app := newTestApplication(t)
|
||||||
|
ts := newTestServer(t, app.routes())
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
urlPath string
|
||||||
|
wantCode int
|
||||||
|
wantBody string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid id",
|
||||||
|
urlPath: fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(1)),
|
||||||
|
wantCode: http.StatusOK,
|
||||||
|
wantBody: "Guestbook for Example",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Non-existent ID",
|
||||||
|
urlPath: fmt.Sprintf("/websites/%s/guestbook", shortIdToSlug(2)),
|
||||||
|
wantCode: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "String ID",
|
||||||
|
urlPath: "/websites/abcd/guestbook",
|
||||||
|
wantCode: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
code, _, body := ts.get(t, tt.urlPath)
|
||||||
|
assert.Equal(t, code, tt.wantCode)
|
||||||
|
if tt.wantBody != "" {
|
||||||
|
assert.StringContains(t, body, tt.wantBody)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
121
cmd/web/handlers_user_test.go
Normal file
121
cmd/web/handlers_user_test.go
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.32bit.cafe/32bitcafe/guestbook/internal/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserSignup(t *testing.T) {
|
||||||
|
app := newTestApplication(t)
|
||||||
|
ts := newTestServer(t, app.routes())
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
_, _, body := ts.get(t, "/users/register")
|
||||||
|
validCSRFToken := extractCSRFToken(t, body)
|
||||||
|
|
||||||
|
const (
|
||||||
|
validName = "John"
|
||||||
|
validPassword = "validPassword"
|
||||||
|
validEmail = "john@example.com"
|
||||||
|
formTag = `<form action="/users/register" method="post">`
|
||||||
|
)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
userName string
|
||||||
|
userEmail string
|
||||||
|
userPassword string
|
||||||
|
csrfToken string
|
||||||
|
wantCode int
|
||||||
|
wantFormTag string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid submission",
|
||||||
|
userName: validName,
|
||||||
|
userEmail: validEmail,
|
||||||
|
userPassword: validPassword,
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusSeeOther,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing token",
|
||||||
|
userName: validName,
|
||||||
|
userEmail: validEmail,
|
||||||
|
userPassword: validPassword,
|
||||||
|
wantCode: http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty name",
|
||||||
|
userName: "",
|
||||||
|
userEmail: validEmail,
|
||||||
|
userPassword: validPassword,
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusUnprocessableEntity,
|
||||||
|
wantFormTag: formTag,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty email",
|
||||||
|
userName: validName,
|
||||||
|
userEmail: "",
|
||||||
|
userPassword: validPassword,
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusUnprocessableEntity,
|
||||||
|
wantFormTag: formTag,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty password",
|
||||||
|
userName: validName,
|
||||||
|
userEmail: validEmail,
|
||||||
|
userPassword: "",
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusUnprocessableEntity,
|
||||||
|
wantFormTag: formTag,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid email",
|
||||||
|
userName: validName,
|
||||||
|
userEmail: "asdfasdf",
|
||||||
|
userPassword: validPassword,
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusUnprocessableEntity,
|
||||||
|
wantFormTag: formTag,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid password",
|
||||||
|
userName: validName,
|
||||||
|
userEmail: validEmail,
|
||||||
|
userPassword: "asdfasd",
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusUnprocessableEntity,
|
||||||
|
wantFormTag: formTag,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Duplicate email",
|
||||||
|
userName: validName,
|
||||||
|
userEmail: "dupe@example.com",
|
||||||
|
userPassword: validPassword,
|
||||||
|
csrfToken: validCSRFToken,
|
||||||
|
wantCode: http.StatusUnprocessableEntity,
|
||||||
|
wantFormTag: formTag,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(*testing.T) {
|
||||||
|
form := url.Values{}
|
||||||
|
form.Add("username", tt.userName)
|
||||||
|
form.Add("email", tt.userEmail)
|
||||||
|
form.Add("password", tt.userPassword)
|
||||||
|
form.Add("csrf_token", tt.csrfToken)
|
||||||
|
code, _, body := ts.postForm(t, "/users/register", form)
|
||||||
|
assert.Equal(t, code, tt.wantCode)
|
||||||
|
if tt.wantFormTag != "" {
|
||||||
|
assert.StringContains(t, body, tt.wantFormTag)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -21,9 +21,9 @@ import (
|
|||||||
type application struct {
|
type application struct {
|
||||||
sequence uint16
|
sequence uint16
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
websites *models.WebsiteModel
|
websites models.WebsiteModelInterface
|
||||||
users *models.UserModel
|
users models.UserModelInterface
|
||||||
guestbookComments *models.GuestbookCommentModel
|
guestbookComments models.GuestbookCommentModelInterface
|
||||||
sessionManager *scs.SessionManager
|
sessionManager *scs.SessionManager
|
||||||
formDecoder *schema.Decoder
|
formDecoder *schema.Decoder
|
||||||
debug bool
|
debug bool
|
||||||
|
@ -11,6 +11,8 @@ func (app *application) routes() http.Handler {
|
|||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.Handle("GET /static/", http.FileServerFS(ui.Files))
|
mux.Handle("GET /static/", http.FileServerFS(ui.Files))
|
||||||
|
|
||||||
|
mux.HandleFunc("GET /ping", ping)
|
||||||
|
|
||||||
dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf, app.authenticate)
|
dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf, app.authenticate)
|
||||||
standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders)
|
standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders)
|
||||||
|
|
||||||
|
96
cmd/web/testutils_test.go
Normal file
96
cmd/web/testutils_test.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"html"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/http/cookiejar"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.32bit.cafe/32bitcafe/guestbook/internal/models/mocks"
|
||||||
|
"github.com/alexedwards/scs/v2"
|
||||||
|
"github.com/gorilla/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newTestApplication(t *testing.T) *application {
|
||||||
|
formDecoder := schema.NewDecoder()
|
||||||
|
formDecoder.IgnoreUnknownKeys(true)
|
||||||
|
|
||||||
|
sessionManager := scs.New()
|
||||||
|
sessionManager.Lifetime = 12 * time.Hour
|
||||||
|
sessionManager.Cookie.Secure = true
|
||||||
|
|
||||||
|
return &application{
|
||||||
|
logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
|
||||||
|
sessionManager: sessionManager,
|
||||||
|
websites: &mocks.WebsiteModel{},
|
||||||
|
users: &mocks.UserModel{},
|
||||||
|
guestbookComments: &mocks.GuestbookCommentModel{},
|
||||||
|
formDecoder: formDecoder,
|
||||||
|
timezones: getAvailableTimezones(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testServer struct {
|
||||||
|
*httptest.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestServer(t *testing.T, h http.Handler) *testServer {
|
||||||
|
ts := httptest.NewTLSServer(h)
|
||||||
|
jar, err := cookiejar.New(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ts.Client().Jar = jar
|
||||||
|
ts.Client().CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||||
|
return http.ErrUseLastResponse
|
||||||
|
}
|
||||||
|
return &testServer{ts}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *testServer) get(t *testing.T, urlPath string) (int, http.Header, string) {
|
||||||
|
rs, err := ts.Client().Get(ts.URL + urlPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer rs.Body.Close()
|
||||||
|
body, err := io.ReadAll(rs.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
body = bytes.TrimSpace(body)
|
||||||
|
|
||||||
|
return rs.StatusCode, rs.Header, string(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *testServer) postForm(t *testing.T, urlPath string, form url.Values) (int, http.Header, string) {
|
||||||
|
rs, err := ts.Client().PostForm(ts.URL+urlPath, form)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer rs.Body.Close()
|
||||||
|
body, err := io.ReadAll(rs.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
body = bytes.TrimSpace(body)
|
||||||
|
return rs.StatusCode, rs.Header, string(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
var csrfTokenRX = regexp.MustCompile(`<input type="hidden" name="csrf_token" value="(.+?)">`)
|
||||||
|
|
||||||
|
func extractCSRFToken(t *testing.T, body string) string {
|
||||||
|
matches := csrfTokenRX.FindStringSubmatch(body)
|
||||||
|
if len(matches) < 2 {
|
||||||
|
t.Fatal("no csrf token found in body")
|
||||||
|
}
|
||||||
|
return html.UnescapeString(matches[1])
|
||||||
|
}
|
22
internal/assert/assert.go
Normal file
22
internal/assert/assert.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package assert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Equal[T comparable](t *testing.T, actual, expected T) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if actual != expected {
|
||||||
|
t.Errorf("got: %v; want %v", actual, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func StringContains(t *testing.T, actual, expectedSubstring string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if !strings.Contains(actual, expectedSubstring) {
|
||||||
|
t.Errorf("got: %q; expected to contain: %q", actual, expectedSubstring)
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,15 @@ type GuestbookCommentModel struct {
|
|||||||
DB *sql.DB
|
DB *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GuestbookCommentModelInterface interface {
|
||||||
|
Insert(shortId uint64, guestbookId, parentId int64, authorName, authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error)
|
||||||
|
Get(shortId uint64) (GuestbookComment, error)
|
||||||
|
GetAll(guestbookId int64) ([]GuestbookComment, error)
|
||||||
|
GetDeleted(guestbookId int64) ([]GuestbookComment, error)
|
||||||
|
GetUnpublished(guestbookId int64) ([]GuestbookComment, error)
|
||||||
|
UpdateComment(comment *GuestbookComment) error
|
||||||
|
}
|
||||||
|
|
||||||
func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName,
|
func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName,
|
||||||
authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) {
|
authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) {
|
||||||
stmt := `INSERT INTO guestbook_comments (ShortId, GuestbookId, ParentId, AuthorName,
|
stmt := `INSERT INTO guestbook_comments (ShortId, GuestbookId, ParentId, AuthorName,
|
||||||
|
64
internal/models/mocks/guestbookcomment.go
Normal file
64
internal/models/mocks/guestbookcomment.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mockGuestbookComment = models.GuestbookComment{
|
||||||
|
ID: 1,
|
||||||
|
ShortId: 1,
|
||||||
|
GuestbookId: 1,
|
||||||
|
AuthorName: "John Test",
|
||||||
|
AuthorEmail: "test@example.com",
|
||||||
|
AuthorSite: "example.com",
|
||||||
|
CommentText: "Hello, world",
|
||||||
|
Created: time.Now(),
|
||||||
|
IsPublished: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
type GuestbookCommentModel struct{}
|
||||||
|
|
||||||
|
func (m *GuestbookCommentModel) Insert(shortId uint64, guestbookId, parentId int64, authorName,
|
||||||
|
authorEmail, authorSite, commentText, pageUrl string, isPublished bool) (int64, error) {
|
||||||
|
return 2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GuestbookCommentModel) Get(shortId uint64) (models.GuestbookComment, error) {
|
||||||
|
switch shortId {
|
||||||
|
case 1:
|
||||||
|
return mockGuestbookComment, nil
|
||||||
|
default:
|
||||||
|
return models.GuestbookComment{}, models.ErrNoRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GuestbookCommentModel) GetAll(guestbookId int64) ([]models.GuestbookComment, error) {
|
||||||
|
switch guestbookId {
|
||||||
|
case 1:
|
||||||
|
return []models.GuestbookComment{mockGuestbookComment}, nil
|
||||||
|
case 2:
|
||||||
|
return []models.GuestbookComment{}, nil
|
||||||
|
default:
|
||||||
|
return []models.GuestbookComment{}, models.ErrNoRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GuestbookCommentModel) GetDeleted(guestbookId int64) ([]models.GuestbookComment, error) {
|
||||||
|
switch guestbookId {
|
||||||
|
default:
|
||||||
|
return []models.GuestbookComment{}, models.ErrNoRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GuestbookCommentModel) GetUnpublished(guestbookId int64) ([]models.GuestbookComment, error) {
|
||||||
|
switch guestbookId {
|
||||||
|
default:
|
||||||
|
return []models.GuestbookComment{}, models.ErrNoRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GuestbookCommentModel) UpdateComment(comment *models.GuestbookComment) error {
|
||||||
|
return nil
|
||||||
|
}
|
89
internal/models/mocks/users.go
Normal file
89
internal/models/mocks/users.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mockUser = models.User{
|
||||||
|
ID: 1,
|
||||||
|
ShortId: 1,
|
||||||
|
Username: "tester",
|
||||||
|
Email: "test@example.com",
|
||||||
|
Deleted: false,
|
||||||
|
IsBanned: false,
|
||||||
|
Created: time.Now(),
|
||||||
|
Settings: mockUserSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
var mockUserSettings = models.UserSettings{
|
||||||
|
LocalTimezone: time.UTC,
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserModel struct {
|
||||||
|
Settings map[string]models.Setting
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) InitializeSettingsMap() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) Insert(shortId uint64, username string, email string, password string, settings models.UserSettings) error {
|
||||||
|
switch email {
|
||||||
|
case "dupe@example.com":
|
||||||
|
return models.ErrDuplicateEmail
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) Get(shortId uint64) (models.User, error) {
|
||||||
|
switch shortId {
|
||||||
|
case 1:
|
||||||
|
return mockUser, nil
|
||||||
|
default:
|
||||||
|
return models.User{}, models.ErrNoRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) GetById(id int64) (models.User, error) {
|
||||||
|
switch id {
|
||||||
|
case 1:
|
||||||
|
return mockUser, nil
|
||||||
|
default:
|
||||||
|
return models.User{}, models.ErrNoRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) GetAll() ([]models.User, error) {
|
||||||
|
return []models.User{mockUser}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) Authenticate(email, password string) (int64, error) {
|
||||||
|
if email == "test@example.com" && password == "password" {
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
return 0, models.ErrInvalidCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) Exists(id int64) (bool, error) {
|
||||||
|
switch id {
|
||||||
|
case 1:
|
||||||
|
return true, nil
|
||||||
|
default:
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) GetSettings(userId int64) (models.UserSettings, error) {
|
||||||
|
return mockUserSettings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) UpdateUserSettings(userId int64, settings models.UserSettings) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UserModel) UpdateSetting(userId int64, setting models.Setting, value string) error {
|
||||||
|
return nil
|
||||||
|
}
|
77
internal/models/mocks/website.go
Normal file
77
internal/models/mocks/website.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package mocks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.32bit.cafe/32bitcafe/guestbook/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mockGuestbook = models.Guestbook{
|
||||||
|
ID: 1,
|
||||||
|
ShortId: 1,
|
||||||
|
UserId: 1,
|
||||||
|
WebsiteId: 1,
|
||||||
|
Created: time.Now(),
|
||||||
|
IsActive: true,
|
||||||
|
Settings: models.GuestbookSettings{
|
||||||
|
IsCommentingEnabled: true,
|
||||||
|
IsVisible: true,
|
||||||
|
FilteredWords: make([]string, 0),
|
||||||
|
AllowRemoteHostAccess: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var mockWebsite = models.Website{
|
||||||
|
ID: 1,
|
||||||
|
ShortId: 1,
|
||||||
|
Name: "Example",
|
||||||
|
SiteUrl: "example.com",
|
||||||
|
AuthorName: "John Test",
|
||||||
|
UserId: 1,
|
||||||
|
Created: time.Now(),
|
||||||
|
Guestbook: mockGuestbook,
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteModel struct{}
|
||||||
|
|
||||||
|
func (m *WebsiteModel) Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error) {
|
||||||
|
return 2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WebsiteModel) Get(shortId uint64) (models.Website, error) {
|
||||||
|
switch shortId {
|
||||||
|
case 1:
|
||||||
|
return mockWebsite, nil
|
||||||
|
default:
|
||||||
|
return models.Website{}, models.ErrNoRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WebsiteModel) GetAllUser(userId int64) ([]models.Website, error) {
|
||||||
|
return []models.Website{mockWebsite}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WebsiteModel) GetById(id int64) (models.Website, error) {
|
||||||
|
switch id {
|
||||||
|
case 1:
|
||||||
|
return mockWebsite, nil
|
||||||
|
default:
|
||||||
|
return models.Website{}, models.ErrNoRecord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WebsiteModel) GetAll() ([]models.Website, error) {
|
||||||
|
return []models.Website{mockWebsite}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WebsiteModel) InitializeSettingsMap() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WebsiteModel) UpdateGuestbookSettings(guestbookId int64, settings models.GuestbookSettings) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WebsiteModel) UpdateSetting(guestbookId int64, setting models.Setting, value string) error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -35,6 +35,18 @@ type UserModel struct {
|
|||||||
Settings map[string]Setting
|
Settings map[string]Setting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserModelInterface interface {
|
||||||
|
InitializeSettingsMap() error
|
||||||
|
Insert(shortId uint64, username string, email string, password string, settings UserSettings) error
|
||||||
|
Get(shortId uint64) (User, error)
|
||||||
|
GetById(id int64) (User, error)
|
||||||
|
GetAll() ([]User, error)
|
||||||
|
Authenticate(email, password string) (int64, error)
|
||||||
|
Exists(id int64) (bool, error)
|
||||||
|
UpdateUserSettings(userId int64, settings UserSettings) error
|
||||||
|
UpdateSetting(userId int64, setting Setting, value string) error
|
||||||
|
}
|
||||||
|
|
||||||
func (m *UserModel) InitializeSettingsMap() error {
|
func (m *UserModel) InitializeSettingsMap() error {
|
||||||
if m.Settings == nil {
|
if m.Settings == nil {
|
||||||
m.Settings = make(map[string]Setting)
|
m.Settings = make(map[string]Setting)
|
||||||
|
@ -90,6 +90,16 @@ func (m *WebsiteModel) InitializeSettingsMap() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsiteModelInterface interface {
|
||||||
|
Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error)
|
||||||
|
Get(shortId uint64) (Website, error)
|
||||||
|
GetAllUser(userId int64) ([]Website, error)
|
||||||
|
GetAll() ([]Website, error)
|
||||||
|
InitializeSettingsMap() error
|
||||||
|
UpdateGuestbookSettings(guestbookId int64, settings GuestbookSettings) error
|
||||||
|
UpdateSetting(guestbookId int64, setting Setting, value string) error
|
||||||
|
}
|
||||||
|
|
||||||
func (m *WebsiteModel) Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error) {
|
func (m *WebsiteModel) Insert(shortId uint64, userId int64, siteName, siteUrl, authorName string) (int64, error) {
|
||||||
stmt := `INSERT INTO websites (ShortId, Name, SiteUrl, AuthorName, UserId, Created)
|
stmt := `INSERT INTO websites (ShortId, Name, SiteUrl, AuthorName, UserId, Created)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)`
|
VALUES (?, ?, ?, ?, ?, ?)`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user