From f7206db295b215a0086bbd5ebbfb39d3becba36e Mon Sep 17 00:00:00 2001 From: Jocadbz Date: Tue, 15 Apr 2025 21:40:01 -0300 Subject: [PATCH] Create admin user, admin can edit news blotter --- config/config-skeleton.json | 6 ++-- handlers/app.go | 14 ++++---- handlers/news.go | 69 ++++++++++++++++++++++++++++++++++--- main.go | 53 ++++++++++++++++++++++++++++ models/news.go | 53 ++++++++++++++++++++++++++++ templates/pages/news.html | 25 +++++++++++++- 6 files changed, 206 insertions(+), 14 deletions(-) create mode 100644 models/news.go diff --git a/config/config-skeleton.json b/config/config-skeleton.json index 433463b..54e1824 100644 --- a/config/config-skeleton.json +++ b/config/config-skeleton.json @@ -4,5 +4,7 @@ "db_username": "threadr_user", "db_password": "threadr_password", "db_database": "threadr_db", - "db_svr_host": "localhost:3306" -} \ No newline at end of file + "db_svr_host": "localhost:3306", + "admin_username": "admin", + "admin_password": "adminpassword" +} diff --git a/handlers/app.go b/handlers/app.go index 9f4773f..062c4cb 100644 --- a/handlers/app.go +++ b/handlers/app.go @@ -19,12 +19,14 @@ type PageData struct { } type Config struct { - DomainName string `json:"domain_name"` - ThreadrDir string `json:"threadr_dir"` - DBUsername string `json:"db_username"` - DBPassword string `json:"db_password"` - DBDatabase string `json:"db_database"` - DBServerHost string `json:"db_svr_host"` + DomainName string `json:"domain_name"` + ThreadrDir string `json:"threadr_dir"` + DBUsername string `json:"db_username"` + DBPassword string `json:"db_password"` + DBDatabase string `json:"db_database"` + DBServerHost string `json:"db_svr_host"` + AdminUsername string `json:"admin_username"` + AdminPassword string `json:"admin_password"` } type App struct { diff --git a/handlers/news.go b/handlers/news.go index 32cc172..2c10a85 100644 --- a/handlers/news.go +++ b/handlers/news.go @@ -3,6 +3,8 @@ package handlers import ( "log" "net/http" + "strconv" + "threadr/models" "github.com/gorilla/sessions" ) @@ -11,13 +13,69 @@ func NewsHandler(app *App) http.HandlerFunc { session := r.Context().Value("session").(*sessions.Session) loggedIn := session.Values["user_id"] != nil cookie, _ := r.Cookie("threadr_cookie_banner") - newsItems := []string{ - "2020-02-21 Whole Website updated: Homepage, News, Boards, About, Log In, Userhome, Log Out", - "2020-01-06 First Steps done", + userID, _ := session.Values["user_id"].(int) + isAdmin := false + + if loggedIn { + user, err := models.GetUserByID(app.DB, userID) + if err != nil { + log.Printf("Error fetching user: %v", err) + } else if user != nil { + isAdmin = models.HasGlobalPermission(user, models.PermManageUsers) + } } + + if r.Method == http.MethodPost && loggedIn && isAdmin { + if action := r.URL.Query().Get("action"); action == "delete" { + newsIDStr := r.URL.Query().Get("id") + newsID, err := strconv.Atoi(newsIDStr) + if err != nil { + http.Error(w, "Invalid news ID", http.StatusBadRequest) + return + } + err = models.DeleteNews(app.DB, newsID) + if err != nil { + log.Printf("Error deleting news item: %v", err) + http.Error(w, "Failed to delete news item", http.StatusInternalServerError) + return + } + http.Redirect(w, r, app.Config.ThreadrDir+"/news/", http.StatusFound) + return + } else { + title := r.FormValue("title") + content := r.FormValue("content") + if title != "" && content != "" { + news := models.News{ + Title: title, + Content: content, + PostedBy: userID, + } + err := models.CreateNews(app.DB, news) + if err != nil { + log.Printf("Error creating news item: %v", err) + http.Error(w, "Failed to create news item", http.StatusInternalServerError) + return + } + http.Redirect(w, r, app.Config.ThreadrDir+"/news/", http.StatusFound) + return + } else { + http.Error(w, "Title and content are required", http.StatusBadRequest) + return + } + } + } + + newsItems, err := models.GetAllNews(app.DB) + if err != nil { + log.Printf("Error fetching news items: %v", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + data := struct { PageData - News []string + News []models.News + IsAdmin bool }{ PageData: PageData{ Title: "ThreadR - News", @@ -28,7 +86,8 @@ func NewsHandler(app *App) http.HandlerFunc { StaticPath: app.Config.ThreadrDir + "/static", CurrentURL: r.URL.Path, }, - News: newsItems, + News: newsItems, + IsAdmin: isAdmin, } if err := app.Tmpl.ExecuteTemplate(w, "news", data); err != nil { log.Printf("Error executing template in NewsHandler: %v", err) diff --git a/main.go b/main.go index 3fc43e4..0061744 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" "threadr/handlers" + "threadr/models" "github.com/gorilla/sessions" _ "github.com/go-sql-driver/mysql" @@ -168,10 +169,56 @@ func createTablesIfNotExist(db *sql.DB) error { return fmt.Errorf("error creating reposts table: %v", err) } + // Create news table + _, err = db.Exec(` + CREATE TABLE IF NOT EXISTS news ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + content TEXT NOT NULL, + posted_by INT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )`) + if err != nil { + return fmt.Errorf("error creating news table: %v", err) + } + log.Println("Database tables created or already exist") return nil } +func ensureAdminUser(db *sql.DB, config *handlers.Config) error { + adminUser, err := models.GetUserByUsername(db, config.AdminUsername) + if err != nil && err != sql.ErrNoRows { + return fmt.Errorf("error checking for admin user: %v", err) + } + + // If admin user doesn't exist, create one + if adminUser == nil { + log.Printf("Creating admin user: %s", config.AdminUsername) + err = models.CreateUser(db, config.AdminUsername, config.AdminPassword) + if err != nil { + return fmt.Errorf("error creating admin user: %v", err) + } + + // Get the newly created admin user to update permissions + adminUser, err = models.GetUserByUsername(db, config.AdminUsername) + if err != nil { + return fmt.Errorf("error fetching new admin user: %v", err) + } + + // Set admin permissions (all permissions) + _, err = db.Exec("UPDATE users SET permissions = ? WHERE id = ?", + models.PermCreateBoard|models.PermManageUsers, adminUser.ID) + if err != nil { + return fmt.Errorf("error setting admin permissions: %v", err) + } + log.Println("Admin user created successfully with full permissions") + } else { + log.Println("Admin user already exists") + } + return nil +} + func main() { config, err := loadConfig("config/config.json") if err != nil { @@ -191,6 +238,12 @@ func main() { log.Fatal("Error creating database tables:", err) } + // Ensure admin user exists + err = ensureAdminUser(db, config) + if err != nil { + log.Fatal("Error ensuring admin user:", err) + } + dir, err := os.Getwd() if err != nil { log.Fatal("Error getting working directory:", err) diff --git a/models/news.go b/models/news.go new file mode 100644 index 0000000..17d6dae --- /dev/null +++ b/models/news.go @@ -0,0 +1,53 @@ +package models + +import ( + "database/sql" + "time" +) + +type News struct { + ID int + Title string + Content string + PostedBy int + CreatedAt time.Time +} + +func GetAllNews(db *sql.DB) ([]News, error) { + query := "SELECT id, title, content, posted_by, created_at FROM news ORDER BY created_at DESC" + rows, err := db.Query(query) + if err != nil { + return nil, err + } + defer rows.Close() + + var newsItems []News + for rows.Next() { + news := News{} + var createdAtStr string + err := rows.Scan(&news.ID, &news.Title, &news.Content, &news.PostedBy, &createdAtStr) + if err != nil { + return nil, err + } + // Parse the timestamp string into time.Time + news.CreatedAt, err = time.Parse("2006-01-02 15:04:05", createdAtStr) + if err != nil { + // Fallback to a default time if parsing fails + news.CreatedAt = time.Time{} + } + newsItems = append(newsItems, news) + } + return newsItems, nil +} + +func CreateNews(db *sql.DB, news News) error { + query := "INSERT INTO news (title, content, posted_by, created_at) VALUES (?, ?, ?, NOW())" + _, err := db.Exec(query, news.Title, news.Content, news.PostedBy) + return err +} + +func DeleteNews(db *sql.DB, id int) error { + query := "DELETE FROM news WHERE id = ?" + _, err := db.Exec(query, id) + return err +} \ No newline at end of file diff --git a/templates/pages/news.html b/templates/pages/news.html index 74c3fc4..260ee18 100644 --- a/templates/pages/news.html +++ b/templates/pages/news.html @@ -12,12 +12,35 @@

News

+ {{if .News}} + {{else}} +

No news items available at the moment.

+ {{end}}
+ {{if .IsAdmin}} +
+

Post New Announcement

+
+ +
+ +
+ +
+
+ {{end}} {{template "cookie_banner" .}}