diff --git a/cmd/web/main.go b/cmd/web/main.go index d6ffe49..43c4cb4 100644 --- a/cmd/web/main.go +++ b/cmd/web/main.go @@ -53,6 +53,8 @@ func main() { app.GoogleClientSecret = "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" app.GoogleRedirectURL = "http://localhost:8080/google-callback" + app.ModeratorPass = "123" //our secret pass for moders + //the list of games that are represented and will be covered on site. app.GamesList = map[string]string{ "Lineage 2": "L2", diff --git a/cmd/web/routes.go b/cmd/web/routes.go index 3bd19ac..a323aa7 100644 --- a/cmd/web/routes.go +++ b/cmd/web/routes.go @@ -37,6 +37,7 @@ func routes(a *config.AppConfig) http.Handler { mux.HandleFunc("/personal_cabinet_threads", handler.Repo.GetAllThreadsForUserHandler) mux.HandleFunc("/personal_cabinet_posts", handler.Repo.GetAllPostsForUserHandler) mux.HandleFunc("/personal_cabinet_likes", handler.Repo.GetAllLikedPostsByUserIDHandler) + mux.HandleFunc("/personal_cabinet_user_type", handler.Repo.ChangeUserTypeResultHandler) //handler to change user type mux.HandleFunc("/create_post_result", handler.Repo.CreatePostResultHandler) diff --git a/internal/config/config.go b/internal/config/config.go index e28a9b0..d167386 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -36,4 +36,6 @@ type AppConfig struct { GoogleClientID string GoogleClientSecret string GoogleRedirectURL string + + ModeratorPass string //added Moder pass to app config } diff --git a/internal/handler/editUserTypeHandler.go b/internal/handler/editUserTypeHandler.go new file mode 100644 index 0000000..80a8925 --- /dev/null +++ b/internal/handler/editUserTypeHandler.go @@ -0,0 +1,45 @@ +package handler + +import ( + "net/http" + "strconv" + "strings" + + "github.com/Pomog/ForumFFF/internal/models" + "github.com/Pomog/ForumFFF/internal/renderer" +) + +// ChangeUserTypeResultHandler handles changing of user type +func (m *Repository) ChangeUserTypeResultHandler(w http.ResponseWriter, r *http.Request) { + sessionUserID := m.GetLoggedUser(w, r) + if sessionUserID == 0 { + setErrorAndRedirect(w, r, "unautorized", "/error-page") + return + } + personalCabinetUserID, err := strconv.Atoi(r.URL.Query().Get("userID")) + if err != nil { + setErrorAndRedirect(w, r, "could not convert string to int: strconv.Atoi(r.URL.Query().Get(userID))", "/error-page") + return + } + if sessionUserID != personalCabinetUserID { + setErrorAndRedirect(w, r, "only owner of cabinet can submit secret code", "/error-page") + return + } + inputPass := strings.TrimSpace(r.FormValue("changeUserType")) + + if r.Method == http.MethodPost && inputPass == m.App.ModeratorPass { + user, _ := m.DB.GetUserByID(sessionUserID) + user.Type = "moder" + m.DB.EditUserType(user) + + data := make(map[string]interface{}) + data["userID"] = user.ID + renderer.RendererTemplate(w, "edit_user_type_result.page.html", &models.TemplateData{ + Data: data, + }) + + } else { + http.Error(w, "wrong secret code", http.StatusMethodNotAllowed) + } + +} diff --git a/internal/handler/loginHandler.go b/internal/handler/loginHandler.go index 1d089bf..6c5a77d 100644 --- a/internal/handler/loginHandler.go +++ b/internal/handler/loginHandler.go @@ -13,6 +13,20 @@ import ( // LoginHandler handles both GET and POST requests for the login page. func (m *Repository) LoginHandler(w http.ResponseWriter, r *http.Request) { + userIDstring := r.URL.Query().Get("id") + if userIDstring != "" { + userID, err := strconv.Atoi(userIDstring) + if err != nil { + setErrorAndRedirect(w, r, "wrong URL", "/error-page") + return + } + err = m.DB.DelSessionByUserID(userID) + if err != nil { + setErrorAndRedirect(w, r, err.Error(), "/error-page") + return + } + } + if r.Method == http.MethodGet { var emptyLogin models.User data := make(map[string]interface{}) @@ -62,8 +76,9 @@ func (m *Repository) LoginHandler(w http.ResponseWriter, r *http.Request) { } cookie := &http.Cookie{ - Name: strconv.Itoa(userID), - Value: m.App.UserLogin.String(), + Name: strconv.Itoa(userID), + Value: m.App.UserLogin.String(), + HttpOnly: true, } http.SetCookie(w, cookie) diff --git a/internal/handler/staticHelperHendlers.go b/internal/handler/staticHelperHendlers.go index 95b182f..074026b 100644 --- a/internal/handler/staticHelperHendlers.go +++ b/internal/handler/staticHelperHendlers.go @@ -88,6 +88,12 @@ func (m *Repository) PrivatPolicyHandler(w http.ResponseWriter, r *http.Request) // PersonaCabinetHandler hanles the personal cabinet of selected user. func (m *Repository) PersonaCabinetHandler(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")) var personalInfo models.User @@ -103,10 +109,12 @@ func (m *Repository) PersonaCabinetHandler(w http.ResponseWriter, r *http.Reques personalInfo.LastName = user.LastName personalInfo.Picture = user.Picture personalInfo.UserName = user.UserName + personalInfo.Type = user.Type //will show type of user in personal cabinet totalPosts, _ := m.DB.GetTotalPostsAmmountByUserID(personalInfo.ID) data := make(map[string]interface{}) data["personal"] = personalInfo data["totalPosts"] = totalPosts + data["loggedAsID"] = sessionUserID renderer.RendererTemplate(w, "personal.page.html", &models.TemplateData{ Data: data, diff --git a/internal/models/models.go b/internal/models/models.go index 27f44ec..d897460 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -14,15 +14,17 @@ type User struct { Created time.Time Picture string LastActivity time.Time + Type string } type Thread struct { - ID int - Subject string - Created time.Time - UserID int - Image string - Category string + ID int + Subject string + Created time.Time + UserID int + Image string + Category string + Classification string } type ThreadDataForMainPage struct { @@ -36,6 +38,7 @@ type ThreadDataForMainPage struct { ThreadID int Image string Category string + Classification string } type PostDataForThemePage struct { @@ -51,16 +54,18 @@ type PostDataForThemePage struct { UserPostsAmmount int Likes int Dislikes int + Classification string } type Post struct { - ID int - Subject string - Content string - Created time.Time - ThreadId int - UserID int - Image string + ID int + Subject string + Content string + Created time.Time + ThreadId int + UserID int + Image string + Classification string } type Votes struct { diff --git a/internal/repository/dbrepo/sqllite.go b/internal/repository/dbrepo/sqllite.go index ee95517..1a4a9ce 100644 --- a/internal/repository/dbrepo/sqllite.go +++ b/internal/repository/dbrepo/sqllite.go @@ -68,7 +68,7 @@ func (m *SqliteBDRepo) GetUserByID(ID int) (models.User, error) { row := m.DB.QueryRowContext(ctx, query, ID) - err := row.Scan(&user.ID, &user.UserName, &user.Password, &user.FirstName, &user.LastName, &user.Email, &user.Created, &user.Picture, &user.LastActivity) + err := row.Scan(&user.ID, &user.UserName, &user.Password, &user.FirstName, &user.LastName, &user.Email, &user.Created, &user.Picture, &user.LastActivity, &user.Type) if err != nil { return user, err } @@ -96,7 +96,7 @@ func (m *SqliteBDRepo) GetThreadByID(ID int) (models.Thread, error) { row := m.DB.QueryRowContext(ctx, query, ID) - err := row.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category) + err := row.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category, &thread.Classification) if err != nil { return thread, err } @@ -115,7 +115,7 @@ func (m *SqliteBDRepo) GetPostByID(ID int) (models.Post, error) { row := m.DB.QueryRowContext(ctx, query, ID) - err := row.Scan(&post.ID, &post.Subject, &post.Content, &post.Created, &post.ThreadId, &post.UserID, &post.Image) + err := row.Scan(&post.ID, &post.Subject, &post.Content, &post.Created, &post.ThreadId, &post.UserID, &post.Image, &post.Classification) if err != nil { return post, err } @@ -334,7 +334,7 @@ func (m *SqliteBDRepo) GetAllPostsFromThread(threadID int) ([]models.Post, error for rows.Next() { var post models.Post - err := rows.Scan(&post.ID, &post.Subject, &post.Content, &post.Created, &post.ThreadId, &post.UserID, &post.Image) + err := rows.Scan(&post.ID, &post.Subject, &post.Content, &post.Created, &post.ThreadId, &post.UserID, &post.Image, &post.Classification) if err != nil { return nil, err } @@ -363,7 +363,7 @@ func (m *SqliteBDRepo) GetAllPostsByUserID(userID int) ([]models.Post, error) { for rows.Next() { var post models.Post - err := rows.Scan(&post.ID, &post.Subject, &post.Content, &post.Created, &post.ThreadId, &post.UserID, &post.Image) + err := rows.Scan(&post.ID, &post.Subject, &post.Content, &post.Created, &post.ThreadId, &post.UserID, &post.Image, &post.Classification) if err != nil { return nil, err } @@ -421,7 +421,7 @@ func (m *SqliteBDRepo) GetAllThreadsByUserID(userID int) ([]models.Thread, error for rows.Next() { var thread models.Thread - err := rows.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category) + err := rows.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category, &thread.Classification) if err != nil { return nil, err } @@ -449,7 +449,7 @@ func (m *SqliteBDRepo) GetAllThreads() ([]models.Thread, error) { for rows.Next() { var thread models.Thread - err := rows.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category) + err := rows.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category, &thread.Classification) if err != nil { return nil, err } @@ -651,7 +651,7 @@ func (m *SqliteBDRepo) GetSearchedThreads(search string) ([]models.Thread, error for rows.Next() { var thread models.Thread - err := rows.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category) + err := rows.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category, &thread.Classification) if err != nil { return nil, err } @@ -679,7 +679,7 @@ func (m *SqliteBDRepo) GetSearchedThreadsByCategory(search string) ([]models.Thr for rows.Next() { var thread models.Thread - err := rows.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category) + err := rows.Scan(&thread.ID, &thread.Subject, &thread.Created, &thread.UserID, &thread.Image, &thread.Category, &thread.Classification) if err != nil { return nil, err } @@ -688,3 +688,40 @@ func (m *SqliteBDRepo) GetSearchedThreadsByCategory(search string) ([]models.Thr return threads, nil } + +//EditUserType changes type of user from "user" to "moder" +func (m *SqliteBDRepo) EditUserType(user models.User) error { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + stmt := `UPDATE users + SET type = $1 + WHERE id = $2; + ` + _, err := m.DB.ExecContext(ctx, stmt, + user.Type, + user.ID, + ) + + if err != nil { + return err + } + return nil +} + +func (m *SqliteBDRepo) DelSessionByUserID(userID int) error { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + + stmt := `delete from sessionId + where userID = $1 + ` + _, err := m.DB.ExecContext(ctx, stmt, + userID, + ) + + if err != nil { + return err + } + return nil +} diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 421c359..326768b 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -30,4 +30,6 @@ type DatabaseInt interface { GetAllThreadsByUserID(userID int) ([]models.Thread, error) GetAllPostsByUserID(userID int) ([]models.Post, error) GetAllLikedPostsByUserID(userID int) ([]models.Post, error) + EditUserType(user models.User) error + DelSessionByUserID(userID int) error } diff --git a/internal/repository/sql.go b/internal/repository/sql.go index bbc297a..007871f 100644 --- a/internal/repository/sql.go +++ b/internal/repository/sql.go @@ -8,7 +8,7 @@ var userTable = `CREATE TABLE IF NOT EXISTS users ( last_name varchar(100) DEFAULT "", email varchar(254) DEFAULT "", created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - picture TEXT DEFAULT "static/ava/pomog_ava.png", + picture TEXT DEFAULT "static/ava/ava1.png", last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP );` @@ -51,9 +51,17 @@ var sessionIdTable = `CREATE TABLE IF NOT EXISTS sessionId ( FOREIGN KEY (userID) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE );` -var guestUser = `INSERT INTO users (username, password, first_name, last_name, email) -VALUES ('guest', '123456', 'Guest', 'User', 'guest@gmail.com');` +var guestUser = `INSERT INTO users (username, password, first_name, last_name, email, type) +VALUES ('guest', '123456', 'Guest', 'User', 'guest@gmail.com', 'guest');` +var addClassificationToPost = `ALTER TABLE post +ADD COLUMN classification VARCHAR(50) DEFAULT '';` + +var addClassificationToThread = `ALTER TABLE thread +ADD COLUMN classification VARCHAR(50) DEFAULT '';` + +var addUserType = `ALTER TABLE users +ADD COLUMN type VARCHAR(50) DEFAULT 'user';` func getQuerys() []string { var sqlQuerys []string @@ -62,5 +70,10 @@ func getQuerys() []string { sqlQuerys = append(sqlQuerys, postTable) sqlQuerys = append(sqlQuerys, votesTable) sqlQuerys = append(sqlQuerys, sessionIdTable) + + sqlQuerys = append(sqlQuerys, addClassificationToPost) + sqlQuerys = append(sqlQuerys, addClassificationToThread) + sqlQuerys = append(sqlQuerys, addUserType) + return sqlQuerys } diff --git a/mainDB.db b/mainDB.db index 21360a6..2a02da6 100644 Binary files a/mainDB.db and b/mainDB.db differ diff --git a/static/ava/face.png b/static/ava/face.png new file mode 100644 index 0000000..20a2037 Binary files /dev/null and b/static/ava/face.png differ diff --git a/static/ava/fp.png b/static/ava/fp.png new file mode 100644 index 0000000..9b7c488 Binary files /dev/null and b/static/ava/fp.png differ diff --git a/static/ava/guestLogo2.png b/static/ava/guestLogo2.png new file mode 100644 index 0000000..04620c0 Binary files /dev/null and b/static/ava/guestLogo2.png differ diff --git "a/static/ava/\320\222\320\260\321\200\320\273\320\276\320\272 \320\232\320\276\321\202\321\217\321\200\320\260.png" "b/static/ava/\320\222\320\260\321\200\320\273\320\276\320\272 \320\232\320\276\321\202\321\217\321\200\320\260.png" new file mode 100644 index 0000000..22165b1 Binary files /dev/null and "b/static/ava/\320\222\320\260\321\200\320\273\320\276\320\272 \320\232\320\276\321\202\321\217\321\200\320\260.png" differ diff --git a/static/post_images/fp.png b/static/post_images/fp.png new file mode 100644 index 0000000..9b7c488 Binary files /dev/null and b/static/post_images/fp.png differ diff --git a/template/edit_user_type_result.page.html b/template/edit_user_type_result.page.html new file mode 100644 index 0000000..a7d7f56 --- /dev/null +++ b/template/edit_user_type_result.page.html @@ -0,0 +1,16 @@ +{{template "body" .}} + +{{define "centralPart"}} +
+ {{$userID := index .Data "userID"}} +
+

Congratulations! Your upgrade has been approved. You're now wielding the mighty powers + of a Moderator! Time to sprinkle some stardust and wield that virtual hammer with grace. + 🌟 And hey, remember, with great power comes great... jokes! How about this one: Why don't + programmers like nature? It has too many bugs! 😄 Welcome to the Moderator club, where puns + and power collide!

+

Return to your cabinet...

+
+
+ +{{end}} diff --git a/template/main.layout.html b/template/main.layout.html index a6b4aca..3a0be80 100644 --- a/template/main.layout.html +++ b/template/main.layout.html @@ -18,7 +18,7 @@