Compare commits
No commits in common. "31484dd44a473a3ed66626405d85fa1b679d0570" and "123071ab1bb8561523c6a6f227e816a073bb394b" have entirely different histories.
31484dd44a
...
123071ab1b
@ -4,19 +4,19 @@ tmp_dir = "tmp"
|
|||||||
|
|
||||||
[build]
|
[build]
|
||||||
args_bin = [
|
args_bin = [
|
||||||
"-aes tmp/cpolis.aes",
|
|
||||||
"-articles tmp/articles",
|
"-articles tmp/articles",
|
||||||
"-config tmp/config.toml",
|
"-config tmp/config.toml",
|
||||||
"-desc 'Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität'",
|
"-desc 'Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität'",
|
||||||
"-domain localhost",
|
"-domain localhost",
|
||||||
"-feed tmp/cpolis.atom",
|
"-feed tmp/cpolis.atom",
|
||||||
"-firebase tmp/firebase.json",
|
"-firebase tmp/firebase.json",
|
||||||
"-gob tmp/cpolis.gob",
|
"-key tmp/key.gob",
|
||||||
"-link https://distrikt-ni-st.de",
|
"-link https://distrikt-ni-st.de",
|
||||||
"-log tmp/cpolis.log",
|
"-log tmp/cpolis.log",
|
||||||
"-pdfs tmp/pdfs",
|
"-pdfs tmp/pdfs",
|
||||||
"-pics tmp/pics",
|
"-pics tmp/pics",
|
||||||
"-port 8080",
|
"-port 8080",
|
||||||
|
"-rss tmp/orientexpress_alle.rss",
|
||||||
"-title 'Freimaurer Distrikt Niedersachsen und Sachsen-Anhalt'",
|
"-title 'Freimaurer Distrikt Niedersachsen und Sachsen-Anhalt'",
|
||||||
"-web web",
|
"-web web",
|
||||||
"-width 1024",
|
"-width 1024",
|
||||||
|
@ -18,7 +18,7 @@ func GenerateAtomFeed(c *Config, db *DB) (*string, error) {
|
|||||||
|
|
||||||
feed.Generator = atom.NewGenerator("cpolis")
|
feed.Generator = atom.NewGenerator("cpolis")
|
||||||
feed.Generator.URI = "https://git.streifling.com/jason/cpolis"
|
feed.Generator.URI = "https://git.streifling.com/jason/cpolis"
|
||||||
feed.Generator.Version = c.Version
|
feed.Generator.Version = "0.13"
|
||||||
|
|
||||||
articles, err := db.GetCertainArticles("published", true)
|
articles, err := db.GetCertainArticles("published", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -39,7 +39,7 @@ func GenerateAtomFeed(c *Config, db *DB) (*string, error) {
|
|||||||
entry.Links[linkID].Rel = "enclosure"
|
entry.Links[linkID].Rel = "enclosure"
|
||||||
entry.Links[linkID].Type = "image/webp"
|
entry.Links[linkID].Type = "image/webp"
|
||||||
|
|
||||||
user, err := db.GetUser(c, article.AuthorID)
|
user, err := db.GetUser(article.AuthorID)
|
||||||
if err != nil {
|
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 RSS feed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
AESKeyFile string
|
|
||||||
ArticleDir string
|
ArticleDir string
|
||||||
ConfigFile string
|
ConfigFile string
|
||||||
DBName string
|
DBName string
|
||||||
@ -20,14 +19,14 @@ type Config struct {
|
|||||||
Domain string
|
Domain string
|
||||||
AtomFeed string
|
AtomFeed string
|
||||||
FirebaseKey string
|
FirebaseKey string
|
||||||
GOBKeyFile string
|
KeyFile string
|
||||||
Link string
|
Link string
|
||||||
LogFile string
|
LogFile string
|
||||||
PDFDir string
|
PDFDir string
|
||||||
PicsDir string
|
PicsDir string
|
||||||
Port string
|
Port string
|
||||||
|
RSSFile string
|
||||||
Title string
|
Title string
|
||||||
Version string
|
|
||||||
WebDir string
|
WebDir string
|
||||||
MaxImgHeight int
|
MaxImgHeight int
|
||||||
MaxImgWidth int
|
MaxImgWidth int
|
||||||
@ -35,20 +34,19 @@ type Config struct {
|
|||||||
|
|
||||||
func newConfig() *Config {
|
func newConfig() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
AESKeyFile: "/var/www/cpolis/aes.key",
|
|
||||||
ArticleDir: "/var/www/cpolis/articles",
|
ArticleDir: "/var/www/cpolis/articles",
|
||||||
ConfigFile: "/etc/cpolis/config.toml",
|
ConfigFile: "/etc/cpolis/config.toml",
|
||||||
DBName: "cpolis",
|
DBName: "cpolis",
|
||||||
AtomFeed: "/var/www/cpolis/cpolis.atom",
|
AtomFeed: "/var/www/cpolis/cpolis.atom",
|
||||||
FirebaseKey: "/var/www/cpolis/serviceAccountKey.json",
|
FirebaseKey: "/var/www/cpolis/serviceAccountKey.json",
|
||||||
GOBKeyFile: "/var/www/cpolis/gob.key",
|
KeyFile: "/var/www/cpolis/cpolis.key",
|
||||||
LogFile: "/var/log/cpolis.log",
|
LogFile: "/var/log/cpolis.log",
|
||||||
MaxImgHeight: 1080,
|
MaxImgHeight: 1080,
|
||||||
MaxImgWidth: 1920,
|
MaxImgWidth: 1920,
|
||||||
PDFDir: "/var/www/cpolis/pdfs",
|
PDFDir: "/var/www/cpolis/pdfs",
|
||||||
PicsDir: "/var/www/cpolis/pics",
|
PicsDir: "/var/www/cpolis/pics",
|
||||||
Port: ":8080",
|
Port: ":8080",
|
||||||
Version: "v0.13.0",
|
RSSFile: "/var/www/cpolis/cpolis.rss",
|
||||||
WebDir: "/var/www/cpolis/web",
|
WebDir: "/var/www/cpolis/web",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,7 +102,6 @@ func (c *Config) handleCliArgs() error {
|
|||||||
var port int
|
var port int
|
||||||
var err error
|
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.ArticleDir, "articles", c.ArticleDir, "articles directory")
|
||||||
flag.StringVar(&c.AtomFeed, "feed", c.AtomFeed, "atom feed file")
|
flag.StringVar(&c.AtomFeed, "feed", c.AtomFeed, "atom feed file")
|
||||||
flag.StringVar(&c.ConfigFile, "config", c.ConfigFile, "config file")
|
flag.StringVar(&c.ConfigFile, "config", c.ConfigFile, "config file")
|
||||||
@ -112,11 +109,12 @@ func (c *Config) handleCliArgs() error {
|
|||||||
flag.StringVar(&c.Description, "desc", c.Description, "channel description")
|
flag.StringVar(&c.Description, "desc", c.Description, "channel description")
|
||||||
flag.StringVar(&c.Domain, "domain", c.Domain, "domain name")
|
flag.StringVar(&c.Domain, "domain", c.Domain, "domain name")
|
||||||
flag.StringVar(&c.FirebaseKey, "firebase", c.FirebaseKey, "Firebase service account key file")
|
flag.StringVar(&c.FirebaseKey, "firebase", c.FirebaseKey, "Firebase service account key file")
|
||||||
flag.StringVar(&c.GOBKeyFile, "gob", c.GOBKeyFile, "gob key file")
|
flag.StringVar(&c.KeyFile, "key", c.KeyFile, "key file")
|
||||||
flag.StringVar(&c.Link, "link", c.Link, "channel Link")
|
flag.StringVar(&c.Link, "link", c.Link, "channel Link")
|
||||||
flag.StringVar(&c.LogFile, "log", c.LogFile, "log file")
|
flag.StringVar(&c.LogFile, "log", c.LogFile, "log file")
|
||||||
flag.StringVar(&c.PDFDir, "pdfs", c.PDFDir, "pdf directory")
|
flag.StringVar(&c.PDFDir, "pdfs", c.PDFDir, "pdf directory")
|
||||||
flag.StringVar(&c.PicsDir, "pics", c.PicsDir, "pictures 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.Title, "title", c.Title, "channel title")
|
||||||
flag.StringVar(&c.WebDir, "web", c.WebDir, "web directory")
|
flag.StringVar(&c.WebDir, "web", c.WebDir, "web directory")
|
||||||
flag.IntVar(&c.MaxImgHeight, "height", c.MaxImgHeight, "maximum image height")
|
flag.IntVar(&c.MaxImgHeight, "height", c.MaxImgHeight, "maximum image height")
|
||||||
@ -149,14 +147,6 @@ func (c *Config) setupConfig(cliConfig *Config) error {
|
|||||||
var err error
|
var err error
|
||||||
defaultConfig := newConfig()
|
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 {
|
if cliConfig.ArticleDir != defaultConfig.ArticleDir {
|
||||||
c.ArticleDir = cliConfig.ArticleDir
|
c.ArticleDir = cliConfig.ArticleDir
|
||||||
}
|
}
|
||||||
@ -197,10 +187,10 @@ func (c *Config) setupConfig(cliConfig *Config) error {
|
|||||||
return fmt.Errorf("error setting up file: %v", err)
|
return fmt.Errorf("error setting up file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cliConfig.GOBKeyFile != defaultConfig.GOBKeyFile {
|
if cliConfig.KeyFile != defaultConfig.KeyFile {
|
||||||
c.GOBKeyFile = cliConfig.GOBKeyFile
|
c.KeyFile = cliConfig.KeyFile
|
||||||
}
|
}
|
||||||
c.GOBKeyFile, err = mkFile(c.GOBKeyFile, 0600, 0700)
|
c.KeyFile, err = mkFile(c.KeyFile, 0600, 0700)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error setting up file: %v", err)
|
return fmt.Errorf("error setting up file: %v", err)
|
||||||
}
|
}
|
||||||
@ -245,6 +235,14 @@ func (c *Config) setupConfig(cliConfig *Config) error {
|
|||||||
c.Port = cliConfig.Port
|
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 {
|
if cliConfig.Title != defaultConfig.Title {
|
||||||
c.Title = cliConfig.Title
|
c.Title = cliConfig.Title
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ func GenerateRSS(c *Config, db *DB) (*string, error) {
|
|||||||
tagNames = append(tagNames, "autogenerated")
|
tagNames = append(tagNames, "autogenerated")
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.GetUser(c, article.AuthorID)
|
user, err := db.GetUser(article.AuthorID)
|
||||||
if err != nil {
|
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 RSS feed: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -2,16 +2,9 @@ package backend
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/rand"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/base64"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
@ -25,135 +18,24 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
UserName string
|
UserName string
|
||||||
FirstName string
|
FirstName string
|
||||||
LastName string
|
LastName string
|
||||||
Email string
|
ID int64
|
||||||
ProfilePicLink string
|
Role int
|
||||||
ID int64
|
|
||||||
Role int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readKey(filename string) ([]byte, error) {
|
func (db *DB) AddUser(u *User, pass string) (int64, 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)
|
hashedPass, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("error creating password hash: %v", err)
|
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 := `
|
query := `
|
||||||
INSERT INTO users (username, password, first_name, last_name, email, role)
|
INSERT INTO users (username, password, first_name, last_name, role)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
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 {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("error inserting new user %v into DB: %v", u.UserName, err)
|
return 0, fmt.Errorf("error inserting new user %v into DB: %v", u.UserName, err)
|
||||||
}
|
}
|
||||||
@ -247,44 +129,34 @@ func (tx *Tx) ChangePassword(id int64, oldPass, newPass string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: No need for ID field in general
|
// TODO: No need for ID field in general
|
||||||
func (db *DB) GetUser(c *Config, id int64) (*User, error) {
|
func (db *DB) GetUser(id int64) (*User, error) {
|
||||||
var aesFirstName, aesLastName, aesEmail string
|
|
||||||
var err error
|
|
||||||
|
|
||||||
user := new(User)
|
user := new(User)
|
||||||
query := `
|
query := `
|
||||||
SELECT id, username, first_name, last_name, email, role
|
SELECT id, username, first_name, last_name, role
|
||||||
FROM users
|
FROM users
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
`
|
`
|
||||||
|
|
||||||
row := db.QueryRow(query, id)
|
row := db.QueryRow(query, id)
|
||||||
if err := row.Scan(&user.ID, &user.UserName, &aesFirstName, &aesLastName, &aesEmail, &user.Role); err != nil {
|
if err := row.Scan(&user.ID, &user.UserName, &user.FirstName,
|
||||||
|
&user.LastName, &user.Role); err != nil {
|
||||||
return nil, fmt.Errorf("error reading user information: %v", err)
|
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
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) UpdateOwnUserAttributes(c *Config, id int64, userName, firstName, lastName, email, oldPass, newPass string) error {
|
func (db *DB) UpdateOwnUserAttributes(id int64, user, first, last, oldPass, newPass, newPass2 string) error {
|
||||||
var err 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)
|
tx := new(Tx)
|
||||||
passwordEmpty := len(newPass) > 0
|
var err error
|
||||||
|
|
||||||
for i := 0; i < TxMaxRetries; i++ {
|
for i := 0; i < TxMaxRetries; i++ {
|
||||||
err := func() error {
|
err := func() error {
|
||||||
@ -302,35 +174,10 @@ func (db *DB) UpdateOwnUserAttributes(c *Config, id int64, userName, firstName,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
if err = tx.UpdateAttributes(
|
||||||
&Attribute{Table: "users", ID: id, AttName: "username", Value: userName},
|
&Attribute{Table: "users", ID: id, AttName: "username", Value: user},
|
||||||
&Attribute{Table: "users", ID: id, AttName: "first_name", Value: aesFirstName},
|
&Attribute{Table: "users", ID: id, AttName: "first_name", Value: first},
|
||||||
&Attribute{Table: "users", ID: id, AttName: "last_name", Value: aesLastName},
|
&Attribute{Table: "users", ID: id, AttName: "last_name", Value: last},
|
||||||
&Attribute{Table: "users", ID: id, AttName: "email", Value: aesEmail},
|
|
||||||
); err != nil {
|
); err != nil {
|
||||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||||
@ -355,13 +202,13 @@ func (db *DB) UpdateOwnUserAttributes(c *Config, id int64, userName, firstName,
|
|||||||
return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries)
|
return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) AddFirstUser(c *Config, u *User, pass string) (int64, error) {
|
func (db *DB) AddFirstUser(u *User, pass string) (int64, error) {
|
||||||
var numUsers int64
|
var numUsers int64
|
||||||
txOptions := &sql.TxOptions{Isolation: sql.LevelSerializable}
|
txOptions := &sql.TxOptions{Isolation: sql.LevelSerializable}
|
||||||
selectQuery := "SELECT COUNT(*) FROM users"
|
selectQuery := "SELECT COUNT(*) FROM users"
|
||||||
insertQuery := `
|
insertQuery := `
|
||||||
INSERT INTO users (username, password, first_name, last_name, email, role)
|
INSERT INTO users (username, password, first_name, last_name, role)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?)
|
||||||
`
|
`
|
||||||
|
|
||||||
for i := 0; i < TxMaxRetries; i++ {
|
for i := 0; i < TxMaxRetries; i++ {
|
||||||
@ -392,31 +239,7 @@ func (db *DB) AddFirstUser(c *Config, u *User, pass string) (int64, error) {
|
|||||||
return 0, fmt.Errorf("error creating password hash: %v", err)
|
return 0, fmt.Errorf("error creating password hash: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
aesFirstName, err := aesEncrypt(c, u.FirstName)
|
result, err := tx.Exec(insertQuery, u.UserName, string(hashedPass), u.FirstName, u.LastName, u.Role)
|
||||||
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 err != nil {
|
||||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||||
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
|
||||||
@ -447,11 +270,8 @@ func (db *DB) AddFirstUser(c *Config, u *User, pass string) (int64, error) {
|
|||||||
return 0, fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries)
|
return 0, fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) GetAllUsers(c *Config) (map[int64]*User, error) {
|
func (db *DB) GetAllUsers() (map[int64]*User, error) {
|
||||||
var aesFirstName, aesLastName, aesEmail string
|
query := "SELECT id, username, first_name, last_name, role FROM users"
|
||||||
var err error
|
|
||||||
|
|
||||||
query := "SELECT id, username, first_name, last_name, email, role FROM users"
|
|
||||||
|
|
||||||
rows, err := db.Query(query)
|
rows, err := db.Query(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -461,25 +281,10 @@ func (db *DB) GetAllUsers(c *Config) (map[int64]*User, error) {
|
|||||||
users := make(map[int64]*User, 0)
|
users := make(map[int64]*User, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
user := new(User)
|
user := new(User)
|
||||||
if err = rows.Scan(&user.ID, &user.UserName, &aesFirstName, &aesLastName, &aesEmail, &user.Role); err != nil {
|
if err = rows.Scan(&user.ID, &user.UserName, &user.FirstName,
|
||||||
|
&user.LastName, &user.Role); err != nil {
|
||||||
return nil, fmt.Errorf("error getting user info: %v", err)
|
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
|
users[user.ID] = user
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,10 +311,17 @@ func (tx *Tx) SetPassword(id int64, newPass string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) UpdateUserAttributes(c *Config, id int64, userName, firstName, lastName, email, newPass string, role int) error {
|
func (db *DB) UpdateUserAttributes(id int64, user, first, last, newPass, newPass2 string, role int) error {
|
||||||
var err 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)
|
tx := new(Tx)
|
||||||
passwordEmpty := len(newPass) > 0
|
var err error
|
||||||
|
|
||||||
for i := 0; i < TxMaxRetries; i++ {
|
for i := 0; i < TxMaxRetries; i++ {
|
||||||
err := func() error {
|
err := func() error {
|
||||||
@ -527,35 +339,10 @@ func (db *DB) UpdateUserAttributes(c *Config, id int64, userName, firstName, las
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
if err = tx.UpdateAttributes(
|
||||||
&Attribute{Table: "users", ID: id, AttName: "username", Value: userName},
|
&Attribute{Table: "users", ID: id, AttName: "username", Value: user},
|
||||||
&Attribute{Table: "users", ID: id, AttName: "first_name", Value: aesFirstName},
|
&Attribute{Table: "users", ID: id, AttName: "first_name", Value: first},
|
||||||
&Attribute{Table: "users", ID: id, AttName: "last_name", Value: aesLastName},
|
&Attribute{Table: "users", ID: id, AttName: "last_name", Value: last},
|
||||||
&Attribute{Table: "users", ID: id, AttName: "email", Value: aesEmail},
|
|
||||||
&Attribute{Table: "users", ID: id, AttName: "role", Value: role},
|
&Attribute{Table: "users", ID: id, AttName: "role", Value: role},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
if rollbackErr := tx.Rollback(); rollbackErr != nil {
|
||||||
|
17
cmd/calls/rss.go
Normal file
17
cmd/calls/rss.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
@ -146,12 +146,9 @@ func SubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -228,12 +225,9 @@ func ResubmitArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -475,12 +469,9 @@ func PublishArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -510,12 +501,9 @@ func RejectArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -710,12 +698,9 @@ func DeleteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -770,11 +755,8 @@ func AllowEditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html"))
|
tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html"))
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -110,12 +110,9 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFun
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -56,18 +56,12 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct {
|
|
||||||
Version string
|
|
||||||
Role int
|
|
||||||
})
|
|
||||||
data.Version = c.Version
|
|
||||||
|
|
||||||
files := make([]string, 2)
|
files := make([]string, 2)
|
||||||
files[0] = c.WebDir + "/templates/index.html"
|
files[0] = c.WebDir + "/templates/index.html"
|
||||||
if numRows == 0 {
|
if numRows == 0 {
|
||||||
files[1] = c.WebDir + "/templates/first-user.html"
|
files[1] = c.WebDir + "/templates/first-user.html"
|
||||||
tmpl, err := template.ParseFiles(files...)
|
tmpl, err := template.ParseFiles(files...)
|
||||||
if err = template.Must(tmpl, err).Execute(w, data); err != nil {
|
if err = template.Must(tmpl, err).Execute(w, nil); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -80,10 +74,9 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if auth, ok := session.Values["authenticated"].(bool); auth && ok {
|
if auth, ok := session.Values["authenticated"].(bool); auth && ok {
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
files[1] = c.WebDir + "/templates/hub.html"
|
files[1] = c.WebDir + "/templates/hub.html"
|
||||||
tmpl, err := template.ParseFiles(files...)
|
tmpl, err := template.ParseFiles(files...)
|
||||||
if err = template.Must(tmpl, err).Execute(w, data); err != nil {
|
if err = template.Must(tmpl, err).Execute(w, session.Values["role"]); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -91,7 +84,7 @@ func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
} else {
|
} else {
|
||||||
files[1] = c.WebDir + "/templates/login.html"
|
files[1] = c.WebDir + "/templates/login.html"
|
||||||
tmpl, err := template.ParseFiles(files...)
|
tmpl, err := template.ParseFiles(files...)
|
||||||
if err = template.Must(tmpl, err).Execute(w, data); err != nil {
|
if err = template.Must(tmpl, err).Execute(w, nil); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -118,7 +111,7 @@ func Login(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.GetUser(c, id)
|
user, err := db.GetUser(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
@ -132,7 +125,7 @@ func Login(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user); err != nil {
|
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user.Role); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -181,11 +174,8 @@ func ShowHub(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -41,12 +41,9 @@ func AddTag(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
db.AddTag(tag)
|
db.AddTag(tag)
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -11,8 +11,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func checkUserStrings(user *b.User) (string, int, bool) {
|
func checkUserStrings(user *b.User) (string, int, bool) {
|
||||||
userLen := 255
|
userLen := 15
|
||||||
nameLen := 56 // max value when aes encrypting up to 255 bytes
|
nameLen := 50
|
||||||
|
|
||||||
if len(user.UserName) > userLen {
|
if len(user.UserName) > userLen {
|
||||||
return "Benutzername", userLen, false
|
return "Benutzername", userLen, false
|
||||||
@ -55,13 +55,12 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
UserName: r.PostFormValue("username"),
|
UserName: r.PostFormValue("username"),
|
||||||
FirstName: r.PostFormValue("first-name"),
|
FirstName: r.PostFormValue("first-name"),
|
||||||
LastName: r.PostFormValue("last-name"),
|
LastName: r.PostFormValue("last-name"),
|
||||||
Email: r.PostFormValue("email"),
|
|
||||||
}
|
}
|
||||||
pass := r.PostFormValue("password")
|
pass := r.PostFormValue("password")
|
||||||
pass2 := r.PostFormValue("password2")
|
pass2 := r.PostFormValue("password2")
|
||||||
email2 := r.PostFormValue("email2")
|
|
||||||
|
|
||||||
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 {
|
if len(user.UserName) == 0 || len(user.FirstName) == 0 ||
|
||||||
|
len(user.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 {
|
||||||
http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest)
|
http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -77,11 +76,6 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Email != email2 {
|
|
||||||
http.Error(w, "Die Emailadressen stimmen nicht überein.", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if pass != pass2 {
|
if pass != pass2 {
|
||||||
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
|
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@ -100,19 +94,16 @@ func AddUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.AddUser(c, user, pass)
|
_, err = db.AddUser(user, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -129,7 +120,7 @@ func EditSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.GetUser(c, session.Values["id"].(int64))
|
user, err := db.GetUser(session.Values["id"].(int64))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
@ -159,13 +150,11 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
UserName: r.PostFormValue("username"),
|
UserName: r.PostFormValue("username"),
|
||||||
FirstName: r.PostFormValue("first-name"),
|
FirstName: r.PostFormValue("first-name"),
|
||||||
LastName: r.PostFormValue("last-name"),
|
LastName: r.PostFormValue("last-name"),
|
||||||
Email: r.PostFormValue("email"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
oldPass := r.PostFormValue("old-password")
|
oldPass := r.PostFormValue("old-password")
|
||||||
newPass := r.PostFormValue("password")
|
newPass := r.PostFormValue("password")
|
||||||
newPass2 := r.PostFormValue("password2")
|
newPass2 := r.PostFormValue("password2")
|
||||||
email2 := r.PostFormValue("email2")
|
|
||||||
|
|
||||||
if len(user.UserName) == 0 {
|
if len(user.UserName) == 0 {
|
||||||
http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest)
|
http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest)
|
||||||
@ -177,20 +166,6 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
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)
|
userString, stringLen, ok := checkUserStrings(user)
|
||||||
if !ok {
|
if !ok {
|
||||||
http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest)
|
http.Error(w, fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt."), http.StatusBadRequest)
|
||||||
@ -202,18 +177,15 @@ func UpdateSelf(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = db.UpdateOwnUserAttributes(c, user.ID, user.UserName, user.FirstName, user.LastName, user.Email, oldPass, newPass); err != nil {
|
if err = db.UpdateOwnUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, oldPass, newPass, newPass2); err != nil {
|
||||||
log.Println("error: user:", user.ID, err)
|
log.Println("error: user:", user.ID, err)
|
||||||
http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
|
http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -228,14 +200,13 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
UserName: r.PostFormValue("username"),
|
UserName: r.PostFormValue("username"),
|
||||||
FirstName: r.PostFormValue("first-name"),
|
FirstName: r.PostFormValue("first-name"),
|
||||||
LastName: r.PostFormValue("last-name"),
|
LastName: r.PostFormValue("last-name"),
|
||||||
Email: r.PostFormValue("email"),
|
|
||||||
Role: b.Admin,
|
Role: b.Admin,
|
||||||
}
|
}
|
||||||
pass := r.PostFormValue("password")
|
pass := r.PostFormValue("password")
|
||||||
pass2 := r.PostFormValue("password2")
|
pass2 := r.PostFormValue("password2")
|
||||||
email2 := r.PostFormValue("email2")
|
|
||||||
|
|
||||||
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 {
|
if len(user.UserName) == 0 || len(user.FirstName) == 0 ||
|
||||||
|
len(user.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 {
|
||||||
http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest)
|
http.Error(w, "Bitte alle Felder ausfüllen.", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -246,17 +217,12 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Email != email2 {
|
|
||||||
http.Error(w, "Die Emailadressen stimmen nicht überein.", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if pass != pass2 {
|
if pass != pass2 {
|
||||||
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
|
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user.ID, err = db.AddFirstUser(c, user, pass)
|
user.ID, err = db.AddFirstUser(user, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
@ -279,11 +245,8 @@ func AddFirstUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = 0
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", 0); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -306,7 +269,7 @@ func ShowAllUsers(c *b.Config, db *b.DB, s *b.CookieStore, action string) http.H
|
|||||||
})
|
})
|
||||||
|
|
||||||
data.Action = action
|
data.Action = action
|
||||||
data.Users, err = db.GetAllUsers(c)
|
data.Users, err = db.GetAllUsers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
@ -338,7 +301,7 @@ func EditUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.GetUser(c, id)
|
user, err := db.GetUser(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
@ -380,34 +343,19 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
|
|
||||||
user.UserName = r.PostFormValue("username")
|
user.UserName = r.PostFormValue("username")
|
||||||
if len(user.UserName) == 0 {
|
if len(user.UserName) == 0 {
|
||||||
http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusBadRequest)
|
http.Error(w, "Bitte den Benutzernamen ausfüllen.", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user.FirstName = r.PostFormValue("first-name")
|
user.FirstName = r.PostFormValue("first-name")
|
||||||
user.LastName = r.PostFormValue("last-name")
|
user.LastName = r.PostFormValue("last-name")
|
||||||
if len(user.FirstName) == 0 || len(user.LastName) == 0 {
|
if len(user.FirstName) == 0 || len(user.LastName) == 0 {
|
||||||
http.Error(w, "Bitte den vollständigen Namen ausfüllen.", http.StatusBadRequest)
|
http.Error(w, "Bitte den vollständigen Namen ausfüllen.", http.StatusInternalServerError)
|
||||||
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newPass := r.PostFormValue("password")
|
newPass := r.PostFormValue("password")
|
||||||
newPass2 := r.PostFormValue("password2")
|
newPass2 := r.PostFormValue("password2")
|
||||||
if newPass != newPass2 {
|
|
||||||
http.Error(w, "Die Passwörter stimmen nicht überein.", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
userString, stringLen, ok := checkUserStrings(user)
|
userString, stringLen, ok := checkUserStrings(user)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -420,17 +368,14 @@ func UpdateUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = db.UpdateUserAttributes(c, user.ID, user.UserName, user.FirstName, user.LastName, user.Email, newPass, user.Role); err != nil {
|
if err = db.UpdateUserAttributes(user.ID, user.UserName, user.FirstName, user.LastName, newPass, newPass2, user.Role); err != nil {
|
||||||
log.Println("error: user:", user.ID, err)
|
log.Println("error: user:", user.ID, err)
|
||||||
http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
|
http.Error(w, "Benutzerdaten konnten nicht aktualisiert werden.", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html"))
|
tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html"))
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -460,12 +405,9 @@ func DeleteUser(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := new(struct{ Role int })
|
|
||||||
data.Role = session.Values["role"].(int)
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
|
||||||
tmpl = template.Must(tmpl, err)
|
tmpl = template.Must(tmpl, err)
|
||||||
if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil {
|
if err = tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -34,13 +34,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
key, err := b.LoadKey(config.GOBKeyFile)
|
key, err := b.LoadKey(config.KeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
key, err = b.NewKey()
|
key, err = b.NewKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
if err = b.SaveKey(key, config.GOBKeyFile); err != nil {
|
if err = b.SaveKey(key, config.KeyFile); err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,6 +72,7 @@ func main() {
|
|||||||
mux.HandleFunc("GET /logout", f.Logout(config, store))
|
mux.HandleFunc("GET /logout", f.Logout(config, store))
|
||||||
mux.HandleFunc("GET /pdf/get-list", c.ServePDFList(config))
|
mux.HandleFunc("GET /pdf/get-list", c.ServePDFList(config))
|
||||||
mux.HandleFunc("GET /pdf/serve/{id}", c.ServePDF(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 /tag/create", f.CreateTag(config, store))
|
||||||
mux.HandleFunc("GET /user/create", f.CreateUser(config, store))
|
mux.HandleFunc("GET /user/create", f.CreateUser(config, store))
|
||||||
mux.HandleFunc("GET /user/delete/{id}", f.DeleteUser(config, db, store))
|
mux.HandleFunc("GET /user/delete/{id}", f.DeleteUser(config, db, store))
|
||||||
|
@ -5,14 +5,12 @@ DROP TABLE IF EXISTS issues;
|
|||||||
DROP TABLE IF EXISTS users;
|
DROP TABLE IF EXISTS users;
|
||||||
|
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id INT AUTO_INCREMENT,
|
id INT AUTO_INCREMENT,
|
||||||
username VARCHAR(255) NOT NULL UNIQUE,
|
username VARCHAR(15) NOT NULL UNIQUE,
|
||||||
password VARCHAR(60) NOT NULL,
|
password VARCHAR(60) NOT NULL,
|
||||||
first_name VARCHAR(255) NOT NULL,
|
first_name VARCHAR(50) NOT NULL,
|
||||||
last_name VARCHAR(255) NOT NULL,
|
last_name VARCHAR(50) NOT NULL,
|
||||||
email VARCHAR(255) NOT NULL,
|
role INT NOT NULL,
|
||||||
-- profile_pic_link VARCHAR(255) NOT NULL,
|
|
||||||
role INT NOT NULL,
|
|
||||||
PRIMARY KEY (id)
|
PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -26,9 +24,12 @@ CREATE TABLE articles (
|
|||||||
id INT AUTO_INCREMENT,
|
id INT AUTO_INCREMENT,
|
||||||
title VARCHAR(255) NOT NULL,
|
title VARCHAR(255) NOT NULL,
|
||||||
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
banner_link VARCHAR(255) NOT NULL,
|
banner_link VARCHAR(255),
|
||||||
summary TEXT NOT NULL,
|
summary TEXT NOT NULL,
|
||||||
content_link VARCHAR(255) NOT NULL,
|
content_link VARCHAR(255),
|
||||||
|
enc_url VARCHAR(255),
|
||||||
|
enc_length INT,
|
||||||
|
enc_type VARCHAR(255),
|
||||||
published BOOL NOT NULL,
|
published BOOL NOT NULL,
|
||||||
rejected BOOL NOT NULL,
|
rejected BOOL NOT NULL,
|
||||||
author_id INT NOT NULL,
|
author_id INT NOT NULL,
|
||||||
|
@ -32,11 +32,11 @@ textarea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.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 cursor-pointer 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 my-2 px-3 py-2 rounded-md w-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
@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;
|
@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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.EasyMDEContainer .CodeMirror {
|
.EasyMDEContainer .CodeMirror {
|
||||||
|
@ -7,36 +7,22 @@
|
|||||||
<label for="username">Benutzername</label>
|
<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" value="{{.UserName}}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="password">Passwort</label>
|
<label for="password">Passwort</label>
|
||||||
<input class="w-full" required name="password" placeholder="***" type="password" />
|
<input class="w-full" required name="password" placeholder="***" type="password" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="password2">Passwort wiederholen</label>
|
<label for="password2">Passwort wiederholen</label>
|
||||||
<input class="w-full" required name="password2" placeholder="***" type="password" />
|
<input class="w-full" required name="password2" placeholder="***" type="password" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="first-name">Vorname</label>
|
<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" value="{{.FirstName}}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="last-name">Nachname</label>
|
<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" value="{{.LastName}}" />
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div class="flex flex-wrap gap-4">
|
<div class="flex flex-wrap gap-4">
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 items-center">
|
<div class="grid grid-cols-1 items-center">
|
||||||
<label class="btn text-center" for="issue-banner-upload">Titelbild</label>
|
<label class="btn cursor-pointer text-center" for="issue-banner-upload">Titelbild</label>
|
||||||
<input class="hidden" id="issue-banner-upload" name="issue-banner" type="file" required
|
<input class="hidden" id="issue-banner-upload" name="issue-banner" type="file" required
|
||||||
hx-post="/issue/upload-banner" hx-target="#issue-banner-container" />
|
hx-post="/issue/upload-banner" hx-target="#issue-banner-container" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,16 +32,6 @@
|
|||||||
<label for="password2">Passwort wiederholen</label>
|
<label for="password2">Passwort wiederholen</label>
|
||||||
<input class="w-full" name="password2" placeholder="***" type="password" />
|
<input class="w-full" name="password2" placeholder="***" type="password" />
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div class="btn-area">
|
<div class="btn-area">
|
||||||
|
@ -27,16 +27,6 @@
|
|||||||
<label for="password2">Passwort wiederholen</label>
|
<label for="password2">Passwort wiederholen</label>
|
||||||
<input class="w-full" name="password2" placeholder="***" type="password" />
|
<input class="w-full" name="password2" placeholder="***" type="password" />
|
||||||
</div>
|
</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>
|
||||||
|
|
||||||
<div class="flex flex-wrap gap-4">
|
<div class="flex flex-wrap gap-4">
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 items-center">
|
<div class="grid grid-cols-1 items-center">
|
||||||
<label class="btn text-center" for="article-banner">Titelbild</label>
|
<label class="btn cursor-pointer text-center" for="article-banner">Titelbild</label>
|
||||||
<input class="hidden" id="article-banner" name="article-banner" type="file" required
|
<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-target="#article-banner-container" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,37 +5,23 @@
|
|||||||
<div class="grid grid-cols-3 gap-4">
|
<div class="grid grid-cols-3 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label for="username">Benutzername</label>
|
<label for="username">Benutzername</label>
|
||||||
<input class="w-full" required name="username" type="text" />
|
<input class="w-full" required name="username" type="text" value="{{.UserName}}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="password">Passwort</label>
|
<label for="password">Passwort</label>
|
||||||
<input class="w-full" required name="password" placeholder="***" type="password" />
|
<input class="w-full" required name="password" placeholder="***" type="password" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="password2">Passwort wiederholen</label>
|
<label for="password2">Passwort wiederholen</label>
|
||||||
<input class="w-full" required name="password2" placeholder="***" type="password" />
|
<input class="w-full" required name="password2" placeholder="***" type="password" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="first-name">Vorname</label>
|
<label for="first-name">Vorname</label>
|
||||||
<input class="w-full" required name="first-name" type="text" />
|
<input class="w-full" required name="first-name" type="text" value="{{.FirstName}}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label for="last-name">Nachname</label>
|
<label for="last-name">Nachname</label>
|
||||||
<input class="w-full" required name="last-name" type="text" />
|
<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" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="email2">Emailadresse wiederholen</label>
|
|
||||||
<input class="w-full" required name="email2" type="text" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -2,31 +2,30 @@
|
|||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<button class="btn" hx-get="/logout" hx-target="#page-content">Abmelden</button>
|
<button class="btn" hx-get="/logout" hx-target="#page-content">Abmelden</button>
|
||||||
|
|
||||||
{{if lt .Role 4}}
|
{{if lt . 4}}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<h2>Artikel</h2>
|
<h2>Artikel</h2>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2">
|
<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/write" hx-target="#page-content">Artikel schreiben</button>
|
||||||
<button class="btn" hx-get="/article/all-rejected" hx-target="#page-content">Artikel bearbeiten</button>
|
<button class="btn" hx-get="/article/all-rejected" hx-target="#page-content">Artikel bearbeiten</button>
|
||||||
{{if lt .Role 3}}<button class="btn" hx-get="/article/all-unpublished-unrejected-and-published-rejected"
|
{{if lt . 3}}<button class="btn" hx-get="/article/all-unpublished-unrejected-and-published-rejected"
|
||||||
hx-target="#page-content">Artikel veröffentlichen</button>{{end}}
|
hx-target="#page-content">Artikel veröffentlichen</button>{{end}}
|
||||||
{{if lt .Role 2}}<button class="btn" hx-get="/article/all-published/delete"
|
{{if lt . 2}}<button class="btn" hx-get="/article/all-published/delete" hx-target="#page-content">Artikel
|
||||||
hx-target="#page-content">Artikel löschen</button>{{end}}
|
löschen</button>{{end}}
|
||||||
{{if lt .Role 2}}<button class="btn" hx-get="/article/all-published/review-edit"
|
{{if lt . 2}}<button class="btn" hx-get="/article/all-published/review-edit"
|
||||||
hx-target="#page-content">Artikel bearbeiten lassen</button>{{end}}
|
hx-target="#page-content">Artikel bearbeiten lassen</button>{{end}}
|
||||||
{{if lt .Role 3}}<button class="btn" hx-get="/tag/create" hx-target="#page-content">Neuer
|
{{if lt . 3}}<button class="btn" hx-get="/tag/create" hx-target="#page-content">Neuer Tag</button>{{end}}
|
||||||
Tag</button>{{end}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if lt .Role 2}}
|
{{if lt . 2}}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<h2>Ausgabe</h2>
|
<h2>Ausgabe</h2>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2">
|
<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>
|
<button class="btn" hx-get="/issue/this" hx-target="#page-content">Diese Ausgabe</button>
|
||||||
<form class="flex" hx-encoding="multipart/form-data">
|
<form class="flex" hx-encoding="multipart/form-data">
|
||||||
<label class="btn text-center" for="pdf-upload">PDF hochladen</label>
|
<label class="btn cursor-pointer text-center" for="pdf-upload">PDF hochladen</label>
|
||||||
<input accept=".pdf" class="hidden" id="pdf-upload" name="pdf-upload" type="file"
|
<input accept=".pdf" class="hidden" id="pdf-upload" name="pdf-upload" type="file"
|
||||||
hx-post="/pdf/upload" />
|
hx-post="/pdf/upload" />
|
||||||
</form>
|
</form>
|
||||||
@ -34,16 +33,16 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if lt .Role 4}}
|
{{if lt . 4}}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<h2>Benutzer</h2>
|
<h2>Benutzer</h2>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-4 gap-y-2">
|
<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>
|
<button class="btn" hx-get="/user/edit/self" hx-target="#page-content">Mein Profil bearbeiten</button>
|
||||||
{{if eq .Role 0}}<button class="btn" hx-get="/user/create" hx-target="#page-content">Benutzer
|
{{if eq . 0}}<button class="btn" hx-get="/user/create" hx-target="#page-content">Benutzer
|
||||||
hinzufügen</button>{{end}}
|
hinzufügen</button>{{end}}
|
||||||
{{if eq .Role 0}}<button class="btn" hx-get="/user/show-all/edit" hx-target="#page-content">Benutzer
|
{{if eq . 0}}<button class="btn" hx-get="/user/show-all/edit" hx-target="#page-content">Benutzer
|
||||||
bearbeiten</button>{{end}}
|
bearbeiten</button>{{end}}
|
||||||
{{if eq .Role 0}}<button class="btn" hx-get="/user/show-all/delete" hx-target="#page-content">Benutzer
|
{{if eq . 0}}<button class="btn" hx-get="/user/show-all/delete" hx-target="#page-content">Benutzer
|
||||||
löschen</button>{{end}}
|
löschen</button>{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
<footer class="text-center text-gray-500 my-8">
|
<footer class="text-center text-gray-500 my-8">
|
||||||
<p>© 2024 Jason Streifling. Alle Rechte vorbehalten.</p>
|
<p>© 2024 Jason Streifling. Alle Rechte vorbehalten.</p>
|
||||||
<p>{{.Version}} - <strong>Alpha: Drastische Änderungen und Fehler vorbehalten.</strong></p>
|
<p>v0.13.0 - <strong>Alpha: Drastische Änderungen und Fehler vorbehalten.</strong></p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="https://unpkg.com/htmx.org@2.0.2"></script>
|
<script src="https://unpkg.com/htmx.org@2.0.2"></script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user