Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yurii dev #95

Merged
merged 6 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/web/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func routes(a *config.AppConfig) http.Handler {

mux.HandleFunc("/moder_panel", handler.Repo.ModerPanelHandler)

mux.HandleFunc("/send-pm", handler.Repo.SendPMHandler)



return mux
Expand Down
86 changes: 86 additions & 0 deletions internal/handler/staticHelperHendlers.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package handler

import (
"fmt"
"log"
"net/http"
"strconv"
"strings"

"github.com/Pomog/ForumFFF/internal/config"
"github.com/Pomog/ForumFFF/internal/helper"
"github.com/Pomog/ForumFFF/internal/models"
"github.com/Pomog/ForumFFF/internal/renderer"
"github.com/Pomog/ForumFFF/internal/repository"
Expand Down Expand Up @@ -111,10 +114,18 @@ func (m *Repository) PersonaCabinetHandler(w http.ResponseWriter, r *http.Reques
personalInfo.UserName = user.UserName
personalInfo.Type = user.Type //will show type of user in personal cabinet
totalPosts, _ := m.DB.GetTotalPostsAmmountByUserID(personalInfo.ID)

receivedPMS, err := m.DB.GetPMbyReceiverUserID(sessionUserID)
if err != nil {
setErrorAndRedirect(w, r, "Could not get received PMS"+err.Error(), "/error-page")
return
}

data := make(map[string]interface{})
data["personal"] = personalInfo
data["totalPosts"] = totalPosts
data["loggedAsID"] = sessionUserID
data["receivedPMS"] = receivedPMS

renderer.RendererTemplate(w, "personal.page.html", &models.TemplateData{
Data: data,
Expand All @@ -127,6 +138,11 @@ func (m *Repository) PersonaCabinetHandler(w http.ResponseWriter, r *http.Reques

// GetAllThreadsForUserHandler gets all threads from user (user id)
func (m *Repository) GetAllThreadsForUserHandler(w http.ResponseWriter, r *http.Request) {
sessionUserID := m.GetLoggedUser(w, r)
if sessionUserID == 0 {
setErrorAndRedirect(w, r, "unautorized", "/error-page")
return
}
if r.Method == http.MethodGet {
userID, _ := strconv.Atoi(r.URL.Query().Get("userID"))
user, errUser := m.DB.GetUserByID(userID)
Expand Down Expand Up @@ -160,6 +176,7 @@ func (m *Repository) GetAllThreadsForUserHandler(w http.ResponseWriter, r *http.
info.Subject = thread.Subject
info.Created = thread.Created.Format("2006-01-02 15:04:05")
info.Category = thread.Category
info.UserID = thread.UserID

info.PictureUserWhoCreatedThread = user.Picture
info.UserNameWhoCreatedThread = user.UserName
Expand Down Expand Up @@ -192,6 +209,7 @@ func (m *Repository) GetAllThreadsForUserHandler(w http.ResponseWriter, r *http.

data["games"] = m.App.GamesList
data["threads"] = threadsInfo
data["loggedAsID"] = sessionUserID

renderer.RendererTemplate(w, "home.page.html", &models.TemplateData{
Data: data,
Expand All @@ -204,6 +222,12 @@ func (m *Repository) GetAllThreadsForUserHandler(w http.ResponseWriter, r *http.

// GetAllPostsForUserHandler gets all posts from user (user id)
func (m *Repository) GetAllPostsForUserHandler(w http.ResponseWriter, r *http.Request) {
sessionUserID := m.GetLoggedUser(w, r)
if sessionUserID == 0 {
setErrorAndRedirect(w, r, "unautorized", "/error-page")
return
}

if r.Method == http.MethodGet {
userID, _ := strconv.Atoi(r.URL.Query().Get("userID"))
user, errUser := m.DB.GetUserByID(userID)
Expand Down Expand Up @@ -259,6 +283,7 @@ func (m *Repository) GetAllPostsForUserHandler(w http.ResponseWriter, r *http.Re

data["posts"] = postsInfo
data["games"] = m.App.GamesList
data["loggedAsID"] = sessionUserID

renderer.RendererTemplate(w, "theme.page.html", &models.TemplateData{
Data: data,
Expand All @@ -267,6 +292,12 @@ func (m *Repository) GetAllPostsForUserHandler(w http.ResponseWriter, r *http.Re
}

func (m *Repository) GetAllLikedPostsByUserIDHandler(w http.ResponseWriter, r *http.Request) {
sessionUserID := m.GetLoggedUser(w, r)
if sessionUserID == 0 {
setErrorAndRedirect(w, r, "unautorized", "/error-page")
return
}

if r.Method == http.MethodGet {
userID, _ := strconv.Atoi(r.URL.Query().Get("userID"))
user, errUser := m.DB.GetUserByID(userID)
Expand Down Expand Up @@ -322,13 +353,68 @@ func (m *Repository) GetAllLikedPostsByUserIDHandler(w http.ResponseWriter, r *h

data["posts"] = postsInfo
data["games"] = m.App.GamesList
data["loggedAsID"] = sessionUserID

renderer.RendererTemplate(w, "theme.page.html", &models.TemplateData{
Data: data,
})
}
}

// SendPMHandler hanles sending of personal message.
func (m *Repository) SendPMHandler(w http.ResponseWriter, r *http.Request) {
senderID := m.GetLoggedUser(w, r)
if senderID == 0 {
setErrorAndRedirect(w, r, "unautorized", "/error-page")
return
}

if r.Method == http.MethodPost {
receiverID, _ := strconv.Atoi(r.FormValue("receiverID"))
content := r.FormValue("pm-text")

content = strings.TrimSpace(content)
content = helper.CorrectPunctuationsSpaces(content)

// Validation of privat message
validationParameters := models.ValidationConfig{
MinSubjectLen: m.App.MinSubjectLen,
MaxSubjectLen: m.App.MaxSubjectLen,
SingleWordMaxLen: len(m.App.LongestSingleWord),
}

if senderID == 1 || receiverID == 1 || senderID == receiverID {
setErrorAndRedirect(w, r, "Wrong receiver!", "/error-page")
return
}
p_message := models.PM{
Content: content,
SenderUserID: senderID,
ReceiverUserID: receiverID,
}

validationsErrors := p_message.ValidatePM(validationParameters)
if len(validationsErrors) > 0 {
// prepare error msg
var errorMsg string
for _, err := range validationsErrors {
errorMsg += err.Error() + "\n"
}
setErrorAndRedirect(w, r, errorMsg, "/error-page")
return
}

err := m.DB.CreatePM(p_message)
if err != nil {
setErrorAndRedirect(w, r, "Could not created a PM "+err.Error(), "/error-page")
return
}
http.Redirect(w, r, fmt.Sprintf("/personal_cabinet?userID=%v", receiverID), http.StatusSeeOther)
} else {
http.Error(w, "No such method", http.StatusMethodNotAllowed)
}
}

// shortenerOfSubject helper function to squeeze theme name
func ShortenerOfSubject(input string) string {
if len(input) <= 80 {
Expand Down
1 change: 1 addition & 0 deletions internal/handler/themeHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ func prepareDataForThemePage(m *Repository, w http.ResponseWriter, r *http.Reque
data["creatorPostsAmount"] = creatorPostsAmount
data["creatorImg"] = creator.Picture
data["mainThreadName"] = mainThread.Subject
data["mainThreadCategory"] = mainThread.Category
data["mainThreadID"] = mainThread.ID
data["mainThreadCreatedTime"] = mainThread.Created.Format("2006-01-02 15:04:05")
data["games"] = m.App.GamesList
Expand Down
8 changes: 8 additions & 0 deletions internal/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,11 @@ var Classifications = []TextClassification{"irrelevant",
"unsorted",
"approved",
}

type PM struct {
ID int
Content string
Created time.Time
SenderUserID int
ReceiverUserID int
}
23 changes: 23 additions & 0 deletions internal/models/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,29 @@ func (post *Post) Validate(config ValidationConfig) []error {
return validationErrors
}

func (pm *PM) ValidatePM(config ValidationConfig) []error {
var validationErrors []error

// Validate Content
if err := ValidateRequired("Content", pm.Content); err != nil {
validationErrors = append(validationErrors, err)
} else {
if err := ValidateLength("Content", pm.Content, config.MinSubjectLen, config.MaxSubjectLen); err != nil {
validationErrors = append(validationErrors, err)
} else {
if !forms.CheckSingleWordLen(pm.Content, config.SingleWordMaxLen) {
err := fmt.Errorf("the Content without spaces is not allowed, max len of each word (without spaces) is %d", config.SingleWordMaxLen)
validationErrors = append(validationErrors, err)
}
}
}

// Add more validation logic for other fields

return validationErrors
}


// ValidateRequired checks if the field is required and not empty.
func ValidateRequired(fieldName string, fieldValue string) error {
if fieldValue == "" {
Expand Down
2 changes: 1 addition & 1 deletion internal/repository/db_funcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

var ObligatoryTables = []string{
"users", "thread", "votes", "post", "sessionId",
"users", "thread", "votes", "post", "sessionId", "pm",
}

func Test_GetDB(t *testing.T) {
Expand Down
100 changes: 100 additions & 0 deletions internal/repository/dbrepo/sqllite.go
Original file line number Diff line number Diff line change
Expand Up @@ -825,3 +825,103 @@ func (m *SqliteBDRepo) EditPostClassification(post models.Post, classification m
}
return nil
}

// CreatePM insert post into SQLite DB
func (m *SqliteBDRepo) CreatePM(pm models.PM) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

stmt := `insert into pm
(content, senderUserID, receiverUserID)
values ($1, $2, $3)
`

_, err := m.DB.ExecContext(ctx, stmt,
pm.Content,
pm.SenderUserID,
pm.ReceiverUserID,
)

if err != nil {
return err
}
return nil
}

// DeletePM deletes pm
func (m *SqliteBDRepo) DeletePM(pm models.PM) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

stmt := `DELETE FROM pm
WHERE id = $1;
`
_, err := m.DB.ExecContext(ctx, stmt,
pm.ID,
)

if err != nil {
return err
}
return nil
}

// GetPMbyReceiverUserID insert post into SQLite DB
func (m *SqliteBDRepo) GetPMbyReceiverUserID(userID int) ([]models.PM, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

query := `select * from pm
where receiverUserID = $1
`

rows, err := m.DB.QueryContext(ctx, query, userID)
if err != nil {
return nil, err
}
defer rows.Close()

var pms []models.PM

for rows.Next() {
var pm models.PM
err := rows.Scan(&pm.ID, &pm.Content, &pm.Created, &pm.SenderUserID, &pm.ReceiverUserID)
if err != nil {
return nil, err
}
pms = append(pms, pm)
}

return pms, nil
}

// GetPMbysenderUserID insert post into SQLite DB
func (m *SqliteBDRepo) GetPMbysenderUserID(userID int) ([]models.PM, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

query := `select * from pm
where senderUserID = $1
`

rows, err := m.DB.QueryContext(ctx, query, userID)
if err != nil {
return nil, err
}
defer rows.Close()

var pms []models.PM

for rows.Next() {
var pm models.PM
err := rows.Scan(&pm.ID, &pm.Content, &pm.Created, &pm.SenderUserID, &pm.ReceiverUserID)
if err != nil {
return nil, err
}
pms = append(pms, pm)
}

return pms, nil
}


4 changes: 4 additions & 0 deletions internal/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ type DatabaseInt interface {
EditTopicClassification(topic models.Thread, classification models.TextClassification) error
GetAllPostsByClassification(classification models.TextClassification) ([]models.Post, error)
GetAllThreadsByClassification(classification models.TextClassification) ([]models.Thread, error)
CreatePM(pm models.PM) error
DeletePM(pm models.PM) error
GetPMbyReceiverUserID(userID int) ([]models.PM, error)
GetPMbysenderUserID(userID int) ([]models.PM, error)
}
11 changes: 11 additions & 0 deletions internal/repository/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ var sessionIdTable = `CREATE TABLE IF NOT EXISTS sessionId (
FOREIGN KEY (userID) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);`

var privateMessageTable = `CREATE TABLE IF NOT EXISTS pm (
id INTEGER PRIMARY KEY,
content TEXT,
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
senderUserID INTEGER,
receiverUserID INTEGER,
FOREIGN KEY (senderUserID) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
FOREIGN KEY (receiverUserID) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);`

var guestUser = `INSERT INTO users (username, password, first_name, last_name, email, type)
VALUES ('guest', '123456', 'Guest', 'User', 'guest@gmail.com', 'guest');`

Expand All @@ -70,6 +80,7 @@ func getQuerys() []string {
sqlQuerys = append(sqlQuerys, postTable)
sqlQuerys = append(sqlQuerys, votesTable)
sqlQuerys = append(sqlQuerys, sessionIdTable)
sqlQuerys = append(sqlQuerys, privateMessageTable)

sqlQuerys = append(sqlQuerys, addClassificationToPost)
sqlQuerys = append(sqlQuerys, addClassificationToThread)
Expand Down
Binary file modified mainDB.db
Binary file not shown.
1 change: 1 addition & 0 deletions template/home.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ <h1 class="modal-title fs-5" id="createNewTopicModalLabel">What this topic will
{{$threadinfo := index .Data "threads"}}

{{ range $threadinfo }}

{{ if or (eq .UserID $loggedID) (eq .Classification "approved") }}
<tr>
<td>
Expand Down
Loading