Create admin user, admin can edit news blotter
parent
3c438b0ee2
commit
f7206db295
|
@ -4,5 +4,7 @@
|
|||
"db_username": "threadr_user",
|
||||
"db_password": "threadr_password",
|
||||
"db_database": "threadr_db",
|
||||
"db_svr_host": "localhost:3306"
|
||||
"db_svr_host": "localhost:3306",
|
||||
"admin_username": "admin",
|
||||
"admin_password": "adminpassword"
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
53
main.go
53
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)
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -12,12 +12,35 @@
|
|||
<h2>News</h2>
|
||||
</header>
|
||||
<section>
|
||||
{{if .News}}
|
||||
<ul>
|
||||
{{range .News}}
|
||||
<li>{{.}}</li>
|
||||
<li><strong>{{.Title}}</strong> - Posted on {{.CreatedAt.Format "02/01/2006 - 15:04"}}
|
||||
<p>{{.Content}}</p>
|
||||
{{if $.IsAdmin}}
|
||||
<form method="post" action="{{$.BasePath}}/news/?action=delete&id={{.ID}}" style="display:inline;">
|
||||
<button type="submit" onclick="return confirm('Are you sure you want to delete this news item?')">Delete</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p>No news items available at the moment.</p>
|
||||
{{end}}
|
||||
</section>
|
||||
{{if .IsAdmin}}
|
||||
<section>
|
||||
<h3>Post New Announcement</h3>
|
||||
<form method="post" action="{{.BasePath}}/news/">
|
||||
<label for="title">Title:</label>
|
||||
<input type="text" id="title" name="title" required><br>
|
||||
<label for="content">Content:</label>
|
||||
<textarea id="content" name="content" required></textarea><br>
|
||||
<input type="submit" value="Post News">
|
||||
</form>
|
||||
</section>
|
||||
{{end}}
|
||||
</main>
|
||||
{{template "cookie_banner" .}}
|
||||
</body>
|
||||
|
|
Loading…
Reference in New Issue