Compare commits
76 Commits
123071ab1b
...
v0.13.4
Author | SHA1 | Date | |
---|---|---|---|
d328ddb749 | |||
ac740cf4b8 | |||
b7d82f15e9 | |||
b4003c8216 | |||
5dc5590da9 | |||
81c046c1b0 | |||
364112a0a4 | |||
1e9fdd2ab9 | |||
a38523e933 | |||
1fbc0ddcf6 | |||
0dd2101a08 | |||
e95871ee70 | |||
083718711d | |||
20a12c6299 | |||
200672dae2 | |||
be829e662b | |||
3d3aad88c8 | |||
0036b42d82 | |||
e4e43d1a83 | |||
59deb69e2f | |||
3aef27585a | |||
3aa8796537 | |||
737a9ec314 | |||
4b75fc61cd | |||
1ebe0380ee | |||
c439e048c1 | |||
f86f2ba146 | |||
d62d71b5d1 | |||
07e1983fcc | |||
878f57af08 | |||
d86b9027bf | |||
31484dd44a | |||
3b4e1e01d2 | |||
03425fc2c6 | |||
0b9bae3bf8 | |||
8ed0676e51 | |||
d7cbb34814 | |||
23f0c6f4a4 | |||
cb322c57f9 | |||
b36e0ea503 | |||
bc4d8fa37e | |||
d2b21e7405 | |||
e3c192359f | |||
46532e4c85 | |||
c722135a56 | |||
887fa863bc | |||
74d71cfb6a | |||
ca7e7cddd3 | |||
94431a2aa9 | |||
5b1f20c5bc | |||
d0c566f8df | |||
5e586aa49a | |||
66b2743d3d | |||
3723b2b5e6 | |||
ce788bfd50 | |||
230a6278cc | |||
42d6e0c198 | |||
e1af2979af | |||
f6dedc6f10 | |||
cdf0a49550 | |||
c3c0650210 | |||
d077f700d8 | |||
ec752b1c66 | |||
46aef4f12f | |||
1b29e328cf | |||
e50cb819f3 | |||
c32e38ca10 | |||
d7c8c7a43a | |||
1cd3edc90c | |||
0e768c9f61 | |||
1fcd775cc5 | |||
203a1ed147 | |||
ef1914ee5c | |||
084b101e31 | |||
b2db128aa9 | |||
081e880fb6 |
@ -4,22 +4,23 @@ tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
args_bin = [
|
||||
"-aes tmp/cpolis.aes",
|
||||
"-articles tmp/articles",
|
||||
"-banner-width 512",
|
||||
"-config tmp/config.toml",
|
||||
"-desc 'Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität'",
|
||||
"-domain localhost",
|
||||
"-feed tmp/cpolis.atom",
|
||||
"-firebase tmp/firebase.json",
|
||||
"-key tmp/key.gob",
|
||||
"-gob tmp/cpolis.gob",
|
||||
"-img-width 256",
|
||||
"-link https://distrikt-ni-st.de",
|
||||
"-log tmp/cpolis.log",
|
||||
"-pdfs tmp/pdfs",
|
||||
"-pics tmp/pics",
|
||||
"-port 8080",
|
||||
"-rss tmp/orientexpress_alle.rss",
|
||||
"-title 'Freimaurer Distrikt Niedersachsen und Sachsen-Anhalt'",
|
||||
"-web web",
|
||||
"-width 1024",
|
||||
]
|
||||
bin = "./tmp/main"
|
||||
cmd = "go build -o ./tmp/main ./cmd/main.go"
|
||||
|
@ -8,8 +8,6 @@ import (
|
||||
"git.streifling.com/jason/atom"
|
||||
)
|
||||
|
||||
type Feed struct{ *atom.Feed }
|
||||
|
||||
func GenerateAtomFeed(c *Config, db *DB) (*string, error) {
|
||||
feed := atom.NewFeed(c.Title)
|
||||
feed.ID = atom.NewID("urn:feed:1")
|
||||
@ -18,45 +16,48 @@ func GenerateAtomFeed(c *Config, db *DB) (*string, error) {
|
||||
|
||||
feed.Generator = atom.NewGenerator("cpolis")
|
||||
feed.Generator.URI = "https://git.streifling.com/jason/cpolis"
|
||||
feed.Generator.Version = "0.13"
|
||||
feed.Generator.Version = c.Version
|
||||
|
||||
articles, err := db.GetCertainArticles("published", true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting published articles for RSS feed: %v", err)
|
||||
return nil, fmt.Errorf("error getting published articles for Atom feed: %v", err)
|
||||
}
|
||||
|
||||
for _, article := range articles {
|
||||
articleTitle, err := ConvertToPlain(article.Title)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting title to plain text for RSS feed: %v", err)
|
||||
return nil, fmt.Errorf("error converting title to plain text for Atom feed: %v", err)
|
||||
}
|
||||
entry := atom.NewEntry(articleTitle)
|
||||
entry.ID = atom.NewID(fmt.Sprint("urn:entry:", article.ID))
|
||||
entry.Content = atom.NewContent(atom.OutOfLine, "text/hmtl", article.ContentLink)
|
||||
entry.Published = atom.NewDate(article.Created)
|
||||
entry.Content = atom.NewContent(atom.OutOfLine, "text/hmtl", article.ContentLink)
|
||||
|
||||
linkID := entry.AddLink(atom.NewLink(article.BannerLink))
|
||||
entry.Links[linkID].Rel = "enclosure"
|
||||
entry.Links[linkID].Type = "image/webp"
|
||||
if article.AutoGenerated {
|
||||
entry.Summary = atom.NewText("text", "automatically generated")
|
||||
} else {
|
||||
articleSummary, err := ConvertToPlain(article.Summary)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting description to plain text for Atom feed: %v", err)
|
||||
}
|
||||
entry.Summary = atom.NewText("text", articleSummary)
|
||||
}
|
||||
|
||||
user, err := db.GetUser(article.AuthorID)
|
||||
if len(article.BannerLink) > 0 {
|
||||
linkID := entry.AddLink(atom.NewLink(article.BannerLink))
|
||||
entry.Links[linkID].Rel = "enclosure"
|
||||
entry.Links[linkID].Type = "image/webp"
|
||||
}
|
||||
|
||||
user, err := db.GetUser(c, article.AuthorID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting user user info for RSS feed: %v", err)
|
||||
return nil, fmt.Errorf("error getting user user info for Atom feed: %v", err)
|
||||
}
|
||||
entry.AddAuthor(atom.NewPerson(user.FirstName + " " + user.LastName))
|
||||
|
||||
articleSummary, err := ConvertToPlain(article.Summary)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting description to plain text for RSS feed: %v", err)
|
||||
}
|
||||
if article.AutoGenerated {
|
||||
articleSummary = "auto generated"
|
||||
}
|
||||
entry.Summary = atom.NewText("text", articleSummary)
|
||||
|
||||
tags, err := db.GetArticleTags(article.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting tags for articles for RSS feed: %v", err)
|
||||
return nil, fmt.Errorf("error getting tags for articles for Atom feed: %v", err)
|
||||
}
|
||||
for _, tag := range tags {
|
||||
entry.AddCategory(atom.NewCategory(tag.Name))
|
||||
@ -79,7 +80,7 @@ func GenerateAtomFeed(c *Config, db *DB) (*string, error) {
|
||||
|
||||
atom, err := feed.ToXML("UTF-8")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting RSS feed to XML: %v", err)
|
||||
return nil, fmt.Errorf("error converting Atom feed to XML: %v", err)
|
||||
}
|
||||
|
||||
return &atom, nil
|
||||
|
@ -12,42 +12,48 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ArticleDir string
|
||||
ConfigFile string
|
||||
DBName string
|
||||
Description string
|
||||
Domain string
|
||||
AtomFeed string
|
||||
FirebaseKey string
|
||||
KeyFile string
|
||||
Link string
|
||||
LogFile string
|
||||
PDFDir string
|
||||
PicsDir string
|
||||
Port string
|
||||
RSSFile string
|
||||
Title string
|
||||
WebDir string
|
||||
MaxImgHeight int
|
||||
MaxImgWidth int
|
||||
AESKeyFile string
|
||||
ArticleDir string
|
||||
ConfigFile string
|
||||
DBName string
|
||||
Description string
|
||||
Domain string
|
||||
AtomFile string
|
||||
FirebaseKey string
|
||||
GOBKeyFile string
|
||||
Link string
|
||||
LogFile string
|
||||
PDFDir string
|
||||
PicsDir string
|
||||
Port string
|
||||
Title string
|
||||
Version string
|
||||
WebDir string
|
||||
MaxBannerHeight int
|
||||
MaxBannerWidth int
|
||||
MaxImgHeight int
|
||||
MaxImgWidth int
|
||||
}
|
||||
|
||||
func newConfig() *Config {
|
||||
return &Config{
|
||||
ArticleDir: "/var/www/cpolis/articles",
|
||||
ConfigFile: "/etc/cpolis/config.toml",
|
||||
DBName: "cpolis",
|
||||
AtomFeed: "/var/www/cpolis/cpolis.atom",
|
||||
FirebaseKey: "/var/www/cpolis/serviceAccountKey.json",
|
||||
KeyFile: "/var/www/cpolis/cpolis.key",
|
||||
LogFile: "/var/log/cpolis.log",
|
||||
MaxImgHeight: 1080,
|
||||
MaxImgWidth: 1920,
|
||||
PDFDir: "/var/www/cpolis/pdfs",
|
||||
PicsDir: "/var/www/cpolis/pics",
|
||||
Port: ":8080",
|
||||
RSSFile: "/var/www/cpolis/cpolis.rss",
|
||||
WebDir: "/var/www/cpolis/web",
|
||||
AESKeyFile: "/var/www/cpolis/aes.key",
|
||||
ArticleDir: "/var/www/cpolis/articles",
|
||||
AtomFile: "/var/www/cpolis/cpolis.atom",
|
||||
ConfigFile: "/etc/cpolis/config.toml",
|
||||
DBName: "cpolis",
|
||||
FirebaseKey: "/var/www/cpolis/serviceAccountKey.json",
|
||||
GOBKeyFile: "/var/www/cpolis/gob.key",
|
||||
LogFile: "/var/log/cpolis.log",
|
||||
MaxBannerHeight: 1080,
|
||||
MaxBannerWidth: 1920,
|
||||
MaxImgHeight: 1080,
|
||||
MaxImgWidth: 1920,
|
||||
PDFDir: "/var/www/cpolis/pdfs",
|
||||
PicsDir: "/var/www/cpolis/pics",
|
||||
Port: ":8080",
|
||||
Version: "v0.13.4",
|
||||
WebDir: "/var/www/cpolis/web",
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,23 +108,25 @@ func (c *Config) handleCliArgs() error {
|
||||
var port int
|
||||
var err error
|
||||
|
||||
flag.StringVar(&c.AESKeyFile, "aes", c.AESKeyFile, "aes key file")
|
||||
flag.StringVar(&c.ArticleDir, "articles", c.ArticleDir, "articles directory")
|
||||
flag.StringVar(&c.AtomFeed, "feed", c.AtomFeed, "atom feed file")
|
||||
flag.StringVar(&c.AtomFile, "feed", c.AtomFile, "atom feed file")
|
||||
flag.StringVar(&c.ConfigFile, "config", c.ConfigFile, "config file")
|
||||
flag.StringVar(&c.DBName, "db", c.DBName, "DB name")
|
||||
flag.StringVar(&c.Description, "desc", c.Description, "channel description")
|
||||
flag.StringVar(&c.Domain, "domain", c.Domain, "domain name")
|
||||
flag.StringVar(&c.FirebaseKey, "firebase", c.FirebaseKey, "Firebase service account key file")
|
||||
flag.StringVar(&c.KeyFile, "key", c.KeyFile, "key file")
|
||||
flag.StringVar(&c.GOBKeyFile, "gob", c.GOBKeyFile, "gob key file")
|
||||
flag.StringVar(&c.Link, "link", c.Link, "channel Link")
|
||||
flag.StringVar(&c.LogFile, "log", c.LogFile, "log file")
|
||||
flag.StringVar(&c.PDFDir, "pdfs", c.PDFDir, "pdf directory")
|
||||
flag.StringVar(&c.PicsDir, "pics", c.PicsDir, "pictures directory")
|
||||
flag.StringVar(&c.RSSFile, "rss", c.RSSFile, "RSS file")
|
||||
flag.StringVar(&c.Title, "title", c.Title, "channel title")
|
||||
flag.StringVar(&c.WebDir, "web", c.WebDir, "web directory")
|
||||
flag.IntVar(&c.MaxImgHeight, "height", c.MaxImgHeight, "maximum image height")
|
||||
flag.IntVar(&c.MaxImgWidth, "width", c.MaxImgWidth, "maximum image width")
|
||||
flag.IntVar(&c.MaxBannerHeight, "banner-height", c.MaxBannerHeight, "maximum banner height")
|
||||
flag.IntVar(&c.MaxBannerWidth, "banner-width", c.MaxBannerWidth, "maximum banner width")
|
||||
flag.IntVar(&c.MaxImgHeight, "img-height", c.MaxImgHeight, "maximum image height")
|
||||
flag.IntVar(&c.MaxImgWidth, "img-width", c.MaxImgWidth, "maximum image width")
|
||||
flag.IntVar(&port, "port", port, "port")
|
||||
flag.Parse()
|
||||
|
||||
@ -147,6 +155,14 @@ func (c *Config) setupConfig(cliConfig *Config) error {
|
||||
var err error
|
||||
defaultConfig := newConfig()
|
||||
|
||||
if cliConfig.AESKeyFile != defaultConfig.AESKeyFile {
|
||||
c.AESKeyFile = cliConfig.AESKeyFile
|
||||
}
|
||||
c.AESKeyFile, err = mkFile(c.AESKeyFile, 0600, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error setting up file: %v", err)
|
||||
}
|
||||
|
||||
if cliConfig.ArticleDir != defaultConfig.ArticleDir {
|
||||
c.ArticleDir = cliConfig.ArticleDir
|
||||
}
|
||||
@ -171,10 +187,10 @@ func (c *Config) setupConfig(cliConfig *Config) error {
|
||||
c.Domain = "https://" + c.Domain
|
||||
}
|
||||
|
||||
if cliConfig.AtomFeed != defaultConfig.AtomFeed {
|
||||
c.AtomFeed = cliConfig.AtomFeed
|
||||
if cliConfig.AtomFile != defaultConfig.AtomFile {
|
||||
c.AtomFile = cliConfig.AtomFile
|
||||
}
|
||||
c.AtomFeed, err = mkFile(c.AtomFeed, 0644, 0744)
|
||||
c.AtomFile, err = mkFile(c.AtomFile, 0644, 0744)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error setting up file: %v", err)
|
||||
}
|
||||
@ -187,10 +203,10 @@ func (c *Config) setupConfig(cliConfig *Config) error {
|
||||
return fmt.Errorf("error setting up file: %v", err)
|
||||
}
|
||||
|
||||
if cliConfig.KeyFile != defaultConfig.KeyFile {
|
||||
c.KeyFile = cliConfig.KeyFile
|
||||
if cliConfig.GOBKeyFile != defaultConfig.GOBKeyFile {
|
||||
c.GOBKeyFile = cliConfig.GOBKeyFile
|
||||
}
|
||||
c.KeyFile, err = mkFile(c.KeyFile, 0600, 0700)
|
||||
c.GOBKeyFile, err = mkFile(c.GOBKeyFile, 0600, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error setting up file: %v", err)
|
||||
}
|
||||
@ -207,6 +223,14 @@ func (c *Config) setupConfig(cliConfig *Config) error {
|
||||
return fmt.Errorf("error setting up file: %v", err)
|
||||
}
|
||||
|
||||
if cliConfig.MaxBannerHeight != defaultConfig.MaxBannerHeight {
|
||||
c.MaxBannerHeight = cliConfig.MaxBannerHeight
|
||||
}
|
||||
|
||||
if cliConfig.MaxBannerWidth != defaultConfig.MaxBannerWidth {
|
||||
c.MaxBannerWidth = cliConfig.MaxBannerWidth
|
||||
}
|
||||
|
||||
if cliConfig.MaxImgHeight != defaultConfig.MaxImgHeight {
|
||||
c.MaxImgHeight = cliConfig.MaxImgHeight
|
||||
}
|
||||
@ -235,14 +259,6 @@ func (c *Config) setupConfig(cliConfig *Config) error {
|
||||
c.Port = cliConfig.Port
|
||||
}
|
||||
|
||||
if cliConfig.RSSFile != defaultConfig.RSSFile {
|
||||
c.RSSFile = cliConfig.RSSFile
|
||||
}
|
||||
c.RSSFile, err = mkFile(c.RSSFile, 0600, 0700)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error setting up file: %v", err)
|
||||
}
|
||||
|
||||
if cliConfig.Title != defaultConfig.Title {
|
||||
c.Title = cliConfig.Title
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
|
||||
var ErrUnsupportedFormat error = image.ErrFormat // used internally by imaging
|
||||
|
||||
func SaveImage(c *Config, src io.Reader) (string, error) {
|
||||
func SaveImage(src io.Reader, maxHeight, maxWidth int, path string) (string, error) {
|
||||
img, err := imaging.Decode(src, imaging.AutoOrientation(true))
|
||||
if err != nil {
|
||||
if err == ErrUnsupportedFormat {
|
||||
@ -22,15 +22,15 @@ func SaveImage(c *Config, src io.Reader) (string, error) {
|
||||
return "", fmt.Errorf("error decoding image: %v", err)
|
||||
}
|
||||
|
||||
if img.Bounds().Dy() > c.MaxImgHeight {
|
||||
img = imaging.Resize(img, 0, c.MaxImgHeight, imaging.Lanczos)
|
||||
if img.Bounds().Dy() > maxHeight {
|
||||
img = imaging.Resize(img, 0, maxHeight, imaging.Lanczos)
|
||||
}
|
||||
if img.Bounds().Dx() > c.MaxImgWidth {
|
||||
img = imaging.Resize(img, c.MaxImgWidth, 0, imaging.Lanczos)
|
||||
if img.Bounds().Dx() > maxWidth {
|
||||
img = imaging.Resize(img, maxWidth, 0, imaging.Lanczos)
|
||||
}
|
||||
|
||||
filename := fmt.Sprint(uuid.New(), ".webp")
|
||||
file, err := os.Create(c.PicsDir + "/" + filename)
|
||||
file, err := os.Create(path + filename)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error creating new image file: %v", err)
|
||||
}
|
||||
|
@ -1,103 +0,0 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.streifling.com/jason/rss"
|
||||
)
|
||||
|
||||
func GenerateRSS(c *Config, db *DB) (*string, error) {
|
||||
channel := &rss.Channel{
|
||||
Title: c.Title,
|
||||
Link: c.Link,
|
||||
Description: c.Description,
|
||||
Items: make([]*rss.Item, 0),
|
||||
}
|
||||
|
||||
articles, err := db.GetCertainArticles("published", true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting published articles for RSS feed: %v", err)
|
||||
}
|
||||
|
||||
for _, article := range articles {
|
||||
tags, err := db.GetArticleTags(article.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting tags for articles for RSS feed: %v", err)
|
||||
}
|
||||
tagNames := make([]string, 0)
|
||||
for _, tag := range tags {
|
||||
tagNames = append(tagNames, tag.Name)
|
||||
}
|
||||
|
||||
if article.IsInIssue || article.AutoGenerated {
|
||||
tagNames = append(tagNames, fmt.Sprint("Orient Express ", article.IssueID))
|
||||
}
|
||||
if article.AutoGenerated {
|
||||
tagNames = append(tagNames, "autogenerated")
|
||||
}
|
||||
|
||||
user, err := db.GetUser(article.AuthorID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting user user info for RSS feed: %v", err)
|
||||
}
|
||||
|
||||
articleTitle, err := ConvertToPlain(article.Title)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting title to plain text for RSS feed: %v", err)
|
||||
}
|
||||
|
||||
articleDescription, err := ConvertToPlain(article.Summary)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting description to plain text for RSS feed: %v", err)
|
||||
}
|
||||
|
||||
item := &rss.Item{
|
||||
Author: user.FirstName + " " + user.LastName,
|
||||
Categories: tagNames,
|
||||
Description: articleDescription,
|
||||
Guid: string(article.ID),
|
||||
Link: article.ContentLink,
|
||||
PubDate: article.Created.Format(time.RFC1123Z),
|
||||
Title: articleTitle,
|
||||
}
|
||||
|
||||
// if article.AutoGenerated {
|
||||
// item.Enclosure = &rss.Enclosure{
|
||||
// Url: article.EncURL,
|
||||
// Lenght: article.EncLength,
|
||||
// Type: article.EncType,
|
||||
// }
|
||||
// }
|
||||
//
|
||||
channel.Items = append(channel.Items, item)
|
||||
}
|
||||
|
||||
feed := rss.NewFeed()
|
||||
feed.Channels = append(feed.Channels, channel)
|
||||
rss, err := feed.ToXML("UTF-8")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting RSS feed to XML: %v", err)
|
||||
}
|
||||
|
||||
return &rss, nil
|
||||
}
|
||||
|
||||
func SaveRSS(filename string, feed *string) error {
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating file for RSS feed: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
if err = file.Chmod(0644); err != nil {
|
||||
return fmt.Errorf("error setting permissions for RSS file: %v", err)
|
||||
}
|
||||
|
||||
if _, err = io.WriteString(file, *feed); err != nil {
|
||||
return fmt.Errorf("error writing to RSS file: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -2,9 +2,16 @@ package backend
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
@ -18,24 +25,135 @@ const (
|
||||
)
|
||||
|
||||
type User struct {
|
||||
UserName string
|
||||
FirstName string
|
||||
LastName string
|
||||
ID int64
|
||||
Role int
|
||||
UserName string
|
||||
FirstName string
|
||||
LastName string
|
||||
Email string
|
||||
ProfilePicLink string
|
||||
ID int64
|
||||
Role int
|
||||
}
|
||||
|
||||
func (db *DB) AddUser(u *User, pass string) (int64, error) {
|
||||
func readKey(filename string) ([]byte, error) {
|
||||
key, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading from aes key file: %v", err)
|
||||
}
|
||||
|
||||
if len(key) != 44 {
|
||||
return nil, errors.New("key is not 32 bytes long")
|
||||
}
|
||||
|
||||
key, err = base64.StdEncoding.DecodeString(string(key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error base64 decoding key: %v", err)
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func key(c *Config) ([]byte, error) {
|
||||
key, err := readKey(c.AESKeyFile)
|
||||
if err != nil {
|
||||
key = make([]byte, 32)
|
||||
if _, err := rand.Read(key); err != nil {
|
||||
return nil, fmt.Errorf("error generating random key: %v", err)
|
||||
}
|
||||
|
||||
fileKey := make([]byte, 44)
|
||||
base64.StdEncoding.Encode(fileKey, key)
|
||||
if err = os.WriteFile(c.AESKeyFile, fileKey, 0600); err != nil {
|
||||
return nil, fmt.Errorf("error writing key to file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func aesEncrypt(c *Config, plaintext string) (string, error) {
|
||||
key, err := key(c)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error retrieving key: %v", err)
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error creating cipher block: %v", err)
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error creating new gcm: %v", err)
|
||||
}
|
||||
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return "", fmt.Errorf("error creating nonce: %v", err)
|
||||
}
|
||||
|
||||
cipherText := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
|
||||
return base64.StdEncoding.EncodeToString(cipherText), nil
|
||||
}
|
||||
|
||||
func aesDecrypt(c *Config, ciphertext string) (string, error) {
|
||||
key, err := key(c)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error retrieving key: %v", err)
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error creating cipher block: %v", err)
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error creating new gcm: %v", err)
|
||||
}
|
||||
|
||||
data, err := base64.StdEncoding.DecodeString(ciphertext)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error base64 decoding ciphertext: %v", err)
|
||||
}
|
||||
|
||||
nonceSize := gcm.NonceSize()
|
||||
nonce, cipherText := data[:nonceSize], data[nonceSize:]
|
||||
|
||||
plaintext, err := gcm.Open(nil, nonce, cipherText, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error aes decoding ciphertext: %v", err)
|
||||
}
|
||||
|
||||
return string(plaintext), nil
|
||||
}
|
||||
|
||||
func (db *DB) AddUser(c *Config, u *User, pass string) (int64, error) {
|
||||
hashedPass, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error creating password hash: %v", err)
|
||||
}
|
||||
|
||||
aesFirstName, err := aesEncrypt(c, u.FirstName)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error encrypting first name: %v", err)
|
||||
}
|
||||
|
||||
aesLastName, err := aesEncrypt(c, u.LastName)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error encrypting last name: %v", err)
|
||||
}
|
||||
|
||||
aesEmail, err := aesEncrypt(c, u.Email)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error encrypting email: %v", err)
|
||||
}
|
||||
|
||||
query := `
|
||||
INSERT INTO users (username, password, first_name, last_name, role)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
INSERT INTO users (username, password, first_name, last_name, email, role)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
`
|
||||
result, err := db.Exec(query, u.UserName, string(hashedPass), u.FirstName, u.LastName, u.Role)
|
||||
|
||||
result, err := db.Exec(query, u.UserName, string(hashedPass), aesFirstName, aesLastName, aesEmail, u.Role)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error inserting new user %v into DB: %v", u.UserName, err)
|
||||
}
|
||||
@ -129,34 +247,44 @@ func (tx *Tx) ChangePassword(id int64, oldPass, newPass string) error {
|
||||
}
|
||||
|
||||
// TODO: No need for ID field in general
|
||||
func (db *DB) GetUser(id int64) (*User, error) {
|
||||
func (db *DB) GetUser(c *Config, id int64) (*User, error) {
|
||||
var aesFirstName, aesLastName, aesEmail string
|
||||
var err error
|
||||
|
||||
user := new(User)
|
||||
query := `
|
||||
SELECT id, username, first_name, last_name, role
|
||||
SELECT id, username, first_name, last_name, email, role
|
||||
FROM users
|
||||
WHERE id = ?
|
||||
`
|
||||
|
||||
row := db.QueryRow(query, id)
|
||||
if err := row.Scan(&user.ID, &user.UserName, &user.FirstName,
|
||||
&user.LastName, &user.Role); err != nil {
|
||||
if err := row.Scan(&user.ID, &user.UserName, &aesFirstName, &aesLastName, &aesEmail, &user.Role); err != nil {
|
||||
return nil, fmt.Errorf("error reading user information: %v", err)
|
||||
}
|
||||
|
||||
user.FirstName, err = aesDecrypt(c, aesFirstName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decrypting first name: %v", err)
|
||||
}
|
||||
|
||||
user.LastName, err = aesDecrypt(c, aesLastName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decrypting last name: %v", err)
|
||||
}
|
||||
|
||||
user.Email, err = aesDecrypt(c, aesEmail)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decrypting email: %v", err)
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (db *DB) UpdateOwnUserAttributes(id int64, user, first, last, oldPass, newPass, newPass2 string) error {
|
||||
passwordEmpty := true
|
||||
if len(newPass) > 0 || len(newPass2) > 0 {
|
||||
if newPass != newPass2 {
|
||||
return fmt.Errorf("error: passwords do not match")
|
||||
}
|
||||
passwordEmpty = false
|
||||
}
|
||||
|
||||
tx := new(Tx)
|
||||
func (db *DB) UpdateOwnUserAttributes(c *Config, id int64, userName, firstName, lastName, email, oldPass, newPass string) error {
|
||||
var err error
|
||||
tx := new(Tx)
|
||||
passwordEmpty := len(newPass) > 0
|
||||
|
||||
for i := 0; i < TxMaxRetries; i++ {
|
||||
err := func() error {
|
||||
@ -174,10 +302,35 @@ func (db *DB) UpdateOwnUserAttributes(id int64, user, first, last, oldPass, newP
|
||||
}
|
||||
}
|
||||
|
||||
aesFirstName, err := aesEncrypt(c, firstName)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
}
|
||||
return fmt.Errorf("error encrypting first name: %v", err)
|
||||
}
|
||||
|
||||
aesLastName, err := aesEncrypt(c, lastName)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
}
|
||||
return fmt.Errorf("error encrypting last name: %v", err)
|
||||
}
|
||||
|
||||
aesEmail, err := aesEncrypt(c, email)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
}
|
||||
return fmt.Errorf("error encrypting email: %v", err)
|
||||
}
|
||||
|
||||
if err = tx.UpdateAttributes(
|
||||
&Attribute{Table: "users", ID: id, AttName: "username", Value: user},
|
||||
&Attribute{Table: "users", ID: id, AttName: "first_name", Value: first},
|
||||
&Attribute{Table: "users", ID: id, AttName: "last_name", Value: last},
|
||||
&Attribute{Table: "users", ID: id, AttName: "username", Value: userName},
|
||||
&Attribute{Table: "users", ID: id, AttName: "first_name", Value: aesFirstName},
|
||||
&Attribute{Table: "users", ID: id, AttName: "last_name", Value: aesLastName},
|
||||
&Attribute{Table: "users", ID: id, AttName: "email", Value: aesEmail},
|
||||
); err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
@ -202,13 +355,13 @@ func (db *DB) UpdateOwnUserAttributes(id int64, user, first, last, oldPass, newP
|
||||
return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries)
|
||||
}
|
||||
|
||||
func (db *DB) AddFirstUser(u *User, pass string) (int64, error) {
|
||||
func (db *DB) AddFirstUser(c *Config, u *User, pass string) (int64, error) {
|
||||
var numUsers int64
|
||||
txOptions := &sql.TxOptions{Isolation: sql.LevelSerializable}
|
||||
selectQuery := "SELECT COUNT(*) FROM users"
|
||||
insertQuery := `
|
||||
INSERT INTO users (username, password, first_name, last_name, role)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
INSERT INTO users (username, password, first_name, last_name, email, role)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
`
|
||||
|
||||
for i := 0; i < TxMaxRetries; i++ {
|
||||
@ -239,7 +392,31 @@ func (db *DB) AddFirstUser(u *User, pass string) (int64, error) {
|
||||
return 0, fmt.Errorf("error creating password hash: %v", err)
|
||||
}
|
||||
|
||||
result, err := tx.Exec(insertQuery, u.UserName, string(hashedPass), u.FirstName, u.LastName, u.Role)
|
||||
aesFirstName, err := aesEncrypt(c, u.FirstName)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
}
|
||||
return 0, fmt.Errorf("error encrypting first name: %v", err)
|
||||
}
|
||||
|
||||
aesLastName, err := aesEncrypt(c, u.LastName)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
}
|
||||
return 0, fmt.Errorf("error encrypting last name: %v", err)
|
||||
}
|
||||
|
||||
aesEmail, err := aesEncrypt(c, u.Email)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
}
|
||||
return 0, fmt.Errorf("error encrypting email: %v", err)
|
||||
}
|
||||
|
||||
result, err := tx.Exec(insertQuery, u.UserName, string(hashedPass), aesFirstName, aesLastName, aesEmail, u.Role)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
@ -270,8 +447,11 @@ func (db *DB) AddFirstUser(u *User, pass string) (int64, error) {
|
||||
return 0, fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries)
|
||||
}
|
||||
|
||||
func (db *DB) GetAllUsers() (map[int64]*User, error) {
|
||||
query := "SELECT id, username, first_name, last_name, role FROM users"
|
||||
func (db *DB) GetAllUsers(c *Config) (map[int64]*User, error) {
|
||||
var aesFirstName, aesLastName, aesEmail string
|
||||
var err error
|
||||
|
||||
query := "SELECT id, username, first_name, last_name, email, role FROM users"
|
||||
|
||||
rows, err := db.Query(query)
|
||||
if err != nil {
|
||||
@ -281,10 +461,25 @@ func (db *DB) GetAllUsers() (map[int64]*User, error) {
|
||||
users := make(map[int64]*User, 0)
|
||||
for rows.Next() {
|
||||
user := new(User)
|
||||
if err = rows.Scan(&user.ID, &user.UserName, &user.FirstName,
|
||||
&user.LastName, &user.Role); err != nil {
|
||||
if err = rows.Scan(&user.ID, &user.UserName, &aesFirstName, &aesLastName, &aesEmail, &user.Role); err != nil {
|
||||
return nil, fmt.Errorf("error getting user info: %v", err)
|
||||
}
|
||||
|
||||
user.FirstName, err = aesDecrypt(c, aesFirstName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decrypting first name: %v", err)
|
||||
}
|
||||
|
||||
user.LastName, err = aesDecrypt(c, aesLastName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decrypting last name: %v", err)
|
||||
}
|
||||
|
||||
user.Email, err = aesDecrypt(c, aesEmail)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decrypting email: %v", err)
|
||||
}
|
||||
|
||||
users[user.ID] = user
|
||||
}
|
||||
|
||||
@ -311,17 +506,10 @@ func (tx *Tx) SetPassword(id int64, newPass string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) UpdateUserAttributes(id int64, user, first, last, newPass, newPass2 string, role int) error {
|
||||
passwordEmpty := true
|
||||
if len(newPass) > 0 || len(newPass2) > 0 {
|
||||
if newPass != newPass2 {
|
||||
return fmt.Errorf("error: passwords do not match")
|
||||
}
|
||||
passwordEmpty = false
|
||||
}
|
||||
|
||||
tx := new(Tx)
|
||||
func (db *DB) UpdateUserAttributes(c *Config, id int64, userName, firstName, lastName, email, newPass string, role int) error {
|
||||
var err error
|
||||
tx := new(Tx)
|
||||
passwordEmpty := len(newPass) > 0
|
||||
|
||||
for i := 0; i < TxMaxRetries; i++ {
|
||||
err := func() error {
|
||||
@ -339,10 +527,35 @@ func (db *DB) UpdateUserAttributes(id int64, user, first, last, newPass, newPass
|
||||
}
|
||||
}
|
||||
|
||||
aesFirstName, err := aesEncrypt(c, firstName)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
}
|
||||
return fmt.Errorf("error encrypting first name: %v", err)
|
||||
}
|
||||
|
||||
aesLastName, err := aesEncrypt(c, lastName)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
}
|
||||
return fmt.Errorf("error encrypting last name: %v", err)
|
||||
}
|
||||
|
||||
aesEmail, err := aesEncrypt(c, email)
|
||||
if err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||
}
|
||||
return fmt.Errorf("error encrypting email: %v", err)
|
||||
}
|
||||
|
||||
if err = tx.UpdateAttributes(
|
||||
&Attribute{Table: "users", ID: id, AttName: "username", Value: user},
|
||||
&Attribute{Table: "users", ID: id, AttName: "first_name", Value: first},
|
||||
&Attribute{Table: "users", ID: id, AttName: "last_name", Value: last},
|
||||
&Attribute{Table: "users", ID: id, AttName: "username", Value: userName},
|
||||
&Attribute{Table: "users", ID: id, AttName: "first_name", Value: aesFirstName},
|
||||
&Attribute{Table: "users", ID: id, AttName: "last_name", Value: aesLastName},
|
||||
&Attribute{Table: "users", ID: id, AttName: "email", Value: aesEmail},
|
||||
&Attribute{Table: "users", ID: id, AttName: "role", Value: role},
|
||||
); err != nil {
|
||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||
|
26
cmd/calls/atom.go
Normal file
26
cmd/calls/atom.go
Normal file
@ -0,0 +1,26 @@
|
||||
package calls
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
b "streifling.com/jason/cpolis/cmd/backend"
|
||||
)
|
||||
|
||||
func ServeAtomFeed(c *b.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !tokenIsVerified(w, r, c) {
|
||||
return
|
||||
}
|
||||
|
||||
absFilepath, err := filepath.Abs(c.AtomFile)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.ServeFile(w, r, absFilepath)
|
||||
}
|
||||
}
|
@ -6,12 +6,15 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
b "streifling.com/jason/cpolis/cmd/backend"
|
||||
f "streifling.com/jason/cpolis/cmd/frontend"
|
||||
)
|
||||
|
||||
func ServeImage(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !tokenIsVerified(w, r, c) {
|
||||
return
|
||||
if _, err := f.GetSession(w, r, c, s); err != nil {
|
||||
if !tokenIsVerified(w, r, c) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
absFilepath, err := filepath.Abs(c.PicsDir)
|
||||
|
@ -1,17 +0,0 @@
|
||||
package calls
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
b "streifling.com/jason/cpolis/cmd/backend"
|
||||
)
|
||||
|
||||
func ServeRSS(c *b.Config) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !tokenIsVerified(w, r, c) {
|
||||
return
|
||||
}
|
||||
|
||||
http.ServeFile(w, r, c.RSSFile)
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ type EditorHTMLData struct {
|
||||
|
||||
func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -64,7 +64,7 @@ func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -80,7 +80,7 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
article := &b.Article{
|
||||
Title: r.PostFormValue("article-title"),
|
||||
BannerLink: r.PostFormValue("article-banner-url"),
|
||||
BannerLink: c.Domain + "/image/serve/" + r.PostFormValue("article-banner-url"),
|
||||
Summary: r.PostFormValue("article-summary"),
|
||||
Published: false,
|
||||
Rejected: false,
|
||||
@ -93,10 +93,6 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if len(article.BannerLink) == 0 {
|
||||
http.Error(w, "Bitte ein Titelbild einfügen.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if len(article.Summary) == 0 {
|
||||
http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest)
|
||||
return
|
||||
@ -146,9 +142,12 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -158,7 +157,7 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -178,6 +177,11 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
bannerLink := r.PostFormValue("article-banner-url")
|
||||
if len(bannerLink) != 0 {
|
||||
bannerLink = c.Domain + "/image/serve/" + bannerLink
|
||||
}
|
||||
|
||||
summary := r.PostFormValue("article-summary")
|
||||
if len(summary) == 0 {
|
||||
http.Error(w, "Bitte die Beschreibung eingeben.", http.StatusBadRequest)
|
||||
@ -199,6 +203,7 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
if err = db.UpdateAttributes(
|
||||
&b.Attribute{Table: "articles", ID: id, AttName: "title", Value: title},
|
||||
&b.Attribute{Table: "articles", ID: id, AttName: "banner_link", Value: bannerLink},
|
||||
&b.Attribute{Table: "articles", ID: id, AttName: "summary", Value: summary},
|
||||
&b.Attribute{Table: "articles", ID: id, AttName: "rejected", Value: false},
|
||||
&b.Attribute{Table: "articles", ID: id, AttName: "is_in_issue", Value: r.PostFormValue("issue") == "on"},
|
||||
@ -225,9 +230,12 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -237,7 +245,7 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func ShowUnpublishedUnrejectedAndPublishedRejectedArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -281,7 +289,7 @@ func ShowUnpublishedUnrejectedAndPublishedRejectedArticles(c *b.Config, db *b.DB
|
||||
|
||||
func ShowRejectedArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -319,7 +327,7 @@ func ShowRejectedArticles(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerF
|
||||
|
||||
func ReviewRejectedArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -341,13 +349,7 @@ func ReviewRejectedArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.Handler
|
||||
}
|
||||
|
||||
imgURL := strings.Split(data.Article.BannerLink, "/")
|
||||
imgFileName := imgURL[len(imgURL)-1]
|
||||
data.BannerImage, err = serveBase64Image(c, imgFileName)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
data.BannerImage = imgURL[len(imgURL)-1]
|
||||
|
||||
articleAbsName := fmt.Sprint(c.ArticleDir, "/", data.Article.ID, ".md")
|
||||
content, err := os.ReadFile(articleAbsName)
|
||||
@ -390,7 +392,7 @@ func ReviewRejectedArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.Handler
|
||||
|
||||
func PublishArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -463,15 +465,18 @@ func PublishArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err = b.SaveAtomFeed(c.AtomFeed, feed); err != nil {
|
||||
if err = b.SaveAtomFeed(c.AtomFile, feed); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -481,7 +486,7 @@ func PublishArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func RejectArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -501,9 +506,12 @@ func RejectArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -513,7 +521,7 @@ func RejectArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func ShowCurrentIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -537,7 +545,7 @@ func ShowCurrentIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc
|
||||
|
||||
func ShowPublishedArticles(c *b.Config, db *b.DB, s *b.CookieStore, action string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -574,7 +582,7 @@ func ShowPublishedArticles(c *b.Config, db *b.DB, s *b.CookieStore, action strin
|
||||
|
||||
func ReviewArticle(c *b.Config, db *b.DB, s *b.CookieStore, action, title, button string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -612,13 +620,7 @@ func ReviewArticle(c *b.Config, db *b.DB, s *b.CookieStore, action, title, butto
|
||||
}
|
||||
|
||||
imgURL := strings.Split(article.BannerLink, "/")
|
||||
imgFileName := imgURL[len(imgURL)-1]
|
||||
data.BannerImage, err = serveBase64Image(c, imgFileName)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
data.BannerImage = imgURL[len(imgURL)-1]
|
||||
|
||||
data.Article.Summary, err = b.ConvertToPlain(article.Summary)
|
||||
if err != nil {
|
||||
@ -660,7 +662,7 @@ func ReviewArticle(c *b.Config, db *b.DB, s *b.CookieStore, action, title, butto
|
||||
|
||||
func DeleteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -692,15 +694,18 @@ func DeleteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err = b.SaveAtomFeed(c.AtomFeed, feed); err != nil {
|
||||
if err = b.SaveAtomFeed(c.AtomFile, feed); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -710,7 +715,7 @@ func DeleteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func AllowEditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -755,8 +760,11 @@ func AllowEditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html"))
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -766,7 +774,7 @@ func AllowEditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc
|
||||
|
||||
func EditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -789,13 +797,7 @@ func EditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
}
|
||||
|
||||
imgURL := strings.Split(data.Article.BannerLink, "/")
|
||||
imgFileName := imgURL[len(imgURL)-1]
|
||||
data.BannerImage, err = serveBase64Image(c, imgFileName)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
data.BannerImage = imgURL[len(imgURL)-1]
|
||||
|
||||
content, err := os.ReadFile(fmt.Sprint(c.ArticleDir, "/", data.Article.ID, ".md"))
|
||||
if err != nil {
|
||||
|
@ -1,49 +1,22 @@
|
||||
package frontend
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
b "streifling.com/jason/cpolis/cmd/backend"
|
||||
)
|
||||
|
||||
func serveBase64Image(c *b.Config, filename string) (string, error) {
|
||||
file := c.PicsDir + "/" + filename
|
||||
|
||||
img, err := os.Open(file)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error opening file %v: %v", file, err)
|
||||
}
|
||||
defer img.Close()
|
||||
|
||||
imgBytes, err := io.ReadAll(img)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error turning %v into bytes: %v", file, err)
|
||||
}
|
||||
|
||||
return base64.StdEncoding.EncodeToString(imgBytes), nil
|
||||
}
|
||||
|
||||
func UploadImage(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := r.ParseMultipartForm(10 << 20); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
file, _, err := r.FormFile("article-image")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@ -52,7 +25,7 @@ func UploadImage(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
filename, err := b.SaveImage(c, file)
|
||||
filename, err := b.SaveImage(file, c.MaxImgHeight, c.MaxImgWidth, c.PicsDir+"/")
|
||||
if err != nil {
|
||||
if err == b.ErrUnsupportedFormat {
|
||||
http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest)
|
||||
@ -69,54 +42,9 @@ func UploadImage(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func UploadIssueImage(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := r.ParseMultipartForm(10 << 20); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
file, _, err := r.FormFile("issue-image")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
filename, err := b.SaveImage(c, file)
|
||||
if err != nil {
|
||||
if err == b.ErrUnsupportedFormat {
|
||||
http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
session.Values["issue-image"] = filename
|
||||
if err = session.Save(r, w); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func UploadBanner(c *b.Config, s *b.CookieStore, fileKey, htmlFile, htmlTemplate string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -130,7 +58,7 @@ func UploadBanner(c *b.Config, s *b.CookieStore, fileKey, htmlFile, htmlTemplate
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
filename, err := b.SaveImage(c, file)
|
||||
filename, err := b.SaveImage(file, c.MaxBannerHeight, c.MaxBannerWidth, c.PicsDir+"/")
|
||||
if err != nil {
|
||||
if err == b.ErrUnsupportedFormat {
|
||||
http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest)
|
||||
@ -141,20 +69,8 @@ func UploadBanner(c *b.Config, s *b.CookieStore, fileKey, htmlFile, htmlTemplate
|
||||
return
|
||||
}
|
||||
|
||||
base64Img, err := serveBase64Image(c, filename)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct {
|
||||
BannerImage string
|
||||
URL string
|
||||
})
|
||||
|
||||
data.BannerImage = base64Img
|
||||
data.URL = c.Domain + "/image/serve/" + filename
|
||||
data := new(struct{ BannerImage string })
|
||||
data.BannerImage = filename
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/" + htmlFile)
|
||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, htmlTemplate, data); err != nil {
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
|
||||
func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -41,10 +41,6 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun
|
||||
http.Error(w, "Bitte den Titel eingeben.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if len(article.BannerLink) == 0 {
|
||||
http.Error(w, "Bitte ein Titelbild einfügen.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
article.ID, err = db.AddArticle(article)
|
||||
if err != nil {
|
||||
@ -97,7 +93,7 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err = b.SaveAtomFeed(c.AtomFeed, feed); err != nil {
|
||||
if err = b.SaveAtomFeed(c.AtomFile, feed); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -110,9 +106,12 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
@ -12,18 +12,12 @@ import (
|
||||
|
||||
func UploadPDF(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := r.ParseMultipartForm(10 << 20); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
file, _, err := r.FormFile("pdf-upload")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
@ -26,8 +26,8 @@ func saveSession(w http.ResponseWriter, r *http.Request, s *b.CookieStore, u *b.
|
||||
return nil
|
||||
}
|
||||
|
||||
// getSession is used for verifying that the user is logged in and returns their session and an error.
|
||||
func getSession(w http.ResponseWriter, r *http.Request, c *b.Config, s *b.CookieStore) (*b.Session, error) {
|
||||
// GetSession is used for verifying that the user is logged in and returns their session and an error.
|
||||
func GetSession(w http.ResponseWriter, r *http.Request, c *b.Config, s *b.CookieStore) (*b.Session, error) {
|
||||
msg := "Keine gültige Session. Bitte erneut anmelden."
|
||||
tmpl, tmplErr := template.ParseFiles(c.WebDir+"/templates/index.html", c.WebDir+"/templates/login.html")
|
||||
|
||||
@ -56,12 +56,18 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
data := new(struct {
|
||||
Version string
|
||||
Role int
|
||||
})
|
||||
data.Version = c.Version
|
||||
|
||||
files := make([]string, 2)
|
||||
files[0] = c.WebDir + "/templates/index.html"
|
||||
if numRows == 0 {
|
||||
files[1] = c.WebDir + "/templates/first-user.html"
|
||||
tmpl, err := template.ParseFiles(files...)
|
||||
if err = template.Must(tmpl, err).Execute(w, nil); err != nil {
|
||||
if err = template.Must(tmpl, err).Execute(w, data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -74,9 +80,10 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
if auth, ok := session.Values["authenticated"].(bool); auth && ok {
|
||||
data.Role = session.Values["role"].(int)
|
||||
files[1] = c.WebDir + "/templates/hub.html"
|
||||
tmpl, err := template.ParseFiles(files...)
|
||||
if err = template.Must(tmpl, err).Execute(w, session.Values["role"]); err != nil {
|
||||
if err = template.Must(tmpl, err).Execute(w, data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -84,7 +91,7 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
} else {
|
||||
files[1] = c.WebDir + "/templates/login.html"
|
||||
tmpl, err := template.ParseFiles(files...)
|
||||
if err = template.Must(tmpl, err).Execute(w, nil); err != nil {
|
||||
if err = template.Must(tmpl, err).Execute(w, data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -111,7 +118,7 @@ func Login(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
user, err := db.GetUser(id)
|
||||
user, err := db.GetUser(c, id)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -125,7 +132,7 @@ func Login(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
}
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user.Role); err != nil {
|
||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -135,7 +142,7 @@ func Login(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func Logout(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -160,7 +167,7 @@ func Logout(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func ShowHub(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -174,8 +181,11 @@ func ShowHub(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
func CreateTag(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -27,7 +27,7 @@ func CreateTag(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func AddTag(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -41,9 +41,12 @@ func AddTag(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
}
|
||||
db.AddTag(tag)
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
@ -11,8 +11,8 @@ import (
|
||||
)
|
||||
|
||||
func checkUserStrings(user *b.User) (string, int, bool) {
|
||||
userLen := 15
|
||||
nameLen := 50
|
||||
userLen := 63 // max value for utf-8 at 255 bytes
|
||||
nameLen := 56 // max value when aes encrypting utf-8 at up to 255 bytes
|
||||
|
||||
if len(user.UserName) > userLen {
|
||||
return "Benutzername", userLen, false
|
||||
@ -27,7 +27,7 @@ func checkUserStrings(user *b.User) (string, int, bool) {
|
||||
|
||||
func CreateUser(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -44,7 +44,7 @@ func CreateUser(c *b.Config, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -55,12 +55,13 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
UserName: r.PostFormValue("username"),
|
||||
FirstName: r.PostFormValue("first-name"),
|
||||
LastName: r.PostFormValue("last-name"),
|
||||
Email: r.PostFormValue("email"),
|
||||
}
|
||||
pass := r.PostFormValue("password")
|
||||
pass2 := r.PostFormValue("password2")
|
||||
email2 := r.PostFormValue("email2")
|
||||
|
||||
if len(user.UserName) == 0 || len(user.FirstName) == 0 ||
|
||||
len(user.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 {
|
||||
if len(user.UserName) == 0 || len(user.FirstName) == 0 || len(user.LastName) == 0 || len(user.Email) == 0 || len(email2) == 0 || len(pass) == 0 || len(pass2) == 0 {
|
||||
http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
@ -76,6 +77,11 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if user.Email != email2 {
|
||||
http.Error(w, "Die Emailadressen stimmen nicht überein.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if pass != pass2 {
|
||||
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
|
||||
return
|
||||
@ -94,16 +100,19 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = db.AddUser(user, pass)
|
||||
_, err = db.AddUser(c, user, pass)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -113,14 +122,14 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func EditSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := db.GetUser(session.Values["id"].(int64))
|
||||
user, err := db.GetUser(c, session.Values["id"].(int64))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -138,7 +147,7 @@ func EditSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -150,11 +159,13 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
UserName: r.PostFormValue("username"),
|
||||
FirstName: r.PostFormValue("first-name"),
|
||||
LastName: r.PostFormValue("last-name"),
|
||||
Email: r.PostFormValue("email"),
|
||||
}
|
||||
|
||||
oldPass := r.PostFormValue("old-password")
|
||||
newPass := r.PostFormValue("password")
|
||||
newPass2 := r.PostFormValue("password2")
|
||||
email2 := r.PostFormValue("email2")
|
||||
|
||||
if len(user.UserName) == 0 {
|
||||
http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest)
|
||||
@ -166,6 +177,20 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if len(user.Email) == 0 || len(email2) == 0 {
|
||||
http.Error(w, "Bitte die Emailadresse ausfüllen.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if user.Email != email2 {
|
||||
http.Error(w, "Die Emailadressen stimmen nicht überein", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if newPass != newPass2 {
|
||||
http.Error(w, "Die Passwörter stimmen nicht überein", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
userString, stringLen, ok := checkUserStrings(user)
|
||||
if !ok {
|
||||
http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest)
|
||||
@ -177,15 +202,18 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if err = db.UpdateOwnUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, oldPass, newPass, newPass2); err != nil {
|
||||
if err = db.UpdateOwnUserAttributes(c, user.ID, user.UserName, user.FirstName, user.LastName, user.Email, oldPass, newPass); err != nil {
|
||||
log.Println("error: user:", user.ID, err)
|
||||
http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -200,13 +228,14 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
UserName: r.PostFormValue("username"),
|
||||
FirstName: r.PostFormValue("first-name"),
|
||||
LastName: r.PostFormValue("last-name"),
|
||||
Email: r.PostFormValue("email"),
|
||||
Role: b.Admin,
|
||||
}
|
||||
pass := r.PostFormValue("password")
|
||||
pass2 := r.PostFormValue("password2")
|
||||
email2 := r.PostFormValue("email2")
|
||||
|
||||
if len(user.UserName) == 0 || len(user.FirstName) == 0 ||
|
||||
len(user.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 {
|
||||
if len(user.UserName) == 0 || len(user.FirstName) == 0 || len(user.LastName) == 0 || len(user.Email) == 0 || len(email2) == 0 || len(pass) == 0 || len(pass2) == 0 {
|
||||
http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
@ -217,12 +246,17 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if user.Email != email2 {
|
||||
http.Error(w, "Die Emailadressen stimmen nicht überein.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if pass != pass2 {
|
||||
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user.ID, err = db.AddFirstUser(user, pass)
|
||||
user.ID, err = db.AddFirstUser(c, user, pass)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -245,8 +279,11 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = 0
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", 0); err != nil {
|
||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -256,7 +293,7 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func ShowAllUsers(c *b.Config, db *b.DB, s *b.CookieStore, action string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -269,7 +306,7 @@ func ShowAllUsers(c *b.Config, db *b.DB, s *b.CookieStore, action string) http.H
|
||||
})
|
||||
|
||||
data.Action = action
|
||||
data.Users, err = db.GetAllUsers()
|
||||
data.Users, err = db.GetAllUsers(c)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -288,7 +325,7 @@ func ShowAllUsers(c *b.Config, db *b.DB, s *b.CookieStore, action string) http.H
|
||||
|
||||
func EditUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, err := getSession(w, r, c, s); err != nil {
|
||||
if _, err := GetSession(w, r, c, s); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -301,7 +338,7 @@ func EditUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
user, err := db.GetUser(id)
|
||||
user, err := db.GetUser(c, id)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -319,7 +356,7 @@ func EditUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -343,19 +380,34 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
user.UserName = r.PostFormValue("username")
|
||||
if len(user.UserName) == 0 {
|
||||
http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusInternalServerError)
|
||||
http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user.FirstName = r.PostFormValue("first-name")
|
||||
user.LastName = r.PostFormValue("last-name")
|
||||
if len(user.FirstName) == 0 || len(user.LastName) == 0 {
|
||||
http.Error(w, "Bitte den vollständigen Namen ausfüllen.", http.StatusInternalServerError)
|
||||
http.Error(w, "Bitte den vollständigen Namen ausfüllen.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
user.Email = r.PostFormValue("email")
|
||||
email2 := r.PostFormValue("email2")
|
||||
if len(user.Email) == 0 || len(email2) == 0 {
|
||||
http.Error(w, "Bitte die Emailadresse ausfüllen.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if user.Email != email2 {
|
||||
http.Error(w, "Die Emailadressen stimmen nicht überein.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
newPass := r.PostFormValue("password")
|
||||
newPass2 := r.PostFormValue("password2")
|
||||
if newPass != newPass2 {
|
||||
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
userString, stringLen, ok := checkUserStrings(user)
|
||||
if !ok {
|
||||
@ -368,14 +420,17 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if err = db.UpdateUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, newPass, newPass2, user.Role); err != nil {
|
||||
if err = db.UpdateUserAttributes(c, user.ID, user.UserName, user.FirstName, user.LastName, user.Email, newPass, user.Role); err != nil {
|
||||
log.Println("error: user:", user.ID, err)
|
||||
http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html"))
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@ -385,7 +440,7 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
|
||||
func DeleteUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := getSession(w, r, c, s)
|
||||
session, err := GetSession(w, r, c, s)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@ -405,9 +460,12 @@ func DeleteUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
data := new(struct{ Role int })
|
||||
data.Role = session.Values["role"].(int)
|
||||
|
||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||
tmpl = template.Must(tmpl, err)
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
||||
log.Println(err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
@ -34,13 +34,13 @@ func main() {
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
key, err := b.LoadKey(config.KeyFile)
|
||||
key, err := b.LoadKey(config.GOBKeyFile)
|
||||
if err != nil {
|
||||
key, err = b.NewKey()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if err = b.SaveKey(key, config.KeyFile); err != nil {
|
||||
if err = b.SaveKey(key, config.GOBKeyFile); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
@ -66,13 +66,13 @@ func main() {
|
||||
mux.HandleFunc("GET /article/review-unpublished/{id}", f.ReviewArticle(config, db, store, "publish", "Artikel veröffentlichen", "Veröffentlichen"))
|
||||
mux.HandleFunc("GET /article/serve/{id}", c.ServeArticle(config, db))
|
||||
mux.HandleFunc("GET /article/write", f.WriteArticle(config, db, store))
|
||||
mux.HandleFunc("GET /atom/serve", c.ServeAtomFeed(config))
|
||||
mux.HandleFunc("GET /hub", f.ShowHub(config, db, store))
|
||||
mux.HandleFunc("GET /image/serve/{pic}", c.ServeImage(config, store))
|
||||
mux.HandleFunc("GET /issue/this", f.ShowCurrentIssue(config, db, store))
|
||||
mux.HandleFunc("GET /logout", f.Logout(config, store))
|
||||
mux.HandleFunc("GET /pdf/get-list", c.ServePDFList(config))
|
||||
mux.HandleFunc("GET /pdf/serve/{id}", c.ServePDF(config))
|
||||
mux.HandleFunc("GET /rss/serve", c.ServeRSS(config))
|
||||
mux.HandleFunc("GET /tag/create", f.CreateTag(config, store))
|
||||
mux.HandleFunc("GET /user/create", f.CreateUser(config, store))
|
||||
mux.HandleFunc("GET /user/delete/{id}", f.DeleteUser(config, db, store))
|
||||
|
@ -5,12 +5,14 @@ DROP TABLE IF EXISTS issues;
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
CREATE TABLE users (
|
||||
id INT AUTO_INCREMENT,
|
||||
username VARCHAR(15) NOT NULL UNIQUE,
|
||||
password VARCHAR(60) NOT NULL,
|
||||
first_name VARCHAR(50) NOT NULL,
|
||||
last_name VARCHAR(50) NOT NULL,
|
||||
role INT NOT NULL,
|
||||
id INT AUTO_INCREMENT,
|
||||
username VARCHAR(255) NOT NULL UNIQUE,
|
||||
password VARCHAR(60) NOT NULL,
|
||||
first_name VARCHAR(255) NOT NULL,
|
||||
last_name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
-- profile_pic_link VARCHAR(255) NOT NULL,
|
||||
role INT NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
@ -24,12 +26,9 @@ CREATE TABLE articles (
|
||||
id INT AUTO_INCREMENT,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
banner_link VARCHAR(255),
|
||||
banner_link VARCHAR(255) NOT NULL,
|
||||
summary TEXT NOT NULL,
|
||||
content_link VARCHAR(255),
|
||||
enc_url VARCHAR(255),
|
||||
enc_length INT,
|
||||
enc_type VARCHAR(255),
|
||||
content_link VARCHAR(255) NOT NULL,
|
||||
published BOOL NOT NULL,
|
||||
rejected BOOL NOT NULL,
|
||||
author_id INT NOT NULL,
|
||||
|
23
go.mod
23
go.mod
@ -3,9 +3,8 @@ module streifling.com/jason/cpolis
|
||||
go 1.23.2
|
||||
|
||||
require (
|
||||
firebase.google.com/go/v4 v4.14.1
|
||||
firebase.google.com/go/v4 v4.15.0
|
||||
git.streifling.com/jason/atom v1.0.0
|
||||
git.streifling.com/jason/rss v0.1.3
|
||||
github.com/BurntSushi/toml v1.4.0
|
||||
github.com/chai2010/webp v1.1.1
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
@ -16,19 +15,19 @@ require (
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
golang.org/x/crypto v0.28.0
|
||||
golang.org/x/term v0.25.0
|
||||
google.golang.org/api v0.201.0
|
||||
google.golang.org/api v0.203.0
|
||||
)
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.16.2 // indirect
|
||||
cel.dev/expr v0.18.0 // indirect
|
||||
cloud.google.com/go v0.116.0 // indirect
|
||||
cloud.google.com/go/auth v0.9.8 // indirect
|
||||
cloud.google.com/go/auth v0.9.9 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.5.2 // indirect
|
||||
cloud.google.com/go/firestore v1.17.0 // indirect
|
||||
cloud.google.com/go/iam v1.2.1 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.1 // indirect
|
||||
cloud.google.com/go/monitoring v1.21.1 // indirect
|
||||
cloud.google.com/go/iam v1.2.2 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.2 // indirect
|
||||
cloud.google.com/go/monitoring v1.21.2 // indirect
|
||||
cloud.google.com/go/storage v1.45.0 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.3 // indirect
|
||||
@ -70,10 +69,10 @@ require (
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
google.golang.org/appengine/v2 v2.0.6 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
google.golang.org/grpc v1.67.1 // indirect
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241018153737-98959d9a4904 // indirect
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241025232817-cb329375b14e // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
)
|
||||
|
50
go.sum
50
go.sum
@ -1,36 +1,34 @@
|
||||
cel.dev/expr v0.16.2 h1:RwRhoH17VhAu9U5CMvMhH1PDVgf0tuz9FT+24AfMLfU=
|
||||
cel.dev/expr v0.16.2/go.mod h1:gXngZQMkWJoSbE8mOzehJlXQyubn/Vg0vR9/F3W7iw8=
|
||||
cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo=
|
||||
cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
|
||||
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
|
||||
cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8=
|
||||
cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
|
||||
cloud.google.com/go/auth v0.9.9 h1:BmtbpNQozo8ZwW2t7QJjnrQtdganSdmqeIBxHxNkEZQ=
|
||||
cloud.google.com/go/auth v0.9.9/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
|
||||
cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
|
||||
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
|
||||
cloud.google.com/go/firestore v1.17.0 h1:iEd1LBbkDZTFsLw3sTH50eyg4qe8eoG6CjocmEXO9aQ=
|
||||
cloud.google.com/go/firestore v1.17.0/go.mod h1:69uPx1papBsY8ZETooc71fOhoKkD70Q1DwMrtKuOT/Y=
|
||||
cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU=
|
||||
cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g=
|
||||
cloud.google.com/go/logging v1.11.0 h1:v3ktVzXMV7CwHq1MBF65wcqLMA7i+z3YxbUsoK7mOKs=
|
||||
cloud.google.com/go/logging v1.11.0/go.mod h1:5LDiJC/RxTt+fHc1LAt20R9TKiUTReDg6RuuFOZ67+A=
|
||||
cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc=
|
||||
cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0=
|
||||
cloud.google.com/go/monitoring v1.21.1 h1:zWtbIoBMnU5LP9A/fz8LmWMGHpk4skdfeiaa66QdFGc=
|
||||
cloud.google.com/go/monitoring v1.21.1/go.mod h1:Rj++LKrlht9uBi8+Eb530dIrzG/cU/lB8mt+lbeFK1c=
|
||||
cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA=
|
||||
cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY=
|
||||
cloud.google.com/go/logging v1.12.0 h1:ex1igYcGFd4S/RZWOCU51StlIEuey5bjqwH9ZYjHibk=
|
||||
cloud.google.com/go/logging v1.12.0/go.mod h1:wwYBt5HlYP1InnrtYI0wtwttpVU1rifnMT7RejksUAM=
|
||||
cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc=
|
||||
cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI=
|
||||
cloud.google.com/go/monitoring v1.21.2 h1:FChwVtClH19E7pJ+e0xUhJPGksctZNVOk2UhMmblmdU=
|
||||
cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU=
|
||||
cloud.google.com/go/storage v1.45.0 h1:5av0QcIVj77t+44mV4gffFC/LscFRUhto6UBMB5SimM=
|
||||
cloud.google.com/go/storage v1.45.0/go.mod h1:wpPblkIuMP5jCB/E48Pz9zIo2S/zD8g+ITmxKkPCITE=
|
||||
cloud.google.com/go/trace v1.11.1 h1:UNqdP+HYYtnm6lb91aNA5JQ0X14GnxkABGlfz2PzPew=
|
||||
cloud.google.com/go/trace v1.11.1/go.mod h1:IQKNQuBzH72EGaXEodKlNJrWykGZxet2zgjtS60OtjA=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
firebase.google.com/go/v4 v4.14.1 h1:4qiUETaFRWoFGE1XP5VbcEdtPX93Qs+8B/7KvP2825g=
|
||||
firebase.google.com/go/v4 v4.14.1/go.mod h1:fgk2XshgNDEKaioKco+AouiegSI9oTWVqRaBdTTGBoM=
|
||||
firebase.google.com/go/v4 v4.15.0 h1:k27M+cHbyN1YpBI2Cf4NSjeHnnYRB9ldXwpqA5KikN0=
|
||||
firebase.google.com/go/v4 v4.15.0/go.mod h1:S/4MJqVZn1robtXkHhpRUbwOC4gdYtgsiMMJQ4x+xmQ=
|
||||
git.streifling.com/jason/atom v1.0.0 h1:E88z4S7JeT6T+WuAaJWnGwCWTx+vzSJ6giUL51MdptI=
|
||||
git.streifling.com/jason/atom v1.0.0/go.mod h1:FNTYJfatYaIOQn4OKy8y+Mtohqm3MeyEGZUu4bMtZ9E=
|
||||
git.streifling.com/jason/rss v0.1.3 h1:fd3j4ZtcLehapcmmroo3AP3X34gRHC4xzpfV6bDV1ZU=
|
||||
git.streifling.com/jason/rss v0.1.3/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
@ -227,8 +225,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0=
|
||||
google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4=
|
||||
google.golang.org/api v0.203.0 h1:SrEeuwU3S11Wlscsn+LA1kb/Y5xT8uggJSkIhD08NAU=
|
||||
google.golang.org/api v0.203.0/go.mod h1:BuOVyCSYEPwJb3npWvDnNmFI92f3GeRnHNkETneT3SI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine/v2 v2.0.6 h1:LvPZLGuchSBslPBp+LAhihBeGSiRh1myRoYK4NtuBIw=
|
||||
@ -236,12 +234,12 @@ google.golang.org/appengine/v2 v2.0.6/go.mod h1:WoEXGoXNfa0mLvaH5sV3ZSGXwVmy8yf7
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE=
|
||||
google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
|
||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
@ -249,8 +247,8 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
|
||||
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241018153737-98959d9a4904 h1:Lplo3VKrYtWeryBkDI4SZ4kJTFaWO4qUGs+xX7N2bFc=
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241018153737-98959d9a4904/go.mod h1:jzYlkSMbKypzuu6xoAEijsNVo9ZeDF1u/zCfFgsx7jg=
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241025232817-cb329375b14e h1:SoMI+r+Qsp379U9BlVzrHtqAqYP3NEv9vNhYqUaAWOg=
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20241025232817-cb329375b14e/go.mod h1:jzYlkSMbKypzuu6xoAEijsNVo9ZeDF1u/zCfFgsx7jg=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -32,11 +32,11 @@ textarea {
|
||||
}
|
||||
|
||||
.btn {
|
||||
@apply bg-slate-200 dark:bg-slate-800 hover:bg-slate-100 dark:hover:bg-slate-900 border border-slate-200 dark:border-slate-800 my-2 px-3 py-2 rounded-md w-full;
|
||||
@apply bg-slate-200 dark:bg-slate-800 hover:bg-slate-100 dark:hover:bg-slate-900 border border-slate-200 dark:border-slate-800 cursor-pointer my-2 px-3 py-2 rounded-md w-full;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
@apply bg-slate-800 dark:bg-slate-200 hover:bg-slate-700 dark:hover:bg-slate-300 my-2 px-3 py-2 rounded-md text-slate-50 dark:text-slate-950 w-full;
|
||||
@apply bg-slate-800 dark:bg-slate-200 hover:bg-slate-700 dark:hover:bg-slate-300 cursor-pointer my-2 px-3 py-2 rounded-md text-slate-50 dark:text-slate-950 w-full;
|
||||
}
|
||||
|
||||
.EasyMDEContainer .CodeMirror {
|
||||
|
@ -7,22 +7,36 @@
|
||||
<label for="username">Benutzername</label>
|
||||
<input class="w-full" required name="username" type="text" value="{{.UserName}}" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password">Passwort</label>
|
||||
<input class="w-full" required name="password" placeholder="***" type="password" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password2">Passwort wiederholen</label>
|
||||
<input class="w-full" required name="password2" placeholder="***" type="password" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="first-name">Vorname</label>
|
||||
<input class="w-full" required name="first-name" type="text" value="{{.FirstName}}" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="last-name">Nachname</label>
|
||||
<input class="w-full" required name="last-name" type="text" value="{{.LastName}}" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email">Emailadresse</label>
|
||||
<input class="w-full" required name="email" type="text" value="{{.Email}}" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email2">Emailadresse wiederholen</label>
|
||||
<input class="w-full" required name="email2" type="text" value="{{.Email}}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-4">
|
||||
|
@ -13,7 +13,7 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 items-center">
|
||||
<label class="btn cursor-pointer text-center" for="issue-banner-upload">Titelbild</label>
|
||||
<label class="btn text-center" for="issue-banner-upload">Titelbild</label>
|
||||
<input class="hidden" id="issue-banner-upload" name="issue-banner" type="file" required
|
||||
hx-post="/issue/upload-banner" hx-target="#issue-banner-container" />
|
||||
</div>
|
||||
|
@ -32,6 +32,16 @@
|
||||
<label for="password2">Passwort wiederholen</label>
|
||||
<input class="w-full" name="password2" placeholder="***" type="password" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email">Emailadresse</label>
|
||||
<input class="w-full" required name="email" type="text" value="{{.Email}}" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email2">Emailadresse wiederholen</label>
|
||||
<input class="w-full" required name="email2" type="text" value="{{.Email}}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-area">
|
||||
|
@ -27,6 +27,16 @@
|
||||
<label for="password2">Passwort wiederholen</label>
|
||||
<input class="w-full" name="password2" placeholder="***" type="password" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email">Emailadresse</label>
|
||||
<input class="w-full" required name="email" type="text" value="{{.Email}}" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email2">Emailadresse wiederholen</label>
|
||||
<input class="w-full" required name="email2" type="text" value="{{.Email}}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-4">
|
||||
|
@ -3,10 +3,7 @@
|
||||
|
||||
<form id="edit-area" hx-encoding="multipart/form-data">
|
||||
<div class="flex flex-col gap-y-1">
|
||||
<div class="w-full" id="article-banner-container">
|
||||
<img src="data:image/webp;base64,{{.BannerImage}}" alt="Banner Image">
|
||||
<input id="article-banner-url" name="article-banner-url" type="hidden" value="{{.Article.BannerLink}}" />
|
||||
</div>
|
||||
{{template "article-banner-template" .}}
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 items-center">
|
||||
<div class="flex flex-col">
|
||||
@ -15,9 +12,9 @@
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 items-center">
|
||||
<label class="btn cursor-pointer text-center" for="article-banner">Titelbild</label>
|
||||
<label class="btn text-center" for="article-banner">Titelbild</label>
|
||||
<input class="hidden" id="article-banner" name="article-banner" type="file" required
|
||||
hx-post="/article/upload-banner" hx-target="#article-banner-container" />
|
||||
hx-post="/article/upload-banner" hx-swap="outerHTML" hx-target="#article-banner-container" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -92,8 +89,8 @@
|
||||
{{end}}
|
||||
|
||||
{{define "article-banner-template"}}
|
||||
<div class="w-full" id="article-banner-container">
|
||||
<img src="data:image/webp;base64,{{.BannerImage}}" alt="Banner Image">
|
||||
<input id="article-banner-url" name="article-banner-url" type="hidden" value="{{.URL}}" />
|
||||
<div id="article-banner-container">
|
||||
<img src="/image/serve/{{.BannerImage}}" alt="">
|
||||
<input id="article-banner-url" name="article-banner-url" type="hidden" value="{{.BannerImage}}" />
|
||||
</div>
|
||||
{{end}}
|
||||
|
@ -5,23 +5,37 @@
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label for="username">Benutzername</label>
|
||||
<input class="w-full" required name="username" type="text" value="{{.UserName}}" />
|
||||
<input class="w-full" required name="username" type="text" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password">Passwort</label>
|
||||
<input class="w-full" required name="password" placeholder="***" type="password" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password2">Passwort wiederholen</label>
|
||||
<input class="w-full" required name="password2" placeholder="***" type="password" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="first-name">Vorname</label>
|
||||
<input class="w-full" required name="first-name" type="text" value="{{.FirstName}}" />
|
||||
<input class="w-full" required name="first-name" type="text" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="last-name">Nachname</label>
|
||||
<input class="w-full" required name="last-name" type="text" value="{{.LastName}}" />
|
||||
<input class="w-full" required name="last-name" type="text" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email">Emailadresse</label>
|
||||
<input class="w-full" required name="email" type="text" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email2">Emailadresse wiederholen</label>
|
||||
<input class="w-full" required name="email2" type="text" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -2,30 +2,31 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
<button class="btn" hx-get="/logout" hx-target="#page-content">Abmelden</button>
|
||||
|
||||
{{if lt . 4}}
|
||||
{{if lt .Role 4}}
|
||||
<div class="mb-3">
|
||||
<h2>Artikel</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2">
|
||||
<button class="btn" hx-get="/article/write" hx-target="#page-content">Artikel schreiben</button>
|
||||
<button class="btn" hx-get="/article/all-rejected" hx-target="#page-content">Artikel bearbeiten</button>
|
||||
{{if lt . 3}}<button class="btn" hx-get="/article/all-unpublished-unrejected-and-published-rejected"
|
||||
{{if lt .Role 3}}<button class="btn" hx-get="/article/all-unpublished-unrejected-and-published-rejected"
|
||||
hx-target="#page-content">Artikel veröffentlichen</button>{{end}}
|
||||
{{if lt . 2}}<button class="btn" hx-get="/article/all-published/delete" hx-target="#page-content">Artikel
|
||||
löschen</button>{{end}}
|
||||
{{if lt . 2}}<button class="btn" hx-get="/article/all-published/review-edit"
|
||||
{{if lt .Role 2}}<button class="btn" hx-get="/article/all-published/delete"
|
||||
hx-target="#page-content">Artikel löschen</button>{{end}}
|
||||
{{if lt .Role 2}}<button class="btn" hx-get="/article/all-published/review-edit"
|
||||
hx-target="#page-content">Artikel bearbeiten lassen</button>{{end}}
|
||||
{{if lt . 3}}<button class="btn" hx-get="/tag/create" hx-target="#page-content">Neuer Tag</button>{{end}}
|
||||
{{if lt .Role 3}}<button class="btn" hx-get="/tag/create" hx-target="#page-content">Neuer
|
||||
Tag</button>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if lt . 2}}
|
||||
{{if lt .Role 2}}
|
||||
<div class="mb-3">
|
||||
<h2>Ausgabe</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2">
|
||||
<button class="btn" hx-get="/issue/this" hx-target="#page-content">Diese Ausgabe</button>
|
||||
<form class="flex" hx-encoding="multipart/form-data">
|
||||
<label class="btn cursor-pointer text-center" for="pdf-upload">PDF hochladen</label>
|
||||
<label class="btn text-center" for="pdf-upload">PDF hochladen</label>
|
||||
<input accept=".pdf" class="hidden" id="pdf-upload" name="pdf-upload" type="file"
|
||||
hx-post="/pdf/upload" />
|
||||
</form>
|
||||
@ -33,16 +34,16 @@
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{if lt . 4}}
|
||||
{{if lt .Role 4}}
|
||||
<div class="mb-3">
|
||||
<h2>Benutzer</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2">
|
||||
<button class="btn" hx-get="/user/edit/self" hx-target="#page-content">Mein Profil bearbeiten</button>
|
||||
{{if eq . 0}}<button class="btn" hx-get="/user/create" hx-target="#page-content">Benutzer
|
||||
{{if eq .Role 0}}<button class="btn" hx-get="/user/create" hx-target="#page-content">Benutzer
|
||||
hinzufügen</button>{{end}}
|
||||
{{if eq . 0}}<button class="btn" hx-get="/user/show-all/edit" hx-target="#page-content">Benutzer
|
||||
{{if eq .Role 0}}<button class="btn" hx-get="/user/show-all/edit" hx-target="#page-content">Benutzer
|
||||
bearbeiten</button>{{end}}
|
||||
{{if eq . 0}}<button class="btn" hx-get="/user/show-all/delete" hx-target="#page-content">Benutzer
|
||||
{{if eq .Role 0}}<button class="btn" hx-get="/user/show-all/delete" hx-target="#page-content">Benutzer
|
||||
löschen</button>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -39,10 +39,10 @@
|
||||
|
||||
<footer class="text-center text-gray-500 my-8">
|
||||
<p>© 2024 Jason Streifling. Alle Rechte vorbehalten.</p>
|
||||
<p>v0.13.0 - <strong>Alpha: Drastische Änderungen und Fehler vorbehalten.</strong></p>
|
||||
<p>{{.Version}} - <strong>Alpha: Drastische Änderungen und Fehler vorbehalten.</strong></p>
|
||||
</footer>
|
||||
|
||||
<script src="https://unpkg.com/htmx.org@2.0.2"></script>
|
||||
<script src="https://unpkg.com/htmx.org@2.0.3"></script>
|
||||
<script src="https://unpkg.com/easymde/dist/easymde.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<div>
|
||||
<div class="w-full" id="article-banner-container">
|
||||
<img src="data:image/webp;base64,{{.BannerImage}}" alt="Banner Image">
|
||||
<img src="/image/serve/{{.BannerImage}}" alt="Banner Image">
|
||||
</div>
|
||||
|
||||
<span>Titel</span>
|
||||
|
Reference in New Issue
Block a user