Merge branch 'develop'
This commit is contained in:
commit
86a6ab3cd2
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//package crypt
|
||||
// Package crypt provides utilities for creating hashes, random strings, password encryption
|
||||
package crypt
|
||||
|
||||
import (
|
||||
|
@ -16,24 +16,26 @@ import (
|
|||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
const bcryptRounds = 12
|
||||
|
||||
var (
|
||||
//AlphaUpper all upper alphas chars
|
||||
// AlphaUpper all upper alphas chars
|
||||
AlphaUpper = RandomSource("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
//AlphaLower all lowers alphas chars
|
||||
// AlphaLower all lowers alphas chars
|
||||
AlphaLower = RandomSource("abcdefghijklmnopqrstuvwxyz")
|
||||
//AlphaUpperLower all upper and lowers aplhas chars
|
||||
// AlphaUpperLower all upper and lowers aplhas chars
|
||||
AlphaUpperLower = RandomSource("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
||||
//AlphaUpperLowerNumeric all upper lowers alphas and numerics
|
||||
// AlphaUpperLowerNumeric all upper lowers alphas and numerics
|
||||
AlphaUpperLowerNumeric = RandomSource("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz")
|
||||
//AlphaUpperLowerNumericSpecial all upper lowers alphas, numerics and special chars
|
||||
// AlphaUpperLowerNumericSpecial all upper lowers alphas, numerics and special chars
|
||||
AlphaUpperLowerNumericSpecial = RandomSource("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456890" +
|
||||
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
|
||||
)
|
||||
|
||||
//RandomSource string containing which characters should be considered when generating random sequences
|
||||
// RandomSource string containing which characters should be considered when generating random sequences
|
||||
type RandomSource string
|
||||
|
||||
//RandomSequence returns random character with given length;
|
||||
// RandomSequence returns random character with given length;
|
||||
func (r RandomSource) RandomSequence(length int) []byte {
|
||||
result := make([]byte, length)
|
||||
for i := 0; i < length; i++ {
|
||||
|
@ -44,7 +46,7 @@ func (r RandomSource) RandomSequence(length int) []byte {
|
|||
return result
|
||||
}
|
||||
|
||||
//RandomSecureKey returns random character with given length
|
||||
// RandomSecureKey returns random character with given length
|
||||
func RandomSecureKey(length int) []byte {
|
||||
k := make([]byte, length)
|
||||
if _, err := io.ReadFull(rand.Reader, k); err != nil {
|
||||
|
@ -53,22 +55,17 @@ func RandomSecureKey(length int) []byte {
|
|||
return k
|
||||
}
|
||||
|
||||
//CryptPassword hashes a password with bcrypt and a given cost
|
||||
func CryptPassword(password []byte, cost int) ([]byte, error) {
|
||||
s, err := bcrypt.GenerateFromPassword(password, cost)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
// CryptPassword hashes a password with bcrypt and a given cost
|
||||
func CryptPassword(password []byte) ([]byte, error) {
|
||||
return bcrypt.GenerateFromPassword(password, bcryptRounds)
|
||||
}
|
||||
|
||||
//GenerateSalt generates a random salt with alphanumerics and some special characters
|
||||
// GenerateSalt generates a random salt with alphanumerics and some special characters
|
||||
func GenerateSalt() []byte {
|
||||
return AlphaUpperLowerNumericSpecial.RandomSequence(32)
|
||||
}
|
||||
|
||||
// RandomHash returns a random SHA-512 hash
|
||||
func RandomHash(length int) string {
|
||||
hash := sha512.New()
|
||||
hash.Write(RandomSecureKey(length))
|
||||
|
|
|
@ -10,17 +10,17 @@ import (
|
|||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
//SQLiteConfig represents sqlite configuration type
|
||||
// SQLiteConfig represents sqlite configuration type
|
||||
type SQLiteConfig struct {
|
||||
File string
|
||||
}
|
||||
|
||||
//Open receives handle for sqlite database, returns an error if connection failed
|
||||
// Open receives handle for sqlite database, returns an error if connection failed
|
||||
func (d SQLiteConfig) Open() (*sql.DB, error) {
|
||||
return sql.Open("sqlite3", d.File)
|
||||
}
|
||||
|
||||
//InitTables creates the tables
|
||||
// InitTables creates the tables
|
||||
func InitTables(db *sql.DB) error {
|
||||
if _, err := db.Exec("CREATE TABLE user " +
|
||||
"(" +
|
||||
|
|
20
go.mod
20
go.mod
|
@ -4,16 +4,22 @@ go 1.15
|
|||
|
||||
require (
|
||||
git.hoogi.eu/snafu/cfg v1.0.6
|
||||
git.hoogi.eu/snafu/session v1.2.0
|
||||
git.hoogi.eu/snafu/session v1.3.0
|
||||
github.com/felixge/httpsnoop v1.0.2 // indirect
|
||||
github.com/gorilla/csrf v1.7.0
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/justinas/alice v1.2.0
|
||||
github.com/mattn/go-sqlite3 v1.14.5
|
||||
github.com/microcosm-cc/bluemonday v1.0.4
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.8
|
||||
github.com/microcosm-cc/bluemonday v1.0.15
|
||||
github.com/russross/blackfriday/v2 v2.1.0
|
||||
github.com/sirupsen/logrus v1.7.0
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
|
||||
golang.org/x/net v0.0.0-20210716203947-853a461950ff // indirect
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
|
|
76
go.sum
76
go.sum
|
@ -1,17 +1,17 @@
|
|||
git.hoogi.eu/snafu/cfg v1.0.6 h1:O34hYFqjwfnMjEwB4M8GaQQmBtf3H+AA0RFHb7PoMNs=
|
||||
git.hoogi.eu/snafu/cfg v1.0.6/go.mod h1:LQolv8bqH8ZPz7h9PSVswdBXj1BIM+kW79AVS/jpE7A=
|
||||
git.hoogi.eu/snafu/session v1.1.2 h1:MclTbSqD/9JodRUqFc4OwyJGk5AtonqB6BaG5RRJHf8=
|
||||
git.hoogi.eu/snafu/session v1.1.2/go.mod h1:kgRDrnHcKc9H18G9533BXy6qO+81eBf6e9gkUzBMDuA=
|
||||
git.hoogi.eu/snafu/session v1.2.0 h1:qmZXMCAZRrzcOOLsOltwPUeA4ckpjwjjJ8fQpFDSx+w=
|
||||
git.hoogi.eu/snafu/session v1.2.0/go.mod h1:kgRDrnHcKc9H18G9533BXy6qO+81eBf6e9gkUzBMDuA=
|
||||
git.hoogi.eu/snafu/session v1.3.0 h1:CzJQG7rseuerwBcLwxoJDtvWjXNP13bnWE90TsuTAls=
|
||||
git.hoogi.eu/snafu/session v1.3.0/go.mod h1:kgRDrnHcKc9H18G9533BXy6qO+81eBf6e9gkUzBMDuA=
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
|
||||
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
|
||||
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/gorilla/csrf v1.7.0 h1:mMPjV5/3Zd460xCavIkppUdvnl5fPXMpv2uz2Zyg7/Y=
|
||||
github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA=
|
||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||
|
@ -24,36 +24,52 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC
|
|||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
|
||||
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
|
||||
github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ=
|
||||
github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
|
||||
github.com/microcosm-cc/bluemonday v1.0.4 h1:p0L+CTpo/PLFdkoPcJemLXG+fpMD7pYOoDEq1axMbGg=
|
||||
github.com/microcosm-cc/bluemonday v1.0.4/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
|
||||
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/microcosm-cc/bluemonday v1.0.15 h1:J4uN+qPng9rvkBZBoBb8YGR+ijuklIMpSOZZLjYpbeY=
|
||||
github.com/microcosm-cc/bluemonday v1.0.15/go.mod h1:ZLvAzeakRwrGnzQEvstVzVt3ZpqOF2+sdFr0Om+ce30=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210716203947-853a461950ff h1:j2EK/QoxYNBsXI4R7fQkkRUk8y6wnOBI+6hgPdP/6Ds=
|
||||
golang.org/x/net v0.0.0-20210716203947-853a461950ff/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/models"
|
||||
)
|
||||
|
||||
//AdminProfileHandler returns page for updating the profile of the currently logged-in user
|
||||
// AdminProfileHandler returns the page for updating the profile of the currently logged-in user
|
||||
func AdminProfileHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
user, _ := middleware.User(r)
|
||||
|
||||
|
@ -27,7 +27,7 @@ func AdminProfileHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
|
|||
}
|
||||
}
|
||||
|
||||
//AdminProfilePostHandler handles the updating of the user profile which is currently logged in
|
||||
// AdminProfilePostHandler handles the updating of the user profile which is currently logged in
|
||||
func AdminProfilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
ctxUser, _ := middleware.User(r)
|
||||
ctxUser.PlainPassword = []byte(r.FormValue("current_password"))
|
||||
|
@ -81,7 +81,7 @@ func AdminProfilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
|
||||
session.SetValue("userid", u.ID)
|
||||
|
||||
sessions := ctx.SessionService.SessionProvider.FindSessionsByValue("userid", u.ID)
|
||||
sessions := ctx.SessionService.SessionProvider.FindByValue("userid", u.ID)
|
||||
|
||||
for _, sid := range sessions {
|
||||
if sid.SessionID() != session.SessionID() {
|
||||
|
@ -111,7 +111,7 @@ func AdminProfilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//ActivateAccountHandler shows the form to activate an account.
|
||||
// ActivateAccountHandler shows the form to activate an account
|
||||
func ActivateAccountHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
hash := getVar(r, "hash")
|
||||
|
||||
|
@ -139,9 +139,9 @@ func ActivateAccountHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
|
|||
}
|
||||
}
|
||||
|
||||
//ActivateAccountPostHandler activates an user account
|
||||
// ActivateAccountPostHandler activates an user account
|
||||
func ActivateAccountPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
// Delete any cookies if an user is logged in
|
||||
// Delete cookie if the user is logged in
|
||||
ctx.SessionService.Remove(w, r)
|
||||
|
||||
password := r.FormValue("password")
|
||||
|
@ -196,11 +196,11 @@ func ActivateAccountPostHandler(ctx *middleware.AppContext, w http.ResponseWrite
|
|||
|
||||
return &middleware.Template{
|
||||
RedirectPath: "admin",
|
||||
SuccessMsg: "The account was successfully activated. You can now log in.",
|
||||
SuccessMsg: "The account was successfully activated. You can now login.",
|
||||
}
|
||||
}
|
||||
|
||||
//ResetPasswordHandler returns the form for resetting the password
|
||||
// ResetPasswordHandler returns the form to reset the password
|
||||
func ResetPasswordHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
hash := getVar(r, "hash")
|
||||
|
||||
|
@ -227,7 +227,7 @@ func ResetPasswordHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *
|
|||
}
|
||||
}
|
||||
|
||||
//ResetPasswordPostHandler handles the resetting of the password
|
||||
// ResetPasswordPostHandler handles a password reset
|
||||
func ResetPasswordPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
password := r.FormValue("password")
|
||||
password2 := r.FormValue("password_repeat")
|
||||
|
@ -283,14 +283,14 @@ func ResetPasswordPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//ForgotPasswordHandler returns the form for the reset password form
|
||||
// ForgotPasswordHandler returns the form for the password reset
|
||||
func ForgotPasswordHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
return &middleware.Template{
|
||||
Name: tplAdminForgotPassword,
|
||||
}
|
||||
}
|
||||
|
||||
//ForgotPasswordPostHandler handles the processing of the reset password function
|
||||
// ForgotPasswordPostHandler handles the processing for the password reset
|
||||
func ForgotPasswordPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
email := r.FormValue("email")
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/models"
|
||||
)
|
||||
|
||||
//GetArticleHandler returns a specific article
|
||||
//Parameters in the url form 2016/3/my-headline are used for obtaining the article
|
||||
// GetArticleHandler returns a specific article
|
||||
// Parameters are in the form /year/month/slug e.g. 2016/3/my-headline
|
||||
func GetArticleHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
year := getVar(r, "year")
|
||||
month := getVar(r, "month")
|
||||
|
@ -51,8 +51,7 @@ func GetArticleHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *htt
|
|||
}}
|
||||
}
|
||||
|
||||
//GetArticleHandler returns a specific article
|
||||
//Parameters in the url form 2016/03/my-headline are used for obtaining the article
|
||||
// GetArticleByIDHandler returns a specific article by the ID
|
||||
func GetArticleByIDHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
id, err := parseInt(getVar(r, "articleID"))
|
||||
|
||||
|
@ -90,7 +89,7 @@ func GetArticleByIDHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
|
|||
}}
|
||||
}
|
||||
|
||||
//ListArticlesHandler returns the template which contains all published articles
|
||||
// ListArticlesHandler returns all published articles
|
||||
func ListArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
page := getPageParam(r)
|
||||
|
||||
|
@ -142,7 +141,7 @@ func ListArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
|
|||
}
|
||||
}
|
||||
|
||||
//ListArticlesHandler returns the template which contains all published articles
|
||||
// ListArticlesCategoryHandler returns all published articles in a category
|
||||
func ListArticlesCategoryHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
page := getPageParam(r)
|
||||
|
||||
|
@ -207,7 +206,39 @@ func ListArticlesCategoryHandler(ctx *middleware.AppContext, w http.ResponseWrit
|
|||
}
|
||||
}
|
||||
|
||||
//IndexArticlesCategoryHandler returns the template information for the index page grouped by categories
|
||||
// IndexArticlesHandler returns articles for the index page
|
||||
func IndexArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
a, err := ctx.ArticleService.Index(nil, nil, nil, models.OnlyPublished)
|
||||
|
||||
if err != nil {
|
||||
return &middleware.Template{
|
||||
Name: tplIndexArticles,
|
||||
Active: "index",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
c, err := ctx.CategoryService.List(models.CategoriesWithPublishedArticles)
|
||||
|
||||
if err != nil {
|
||||
return &middleware.Template{
|
||||
Name: tplIndexArticles,
|
||||
Active: "index",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
return &middleware.Template{
|
||||
Name: tplIndexArticles,
|
||||
Active: "index",
|
||||
Data: map[string]interface{}{
|
||||
"articles": a,
|
||||
"categories": c,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// IndexArticlesCategoryHandler returns articles for the index page grouped by categories
|
||||
func IndexArticlesCategoryHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
cs, err := ctx.CategoryService.List(models.CategoriesWithPublishedArticles)
|
||||
|
||||
|
@ -257,40 +288,7 @@ func IndexArticlesCategoryHandler(ctx *middleware.AppContext, w http.ResponseWri
|
|||
}
|
||||
}
|
||||
|
||||
//IndexArticlesHandler returns the template information for the index page
|
||||
func IndexArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
a, err := ctx.ArticleService.Index(nil, nil, nil, models.OnlyPublished)
|
||||
|
||||
if err != nil {
|
||||
return &middleware.Template{
|
||||
Name: tplIndexArticles,
|
||||
Active: "index",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
c, err := ctx.CategoryService.List(models.CategoriesWithPublishedArticles)
|
||||
|
||||
if err != nil {
|
||||
return &middleware.Template{
|
||||
Name: tplIndexArticles,
|
||||
Active: "index",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
return &middleware.Template{
|
||||
Name: tplIndexArticles,
|
||||
Active: "index",
|
||||
Data: map[string]interface{}{
|
||||
"articles": a,
|
||||
"categories": c,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//GetArticleHandler returns a specific article
|
||||
//Parameters in the url form 2016/03/my-headline are used for obtaining the article
|
||||
// RSSFeed returns XML list of published articles for the RSS feed
|
||||
func RSSFeed(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) (*models.XMLData, error) {
|
||||
p := &models.Pagination{
|
||||
Limit: ctx.ConfigService.RSSFeedItems,
|
||||
|
@ -308,7 +306,7 @@ func RSSFeed(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request)
|
|||
}, nil
|
||||
}
|
||||
|
||||
//AdminListArticlesHandler returns all articles, also not yet published articles will be shown
|
||||
// AdminListArticlesHandler returns all articles, also not yet published articles
|
||||
func AdminListArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -347,8 +345,7 @@ func AdminListArticlesHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}}
|
||||
}
|
||||
|
||||
//AdminShowArticleByIDHandler returns a specific article, renders it on the front page
|
||||
//used for the preview
|
||||
// AdminPreviewArticleByIDHandler returns a specific article, renders it on the front page used for the preview
|
||||
func AdminPreviewArticleByIDHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -392,7 +389,7 @@ func AdminPreviewArticleByIDHandler(ctx *middleware.AppContext, w http.ResponseW
|
|||
}}
|
||||
}
|
||||
|
||||
// AdminArticleNewHandler returns the template which shows the form to create a new article
|
||||
// AdminArticleNewHandler returns the form to create a new article
|
||||
func AdminArticleNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
c, err := ctx.CategoryService.List(models.AllCategories)
|
||||
|
||||
|
@ -458,7 +455,7 @@ func AdminArticleNewPostHandler(ctx *middleware.AppContext, w http.ResponseWrite
|
|||
}
|
||||
}
|
||||
|
||||
//AdminArticleEditHandler shows the form for changing an article
|
||||
// AdminArticleEditHandler shows the form for changing an article
|
||||
func AdminArticleEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -499,7 +496,7 @@ func AdminArticleEditHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//AdminArticleEditPostHandler handles the update of an article
|
||||
// AdminArticleEditPostHandler handles the update of an article
|
||||
func AdminArticleEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -556,7 +553,7 @@ func AdminArticleEditPostHandler(ctx *middleware.AppContext, w http.ResponseWrit
|
|||
}
|
||||
}
|
||||
|
||||
//AdminArticlePublishHandler returns the action template which asks the user if the article should be published / unpublished
|
||||
// AdminArticlePublishHandler returns the action template which asks the user if the article should be published / unpublished
|
||||
func AdminArticlePublishHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -574,6 +571,14 @@ func AdminArticlePublishHandler(ctx *middleware.AppContext, w http.ResponseWrite
|
|||
|
||||
a, err := ctx.ArticleService.GetByID(id, u, models.All)
|
||||
|
||||
if err != nil {
|
||||
return &middleware.Template{
|
||||
Name: tplAdminArticles,
|
||||
Err: err,
|
||||
Active: "articles",
|
||||
}
|
||||
}
|
||||
|
||||
var action models.Action
|
||||
|
||||
if a.Published {
|
||||
|
@ -603,7 +608,7 @@ func AdminArticlePublishHandler(ctx *middleware.AppContext, w http.ResponseWrite
|
|||
}
|
||||
}
|
||||
|
||||
// AdminArticlePublishPostHandler publishes or "depublishes" an article
|
||||
// AdminArticlePublishPostHandler publish or unpublish an article
|
||||
func AdminArticlePublishPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -632,7 +637,7 @@ func AdminArticlePublishPostHandler(ctx *middleware.AppContext, w http.ResponseW
|
|||
}
|
||||
}
|
||||
|
||||
//AdminArticleDeleteHandler returns the action template which asks the user if the article should be removed
|
||||
// AdminArticleDeleteHandler returns the action template which asks the user if the article should be removed
|
||||
func AdminArticleDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -675,7 +680,7 @@ func AdminArticleDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter
|
|||
}
|
||||
}
|
||||
|
||||
//AdminArticleDeletePostHandler handles the removing of an article
|
||||
// AdminArticleDeletePostHandler handles the removing of an article
|
||||
func AdminArticleDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/models"
|
||||
)
|
||||
|
||||
// AdminListCategoriesHandler returns a list of all categories
|
||||
func AdminListCategoriesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
c, err := ctx.CategoryService.List(models.AllCategories)
|
||||
|
||||
|
@ -31,6 +32,7 @@ func AdminListCategoriesHandler(ctx *middleware.AppContext, w http.ResponseWrite
|
|||
}}
|
||||
}
|
||||
|
||||
// AdminGetCategoryHandler get category by the ID
|
||||
func AdminGetCategoryHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
reqVar := getVar(r, "categoryID")
|
||||
id, err := parseInt(reqVar)
|
||||
|
@ -59,7 +61,7 @@ func AdminGetCategoryHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}}
|
||||
}
|
||||
|
||||
// AdminCategoryNewHandler returns the template which shows the form to create a new article
|
||||
// AdminCategoryNewHandler returns the form to create a new category
|
||||
func AdminCategoryNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
return &middleware.Template{
|
||||
Active: "categories",
|
||||
|
@ -67,7 +69,7 @@ func AdminCategoryNewHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
// AdminCategoryNewPostHandler handles the creation of a new article
|
||||
// AdminCategoryNewPostHandler handles the creation of a new category
|
||||
func AdminCategoryNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -99,7 +101,7 @@ func AdminCategoryNewPostHandler(ctx *middleware.AppContext, w http.ResponseWrit
|
|||
}
|
||||
}
|
||||
|
||||
//AdminCategoryEditHandler shows the form for changing an article
|
||||
// AdminCategoryEditHandler shows the form to change a category
|
||||
func AdminCategoryEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
id, err := parseInt(getVar(r, "categoryID"))
|
||||
|
||||
|
@ -128,7 +130,7 @@ func AdminCategoryEditHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//AdminArticleEditPostHandler handles the update of an article
|
||||
// AdminCategoryEditPostHandler handles the update of a category
|
||||
func AdminCategoryEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -168,7 +170,7 @@ func AdminCategoryEditPostHandler(ctx *middleware.AppContext, w http.ResponseWri
|
|||
}
|
||||
}
|
||||
|
||||
//AdminArticleDeleteHandler returns the action template which asks the user if the article should be removed
|
||||
// AdminCategoryDeleteHandler returns the action which asks the user if the category should be removed
|
||||
func AdminCategoryDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
reqVar := getVar(r, "categoryID")
|
||||
|
||||
|
@ -209,7 +211,7 @@ func AdminCategoryDeleteHandler(ctx *middleware.AppContext, w http.ResponseWrite
|
|||
}
|
||||
}
|
||||
|
||||
//AdminArticleDeletePostHandler handles the removing of an article
|
||||
// AdminCategoryDeletePostHandler handles the removing of a category
|
||||
func AdminCategoryDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
reqVar := getVar(r, "categoryID")
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ type FileHandler struct {
|
|||
Context *middleware.AppContext
|
||||
}
|
||||
|
||||
//FileGetHandler serves the file based on the url filename
|
||||
// FileGetHandler serves the file based on the unique filename
|
||||
func (fh FileHandler) FileGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
rv := getVar(r, "uniquename")
|
||||
|
||||
|
@ -55,12 +55,19 @@ func (fh FileHandler) FileGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
defer rf.Close()
|
||||
defer func(rf *os.File) {
|
||||
err := rf.Close()
|
||||
|
||||
if err != nil {
|
||||
logger.Log.Errorf("error while closing the file %v", err)
|
||||
http.Error(w, "500 Internal Server Error", http.StatusInternalServerError)
|
||||
}
|
||||
}(rf)
|
||||
|
||||
http.ServeContent(w, r, loc, f.LastModified, rf)
|
||||
}
|
||||
|
||||
//AdminListFilesHandler returns the template which lists all uploaded files belonging to a user, admins will see all files
|
||||
// AdminListFilesHandler returns the template which lists all uploaded files belonging to a user, admins will see all files
|
||||
func AdminListFilesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -102,7 +109,7 @@ func AdminListFilesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
|
|||
}}
|
||||
}
|
||||
|
||||
//AdminUploadFileHandler returns the form for uploading a file
|
||||
// AdminUploadFileHandler returns the form for uploading a file
|
||||
func AdminUploadFileHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
return &middleware.Template{
|
||||
Name: tplAdminFileUpload,
|
||||
|
@ -110,6 +117,7 @@ func AdminUploadFileHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
|
|||
}
|
||||
}
|
||||
|
||||
// AdminToggleInlineFilePostHandler toggles the flag if the file should be inline or downloaded (toggles Content-Disposition header)
|
||||
func AdminToggleInlineFilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -173,6 +181,7 @@ func AdminUploadFilePostHandler(ctx *middleware.AppContext, w http.ResponseWrite
|
|||
}
|
||||
}
|
||||
|
||||
// AdminUploadJSONFilePostHandler
|
||||
func AdminUploadJSONFilePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) (*models.JSONData, error) {
|
||||
file, err := parseFileField(ctx, w, r)
|
||||
|
||||
|
@ -197,7 +206,7 @@ func AdminUploadJSONFilePostHandler(ctx *middleware.AppContext, w http.ResponseW
|
|||
return json, nil
|
||||
}
|
||||
|
||||
//AdminUploadDeleteHandler returns the action template which asks the user if the file should be removed
|
||||
// AdminUploadDeleteHandler returns the action template which asks the user if the file should be removed
|
||||
func AdminUploadDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -239,7 +248,7 @@ func AdminUploadDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//AdminUploadDeletePostHandler removes a file
|
||||
// AdminUploadDeletePostHandler removes a file
|
||||
func AdminUploadDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
|
|
@ -7,12 +7,14 @@ package handler
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
|
||||
"git.hoogi.eu/snafu/go-blog/middleware"
|
||||
"git.hoogi.eu/snafu/go-blog/models"
|
||||
)
|
||||
|
||||
// LoginHandler shows the login form;
|
||||
// if the user is already logged in the user will be redirected to the administration page of aricles
|
||||
// if the user is already logged in the user will be redirected to the administration articles page
|
||||
func LoginHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
_, err := ctx.SessionService.Get(rw, r)
|
||||
|
||||
|
@ -29,7 +31,7 @@ func LoginHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Re
|
|||
}
|
||||
|
||||
// LoginPostHandler receives the login information from the form; checks the login and
|
||||
// starts a session for the user. The sesion will be stored in a cookie
|
||||
// starts a session for the user. The session will be stored in a cookie
|
||||
func LoginPostHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return &middleware.Template{
|
||||
|
@ -75,7 +77,9 @@ func LoginPostHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *htt
|
|||
|
||||
// LogoutHandler logs the user out by removing the cookie and removing the session from the session store
|
||||
func LogoutHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
ctx.SessionService.Remove(rw, r)
|
||||
if err := ctx.SessionService.Remove(rw, r); err != nil {
|
||||
logger.Log.Infof("LogoutHandler: unable to remove session, err: %v", err)
|
||||
}
|
||||
|
||||
return &middleware.Template{
|
||||
RedirectPath: "admin",
|
||||
|
@ -85,9 +89,7 @@ func LogoutHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.R
|
|||
|
||||
// KeepAliveSessionHandler keeps a session alive.
|
||||
func KeepAliveSessionHandler(ctx *middleware.AppContext, rw http.ResponseWriter, r *http.Request) (*models.JSONData, error) {
|
||||
_, err := ctx.SessionService.Get(rw, r)
|
||||
|
||||
if err != nil {
|
||||
if _, err := ctx.SessionService.Get(rw, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/models"
|
||||
)
|
||||
|
||||
//GetSiteHandler returns the site template - only published sites are considered
|
||||
// GetSiteHandler returns the published sites
|
||||
func GetSiteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
site, err := ctx.SiteService.GetByLink(getVar(r, "site"), models.OnlyPublished)
|
||||
|
||||
|
@ -40,7 +40,7 @@ func GetSiteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.R
|
|||
}
|
||||
}
|
||||
|
||||
//AdminGetSiteHandler returns the template containing the sites
|
||||
// AdminGetSiteHandler returns a specific site by the ID
|
||||
func AdminGetSiteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
reqVar := getVar(r, "siteID")
|
||||
|
||||
|
@ -76,7 +76,7 @@ func AdminGetSiteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSitesHandler returns the template containing the sites overview in the administration
|
||||
// AdminSitesHandler returns all sites
|
||||
func AdminSitesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
page := getPageParam(r)
|
||||
|
||||
|
@ -121,7 +121,7 @@ func AdminSitesHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *htt
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSiteNewHandler returns the template for adding a new site
|
||||
// AdminSiteNewHandler returns the form for adding a new site
|
||||
func AdminSiteNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
return &middleware.Template{
|
||||
Name: tplAdminSiteNew,
|
||||
|
@ -129,8 +129,8 @@ func AdminSiteNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSiteNewPostHandler receives the form values and creating the site; on success the user is redirected with a success message
|
||||
//to the site overview
|
||||
// AdminSiteNewPostHandler receives the form values and creating the site; on success the user is redirected with a success message
|
||||
// to the site overview
|
||||
func AdminSiteNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
user, _ := middleware.User(r)
|
||||
|
||||
|
@ -169,7 +169,7 @@ func AdminSiteNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSiteEditHandler returns the template for editing an existing site
|
||||
// AdminSiteEditHandler returns the form for changing an existing site
|
||||
func AdminSiteEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
siteID, err := parseInt(getVar(r, "siteID"))
|
||||
|
||||
|
@ -198,8 +198,8 @@ func AdminSiteEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSiteEditPostHandler receives the form values and updates the site; on success the user is redirected with a success message
|
||||
//to the site overview
|
||||
// AdminSiteEditPostHandler receives the form values and updates the site; on success the user is redirected with a success message
|
||||
// to the site overview
|
||||
func AdminSiteEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u, _ := middleware.User(r)
|
||||
|
||||
|
@ -244,7 +244,7 @@ func AdminSiteEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSiteOrderHandler moves the site with site id down or up
|
||||
// AdminSiteOrderHandler moves the site with site ID down or up
|
||||
func AdminSiteOrderHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
siteID, err := parseInt(getVar(r, "siteID"))
|
||||
|
||||
|
@ -286,7 +286,7 @@ func AdminSiteOrderHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSitePublishHandler returns the action template which asks the user if the site should be published / unpublished
|
||||
// AdminSitePublishHandler returns the action template which asks the user if the site should be published / unpublished
|
||||
func AdminSitePublishHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
reqVar := getVar(r, "siteID")
|
||||
|
||||
|
@ -338,7 +338,7 @@ func AdminSitePublishHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSitePublishPostHandler handles the un-/publishing of a site
|
||||
// AdminSitePublishPostHandler handles the un-/publishing of a site
|
||||
func AdminSitePublishPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
reqVar := getVar(r, "siteID")
|
||||
|
||||
|
@ -367,7 +367,7 @@ func AdminSitePublishPostHandler(ctx *middleware.AppContext, w http.ResponseWrit
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSiteDeleteHandler returns the action template which asks the user if the site should be removed
|
||||
// AdminSiteDeleteHandler returns the action which asks the user if the site should be removed
|
||||
func AdminSiteDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
reqVar := getVar(r, "siteID")
|
||||
|
||||
|
@ -408,7 +408,7 @@ func AdminSiteDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
|
|||
}
|
||||
}
|
||||
|
||||
//AdminSiteDeletePostHandler handles the removing of a site
|
||||
// AdminSiteDeletePostHandler handles the removing of a site
|
||||
func AdminSiteDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
reqVar := getVar(r, "siteID")
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/models"
|
||||
)
|
||||
|
||||
//AdminUsersHandler returns an overview of the created users (admin only action)
|
||||
// AdminUsersHandler returns an overview of the created users
|
||||
func AdminUsersHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
page := getPageParam(r)
|
||||
|
||||
|
@ -73,7 +73,7 @@ func AdminUsersHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *htt
|
|||
}
|
||||
}
|
||||
|
||||
//AdminUserNewHandler returns the form for adding new user (admin only action)
|
||||
// AdminUserNewHandler returns the form for adding new user
|
||||
func AdminUserNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
return &middleware.Template{
|
||||
Name: tplAdminUserNew,
|
||||
|
@ -81,7 +81,7 @@ func AdminUserNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *h
|
|||
}
|
||||
}
|
||||
|
||||
//AdminUserNewPostHandler handles the creation of new users (admin only action)
|
||||
// AdminUserNewPostHandler handles the creation of new users
|
||||
func AdminUserNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
u := &models.User{
|
||||
DisplayName: r.FormValue("displayname"),
|
||||
|
@ -114,7 +114,7 @@ func AdminUserNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//AdminUserEditHandler returns the form for editing an user (admin only action)
|
||||
// AdminUserEditHandler returns the form for editing an user
|
||||
func AdminUserEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
userID, err := parseInt(getVar(r, "userID"))
|
||||
|
||||
|
@ -143,7 +143,7 @@ func AdminUserEditHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *
|
|||
}
|
||||
}
|
||||
|
||||
//AdminUserEditPostHandler handles the updating of an user (admin only action)
|
||||
// AdminUserEditPostHandler handles the updating of an user
|
||||
func AdminUserEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
userID, err := parseInt(getVar(r, "userID"))
|
||||
|
||||
|
@ -196,7 +196,7 @@ func AdminUserEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
sessions := ctx.SessionService.SessionProvider.FindSessionsByValue("userid", u.ID)
|
||||
sessions := ctx.SessionService.SessionProvider.FindByValue("userid", u.ID)
|
||||
|
||||
for _, s := range sessions {
|
||||
if session.SessionID() != s.SessionID() {
|
||||
|
@ -212,7 +212,7 @@ func AdminUserEditPostHandler(ctx *middleware.AppContext, w http.ResponseWriter,
|
|||
}
|
||||
}
|
||||
|
||||
//AdminUserDeleteHandler returns the form for removing user (admin only action)
|
||||
// AdminUserDeleteHandler returns the form for removing a user
|
||||
func AdminUserDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
userID, err := parseInt(getVar(r, "userID"))
|
||||
|
||||
|
@ -256,7 +256,7 @@ func AdminUserDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r
|
|||
}
|
||||
}
|
||||
|
||||
//AdminUserDeletePostHandler handles removing of a user (admin only action)
|
||||
// AdminUserDeletePostHandler handles removing of a user
|
||||
func AdminUserDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
userID, err := parseInt(getVar(r, "userID"))
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/models"
|
||||
)
|
||||
|
||||
// AdminUserInviteNewHandler shows the form to invite an user
|
||||
func AdminUserInviteNewHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
return &middleware.Template{
|
||||
Name: tplAdminUserInviteNew,
|
||||
|
@ -15,6 +16,7 @@ func AdminUserInviteNewHandler(ctx *middleware.AppContext, w http.ResponseWriter
|
|||
}
|
||||
}
|
||||
|
||||
// AdminUserInviteNewPostHandler handles the invitation, sends an activation mail to the invited user
|
||||
func AdminUserInviteNewPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
user, _ := middleware.User(r)
|
||||
|
||||
|
@ -52,6 +54,7 @@ func AdminUserInviteNewPostHandler(ctx *middleware.AppContext, w http.ResponseWr
|
|||
}
|
||||
}
|
||||
|
||||
// AdminUserInviteResendPostHandler resends the activation link to the user
|
||||
func AdminUserInviteResendPostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
inviteID, err := parseInt(getVar(r, "inviteID"))
|
||||
|
||||
|
@ -86,6 +89,7 @@ func AdminUserInviteResendPostHandler(ctx *middleware.AppContext, w http.Respons
|
|||
}
|
||||
}
|
||||
|
||||
// AdminUserInviteDeleteHandler shows the form to remove an user invitation
|
||||
func AdminUserInviteDeleteHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
inviteID, err := parseInt(getVar(r, "inviteID"))
|
||||
|
||||
|
@ -124,6 +128,7 @@ func AdminUserInviteDeleteHandler(ctx *middleware.AppContext, w http.ResponseWri
|
|||
}
|
||||
}
|
||||
|
||||
// AdminUserInviteDeletePostHandler handles the removing of an user invitation
|
||||
func AdminUserInviteDeletePostHandler(ctx *middleware.AppContext, w http.ResponseWriter, r *http.Request) *middleware.Template {
|
||||
inviteID, err := parseInt(getVar(r, "inviteID"))
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ func setup(t *testing.T) {
|
|||
AppConfig: &cfg.Application,
|
||||
}
|
||||
|
||||
sessionService := session.SessionService{
|
||||
sessionService := session.Service{
|
||||
Path: "/admin",
|
||||
Name: "test-session",
|
||||
HTTPOnly: true,
|
||||
|
@ -147,7 +147,7 @@ func teardown() {
|
|||
func fillSeeds(db *sql.DB) error {
|
||||
salt := crypt.GenerateSalt()
|
||||
saltedPassword := append([]byte("123456789012"), salt[:]...)
|
||||
password, err := crypt.CryptPassword([]byte(saltedPassword), 12)
|
||||
password, err := crypt.CryptPassword([]byte(saltedPassword))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -9,23 +9,23 @@ import (
|
|||
"net/http"
|
||||
)
|
||||
|
||||
//Error enriches the original go error type with
|
||||
//DisplayMsg the description for the displaying message
|
||||
//HTTPStatus the HTTP status code
|
||||
//Err the internal error it should not be shown to the user
|
||||
// Error enriches the original go error type with
|
||||
// DisplayMsg the human readable display message
|
||||
// HTTPStatus the HTTP status code
|
||||
// Err the internal error
|
||||
type Error struct {
|
||||
DisplayMsg string `json:"display_message"`
|
||||
HTTPStatus int `json:"status"`
|
||||
Err error `json:"-"`
|
||||
}
|
||||
|
||||
//New returns a new error
|
||||
// New returns a new error
|
||||
func New(httpStatus int, displayMsg string, err error) *Error {
|
||||
return &Error{DisplayMsg: displayMsg, Err: err, HTTPStatus: httpStatus}
|
||||
}
|
||||
|
||||
//PermissionDenied returns a permission denied message with code 403.
|
||||
//The following display message is returned: "You are not allowed to [action] the [subject]."
|
||||
// PermissionDenied returns a permission denied message with code 403.
|
||||
// The following display message is returned: "You are not allowed to [action] the [subject]."
|
||||
func PermissionDenied(action, subject string, err error) *Error {
|
||||
return &Error{
|
||||
HTTPStatus: http.StatusForbidden,
|
||||
|
@ -34,8 +34,8 @@ func PermissionDenied(action, subject string, err error) *Error {
|
|||
}
|
||||
}
|
||||
|
||||
//NotFound returns a not found message with code 404.
|
||||
//The following display message is returned: "The [res] was not found."
|
||||
// NotFound returns a not found message with code 404.
|
||||
// The following display message is returned: "The [res] was not found."
|
||||
func NotFound(res string, err error) *Error {
|
||||
return &Error{
|
||||
HTTPStatus: http.StatusNotFound,
|
||||
|
@ -44,8 +44,8 @@ func NotFound(res string, err error) *Error {
|
|||
}
|
||||
}
|
||||
|
||||
//ValueTooLong returns the following display message with code 422.
|
||||
//Display message: "The value of [param] is too long. Maximum [nchars] characters are allowed."
|
||||
// ValueTooLong returns the following display message with code 422.
|
||||
// Display message: "The value of [param] is too long. Maximum [nchars] characters are allowed."
|
||||
func ValueTooLong(param string, nchars int) *Error {
|
||||
return &Error{
|
||||
HTTPStatus: http.StatusUnprocessableEntity,
|
||||
|
@ -54,18 +54,18 @@ func ValueTooLong(param string, nchars int) *Error {
|
|||
}
|
||||
}
|
||||
|
||||
//InternalServerError returns a internal server error message with code 500.
|
||||
//Display message: "An internal server error occured."
|
||||
// InternalServerError returns a internal server error message with code 500.
|
||||
// Display message: "An internal server error occurred."
|
||||
func InternalServerError(err error) *Error {
|
||||
return &Error{
|
||||
HTTPStatus: http.StatusInternalServerError,
|
||||
DisplayMsg: "An internal server error occured.",
|
||||
DisplayMsg: "An internal server error occurred.",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
//ParameterMissing returns a parameter missing message with code 422.
|
||||
//Display message: "The parameter [param] is invalid."
|
||||
// ParameterMissing returns a parameter missing message with code 422.
|
||||
// Display message: "The parameter [param] is invalid."
|
||||
func ParameterMissing(param string, err error) *Error {
|
||||
return &Error{
|
||||
HTTPStatus: http.StatusUnprocessableEntity,
|
||||
|
@ -74,8 +74,8 @@ func ParameterMissing(param string, err error) *Error {
|
|||
}
|
||||
}
|
||||
|
||||
//ValueRequired returns a value required message with code 422.
|
||||
//Display message: "Please fill out the field [param]."
|
||||
// ValueRequired returns a value required message with code 422.
|
||||
// Display message: "Please fill out the field [param]."
|
||||
func ValueRequired(param string) *Error {
|
||||
return &Error{
|
||||
HTTPStatus: http.StatusUnprocessableEntity,
|
||||
|
|
|
@ -11,12 +11,12 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
//Log returns a new logrus instance
|
||||
// Log returns a new logrus instance
|
||||
var Log = logrus.New()
|
||||
|
||||
//InitLogger initializes the logger
|
||||
//Valid log levels are: debug|info|warn|error|fatal|panic
|
||||
//Fallback: info
|
||||
// InitLogger initializes the logger
|
||||
// Valid log levels are: debug|info|warn|error|fatal|panic
|
||||
// Fallback: info
|
||||
func InitLogger(w io.Writer, level string) {
|
||||
level = strings.ToLower(level)
|
||||
|
||||
|
|
18
mail/mail.go
18
mail/mail.go
|
@ -9,8 +9,8 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
)
|
||||
|
||||
//Service holds configuration for the SMTP server
|
||||
//The sender address and an optional subject prefix
|
||||
// Service holds configuration for the SMTP server
|
||||
// The sender address and an optional subject prefix
|
||||
type Service struct {
|
||||
SubjectPrefix string
|
||||
SMTPConfig SMTPConfig
|
||||
|
@ -25,7 +25,7 @@ func (m Mail) validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//NewMailService returns a new Service with specified config
|
||||
// NewMailService returns a new Service with specified config
|
||||
func NewMailService(subjectPrefix, from string, smtpConfig SMTPConfig) Service {
|
||||
s := Service{
|
||||
SubjectPrefix: subjectPrefix,
|
||||
|
@ -44,16 +44,16 @@ type Sender interface {
|
|||
SendAsync(m Mail)
|
||||
}
|
||||
|
||||
//SMTPConfig holds the configuration for the SMTP server
|
||||
// SMTPConfig holds the configuration for the SMTP server
|
||||
type SMTPConfig struct {
|
||||
Address string
|
||||
Port int
|
||||
User string
|
||||
Helo string
|
||||
HELO string
|
||||
Password []byte
|
||||
}
|
||||
|
||||
//Mail represents a mail
|
||||
// Mail represents a mail
|
||||
type Mail struct {
|
||||
To string
|
||||
Subject string
|
||||
|
@ -89,7 +89,7 @@ func (s Service) SendAsync(m Mail) {
|
|||
}()
|
||||
}
|
||||
|
||||
//Send sends a mail over the configured SMTP server
|
||||
// Send sends a mail over the configured SMTP server
|
||||
func (s Service) Send(m Mail) error {
|
||||
if len(s.SMTPConfig.User) > 0 && len(s.SMTPConfig.Password) > 0 {
|
||||
auth := smtp.PlainAuth("", s.SMTPConfig.User, string(s.SMTPConfig.Password), s.SMTPConfig.Address)
|
||||
|
@ -109,8 +109,8 @@ func (s Service) Send(m Mail) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if len(s.SMTPConfig.Helo) > 0 {
|
||||
if err := c.Hello(s.SMTPConfig.Helo); err != nil {
|
||||
if len(s.SMTPConfig.HELO) > 0 {
|
||||
if err := c.Hello(s.SMTPConfig.HELO); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
40
main.go
40
main.go
|
@ -36,19 +36,19 @@ func main() {
|
|||
}()
|
||||
|
||||
configFiles := []cfg.File{
|
||||
cfg.File{
|
||||
{
|
||||
Name: "go-blog.conf",
|
||||
Path: ".",
|
||||
Required: true,
|
||||
},
|
||||
cfg.File{
|
||||
{
|
||||
Name: "go-blog.conf",
|
||||
Path: "./custom",
|
||||
Required: false,
|
||||
},
|
||||
}
|
||||
|
||||
cfg, err := settings.MergeConfigs(configFiles)
|
||||
config, err := settings.MergeConfigs(configFiles)
|
||||
|
||||
if err != nil {
|
||||
exitCode = 1
|
||||
|
@ -56,29 +56,29 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
cfg.BuildVersion = BuildVersion
|
||||
cfg.BuildGitHash = GitHash
|
||||
config.BuildVersion = BuildVersion
|
||||
config.BuildGitHash = GitHash
|
||||
|
||||
if err = cfg.CheckConfig(); err != nil {
|
||||
if err = config.CheckConfig(); err != nil {
|
||||
exitCode = 1
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if cfg.Environment == "prod" {
|
||||
logFile, err := os.OpenFile(cfg.Log.File, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
|
||||
if config.Environment == "prod" {
|
||||
logFile, err := os.OpenFile(config.Log.File, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
exitCode = 1
|
||||
}
|
||||
|
||||
logger.InitLogger(logFile, cfg.Log.Level)
|
||||
logger.InitLogger(logFile, config.Log.Level)
|
||||
} else {
|
||||
logger.InitLogger(os.Stdout, cfg.Log.Level)
|
||||
logger.InitLogger(os.Stdout, config.Log.Level)
|
||||
}
|
||||
|
||||
csrf, err := cfg.GenerateCSRF()
|
||||
csrf, err := config.GenerateCSRF()
|
||||
|
||||
if err != nil {
|
||||
exitCode = 1
|
||||
|
@ -91,10 +91,10 @@ func main() {
|
|||
}
|
||||
|
||||
logger.Log.Infof("Go-Blog version: %s, commit: %s", BuildVersion, GitHash)
|
||||
logger.Log.Infof("running in %s mode", cfg.Environment)
|
||||
logger.Log.Infof("running in %s mode", config.Environment)
|
||||
|
||||
dbConf := database.SQLiteConfig{
|
||||
File: cfg.Database.File,
|
||||
File: config.Database.File,
|
||||
}
|
||||
|
||||
db, err := dbConf.Open()
|
||||
|
@ -112,7 +112,7 @@ func main() {
|
|||
}
|
||||
}()
|
||||
|
||||
ctx, err := context(db, cfg)
|
||||
ctx, err := context(db, config)
|
||||
|
||||
if err != nil {
|
||||
logger.Log.Error(err)
|
||||
|
@ -120,20 +120,20 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
r := routers.InitRoutes(ctx, cfg)
|
||||
r := routers.InitRoutes(ctx, config)
|
||||
|
||||
s := &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", cfg.Server.Address, cfg.Server.Port),
|
||||
Addr: fmt.Sprintf("%s:%d", config.Server.Address, config.Server.Port),
|
||||
Handler: r,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 20 * time.Second,
|
||||
MaxHeaderBytes: 1 << 20,
|
||||
}
|
||||
|
||||
logger.Log.Infof("server will start at %s on port %d", cfg.Server.Address, cfg.Server.Port)
|
||||
logger.Log.Infof("server will start at %s on port %d", config.Server.Address, config.Server.Port)
|
||||
|
||||
if cfg.Server.UseTLS {
|
||||
err = s.ListenAndServeTLS(cfg.Server.Cert, cfg.Server.Key)
|
||||
if config.Server.UseTLS {
|
||||
err = s.ListenAndServeTLS(config.Server.Cert, config.Server.Key)
|
||||
|
||||
} else {
|
||||
err = s.ListenAndServe()
|
||||
|
@ -221,7 +221,7 @@ func context(db *sql.DB, cfg *settings.Settings) (*m.AppContext, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
sessionService := session.SessionService{
|
||||
sessionService := session.Service{
|
||||
Path: cfg.Session.CookiePath,
|
||||
Name: cfg.Session.CookieName,
|
||||
Secure: cfg.Session.CookieSecure,
|
||||
|
|
|
@ -12,9 +12,9 @@ import (
|
|||
"git.hoogi.eu/snafu/session"
|
||||
)
|
||||
|
||||
//AppContext contains the services, session store, templates, ...
|
||||
// AppContext contains the services, session store, templates, ...
|
||||
type AppContext struct {
|
||||
SessionService *session.SessionService
|
||||
SessionService *session.Service
|
||||
ArticleService models.ArticleService
|
||||
CategoryService models.CategoryService
|
||||
UserService models.UserService
|
||||
|
|
|
@ -19,7 +19,7 @@ type JSONHandler struct {
|
|||
Handler JHandler
|
||||
}
|
||||
|
||||
//JHandler enriches handler with the AppContext
|
||||
// JHandler enriches handler with the AppContext
|
||||
type JHandler func(*AppContext, http.ResponseWriter, *http.Request) (*models.JSONData, error)
|
||||
|
||||
func (fn JSONHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
|
@ -41,6 +41,7 @@ func (fn JSONHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|||
logger.Log.Error(err)
|
||||
|
||||
j, err := json.Marshal(err)
|
||||
|
||||
if err != nil {
|
||||
logger.Log.Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
|
@ -48,7 +49,14 @@ func (fn JSONHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
rw.WriteHeader(code)
|
||||
rw.Write(j)
|
||||
|
||||
_, err = rw.Write(j)
|
||||
|
||||
if err != nil {
|
||||
logger.Log.Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -61,5 +69,12 @@ func (fn JSONHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
rw.WriteHeader(code)
|
||||
rw.Write(j)
|
||||
|
||||
_, err = rw.Write(j)
|
||||
|
||||
if err != nil {
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,15 @@ import (
|
|||
)
|
||||
|
||||
var locals = [...]net.IPNet{
|
||||
net.IPNet{
|
||||
{
|
||||
IP: net.IPv4(10, 0, 0, 0),
|
||||
Mask: net.CIDRMask(8, 32),
|
||||
},
|
||||
net.IPNet{
|
||||
{
|
||||
IP: net.IPv4(172, 16, 0, 0),
|
||||
Mask: net.CIDRMask(12, 32),
|
||||
},
|
||||
net.IPNet{
|
||||
{
|
||||
IP: net.IPv4(192, 168, 0, 0),
|
||||
Mask: net.CIDRMask(16, 32),
|
||||
},
|
||||
|
|
|
@ -36,13 +36,13 @@ type Template struct {
|
|||
Err error
|
||||
}
|
||||
|
||||
//Templates defines in which directory should be looked for template
|
||||
// Templates defines in which directory should be looked for template
|
||||
type Templates struct {
|
||||
Directory string
|
||||
FuncMap template.FuncMap
|
||||
}
|
||||
|
||||
//NotFound returned if no route matches
|
||||
// NotFound returned if no route matches
|
||||
func NotFound(ctx *AppContext, rw http.ResponseWriter, r *http.Request) *Template {
|
||||
//For deleting flash cookies
|
||||
getFlash(rw, r, "ErrorMsg")
|
||||
|
@ -63,7 +63,7 @@ func NotFound(ctx *AppContext, rw http.ResponseWriter, r *http.Request) *Templat
|
|||
}
|
||||
}
|
||||
|
||||
//FuncMap some function that can be used in templates
|
||||
// FuncMap some function that can be used in templates
|
||||
func FuncMap(ss models.SiteService, settings *settings.Settings) template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"GetMetadata": func(data map[string]interface{}) template.HTML {
|
||||
|
@ -202,7 +202,7 @@ func FuncMap(ss models.SiteService, settings *settings.Settings) template.FuncMa
|
|||
}
|
||||
}
|
||||
|
||||
//Load walks threw directory and parses templates ending with html
|
||||
// Load walks threw directory and parses templates ending with html
|
||||
func (ts Templates) Load() (*template.Template, error) {
|
||||
tpl := template.New("").Funcs(ts.FuncMap)
|
||||
|
||||
|
@ -227,7 +227,7 @@ func (ts Templates) Load() (*template.Template, error) {
|
|||
return tpl, err
|
||||
}
|
||||
|
||||
//RedirectURL builds a URL for redirecting
|
||||
// RedirectURL builds a URL for redirecting
|
||||
func (t Template) RedirectURL() string {
|
||||
if t.RedirectPath[0] == byte('/') {
|
||||
return t.RedirectPath
|
||||
|
|
|
@ -23,13 +23,13 @@ var (
|
|||
UserContextKey = contextKey("user")
|
||||
)
|
||||
|
||||
//TemplateHandler enriches handlers with a application context containing 'services'
|
||||
// TemplateHandler enriches handlers with a application context containing 'services'
|
||||
type TemplateHandler struct {
|
||||
AppCtx *AppContext
|
||||
Handler Handler
|
||||
}
|
||||
|
||||
//Handler enriches handler with the AppContext
|
||||
// Handler enriches handler with the AppContext
|
||||
type Handler func(*AppContext, http.ResponseWriter, *http.Request) *Template
|
||||
|
||||
func (fn TemplateHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
|
@ -66,7 +66,7 @@ func (fn TemplateHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|||
errorMsg = e.DisplayMsg
|
||||
default:
|
||||
en.Error(e)
|
||||
errorMsg = "Sorry, an internal server error occured"
|
||||
errorMsg = "Sorry, an internal server error occurred"
|
||||
}
|
||||
|
||||
t.Data["ErrorMsg"] = errorMsg
|
||||
|
@ -119,7 +119,7 @@ func (fn TemplateHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
//AuthHandler checks if the user is authenticated; if not next handler in chain is not called
|
||||
// AuthHandler checks if the user is authenticated; if not next handler in chain is not called
|
||||
func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
|
||||
fn := func(rw http.ResponseWriter, r *http.Request) {
|
||||
session, err := ctx.SessionService.Get(rw, r)
|
||||
|
@ -127,11 +127,14 @@ func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
|
|||
if err != nil {
|
||||
logger.Log.Error(err)
|
||||
rw.WriteHeader(http.StatusUnauthorized)
|
||||
ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
|
||||
if err := ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
|
||||
"ErrorMsg": "Please provide login credentials.",
|
||||
"state": r.URL.EscapedPath(),
|
||||
csrf.TemplateTag: csrf.TemplateField(r),
|
||||
})
|
||||
}); err != nil {
|
||||
logger.Log.Errorf("error while executing the template %v", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -141,11 +144,15 @@ func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
|
|||
logger.Log.Errorf("userid is not an integer %v", userid)
|
||||
|
||||
rw.WriteHeader(http.StatusUnauthorized)
|
||||
ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
|
||||
if err := ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
|
||||
"ErrorMsg": "Please provide login credentials.",
|
||||
"state": r.URL.EscapedPath(),
|
||||
csrf.TemplateTag: csrf.TemplateField(r),
|
||||
})
|
||||
}); err != nil {
|
||||
logger.Log.Errorf("error while executing the template %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -154,11 +161,14 @@ func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
|
|||
if err != nil {
|
||||
logger.Log.Error(err)
|
||||
rw.WriteHeader(http.StatusUnauthorized)
|
||||
ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
|
||||
if err := ctx.Templates.ExecuteTemplate(rw, "admin/login", map[string]interface{}{
|
||||
"ErrorMsg": "Please provide login credentials.",
|
||||
"state": r.URL.EscapedPath(),
|
||||
csrf.TemplateTag: csrf.TemplateField(r),
|
||||
})
|
||||
}); err != nil {
|
||||
logger.Log.Errorf("error while executing the template %v", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -167,24 +177,30 @@ func (ctx AppContext) AuthHandler(handler http.Handler) http.Handler {
|
|||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
//RequireAdmin ensures that the user is an admin; if not next handler in chain is not called
|
||||
// RequireAdmin ensures that the user is an admin; if not next handler in chain is not called
|
||||
func (ctx AppContext) RequireAdmin(handler http.Handler) http.Handler {
|
||||
fn := func(rw http.ResponseWriter, r *http.Request) {
|
||||
u, err := User(r)
|
||||
|
||||
if err != nil {
|
||||
logger.Log.Error(err)
|
||||
ctx.Templates.ExecuteTemplate(rw, "admin/error", map[string]interface{}{
|
||||
"ErrorMsg": "An internal server error occured",
|
||||
})
|
||||
if err := ctx.Templates.ExecuteTemplate(rw, "admin/error", map[string]interface{}{
|
||||
"ErrorMsg": "An internal server error occurred",
|
||||
}); err != nil {
|
||||
logger.Log.Errorf("error while executing the template %v", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if u.IsAdmin == false {
|
||||
ctx.Templates.ExecuteTemplate(rw, "admin/error", map[string]interface{}{
|
||||
if err := ctx.Templates.ExecuteTemplate(rw, "admin/error", map[string]interface{}{
|
||||
"ErrorMsg": "You have not the permissions to execute this action",
|
||||
"currentUser": u,
|
||||
})
|
||||
}); err != nil {
|
||||
logger.Log.Errorf("error while executing the template %v", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -193,7 +209,7 @@ func (ctx AppContext) RequireAdmin(handler http.Handler) http.Handler {
|
|||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
//User gets the user from the request context
|
||||
// User gets the user from the request context
|
||||
func User(r *http.Request) (*models.User, error) {
|
||||
v := r.Context().Value(UserContextKey)
|
||||
if v == nil {
|
||||
|
|
|
@ -15,7 +15,7 @@ type XMLHandler struct {
|
|||
Handler XHandler
|
||||
}
|
||||
|
||||
//XNLHandler enriches handler with the AppContext
|
||||
// XHandler enriches handler with the AppContext
|
||||
type XHandler func(*AppContext, http.ResponseWriter, *http.Request) (*models.XMLData, error)
|
||||
|
||||
func (fn XMLHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
|
@ -34,7 +34,12 @@ func (fn XMLHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
rw.Write(x)
|
||||
if _, err = rw.Write(x); err != nil {
|
||||
logger.Log.Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -55,5 +60,9 @@ func (fn XMLHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
|||
x = bytes.Replace(x, []byte(">"), []byte(">"), -1) // >
|
||||
}
|
||||
|
||||
rw.Write(x)
|
||||
if _, err := rw.Write(x); err != nil {
|
||||
logger.Log.Error(err)
|
||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ type Article struct {
|
|||
CName sql.NullString
|
||||
}
|
||||
|
||||
//ArticleDatasourceService defines an interface for CRUD operations of articles
|
||||
// ArticleDatasourceService defines an interface for CRUD operations of articles
|
||||
type ArticleDatasourceService interface {
|
||||
Create(a *Article) (int, error)
|
||||
List(u *User, c *Category, p *Pagination, pc PublishedCriteria) ([]Article, error)
|
||||
|
@ -53,7 +53,7 @@ const (
|
|||
maxHeadlineSize = 150
|
||||
)
|
||||
|
||||
//SlugEscape escapes the slug for use in URLs
|
||||
// SlugEscape escapes the slug for use in URLs
|
||||
func (a Article) SlugEscape() string {
|
||||
spl := strings.Split(a.Slug, "/")
|
||||
return fmt.Sprintf("%s/%s/%s", spl[0], spl[1], url.PathEscape(spl[2]))
|
||||
|
@ -106,7 +106,7 @@ func (a *Article) validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//ArticleService containing the service to access articles
|
||||
// ArticleService containing the service to access articles
|
||||
type ArticleService struct {
|
||||
Datasource ArticleDatasourceService
|
||||
AppConfig settings.Application
|
||||
|
@ -129,7 +129,7 @@ func (as ArticleService) Create(a *Article) (int, error) {
|
|||
return as.Datasource.Create(a)
|
||||
}
|
||||
|
||||
//Update updates an article
|
||||
// Update updates an article
|
||||
func (as ArticleService) Update(a *Article, u *User, updateSlug bool) error {
|
||||
if err := a.validate(); err != nil {
|
||||
return err
|
||||
|
@ -161,7 +161,7 @@ func (as ArticleService) Update(a *Article, u *User, updateSlug bool) error {
|
|||
return as.Datasource.Update(a)
|
||||
}
|
||||
|
||||
//Publish publishes or 'unpublishes' an article
|
||||
// Publish publishes or 'unpublishes' an article
|
||||
func (as ArticleService) Publish(id int, u *User) error {
|
||||
a, err := as.Datasource.Get(id, nil, All)
|
||||
|
||||
|
@ -178,7 +178,7 @@ func (as ArticleService) Publish(id int, u *User) error {
|
|||
return as.Datasource.Publish(a)
|
||||
}
|
||||
|
||||
//Delete deletes an article
|
||||
// Delete deletes an article
|
||||
func (as ArticleService) Delete(id int, u *User) error {
|
||||
a, err := as.Datasource.Get(id, nil, All)
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -38,8 +39,8 @@ func (rdb SQLiteArticleDatasource) Create(a *Article) (int, error) {
|
|||
return int(id), nil
|
||||
}
|
||||
|
||||
//List returns a slice of articles; if the user is not nil the number of articles for this explcit user is returned
|
||||
//the PublishedCritera specifies which articles should be considered
|
||||
// List returns a slice of articles; if the user is not nil the number of articles for this explcit user is returned
|
||||
// the PublishedCritera specifies which articles should be considered
|
||||
func (rdb SQLiteArticleDatasource) List(u *User, c *Category, p *Pagination, pc PublishedCriteria) ([]Article, error) {
|
||||
rows, err := selectArticlesStmt(rdb.SQLConn, u, c, p, pc)
|
||||
|
||||
|
@ -47,7 +48,11 @@ func (rdb SQLiteArticleDatasource) List(u *User, c *Category, p *Pagination, pc
|
|||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
logger.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
articles := []Article{}
|
||||
|
||||
|
@ -72,12 +77,12 @@ func (rdb SQLiteArticleDatasource) List(u *User, c *Category, p *Pagination, pc
|
|||
|
||||
}
|
||||
|
||||
//Count returns the number of article found; if the user is not nil the number of articles for this explcit user is returned
|
||||
//the PublishedCritera specifies which articles should be considered
|
||||
// Count returns the number of article found; if the user is not nil the number of articles for this explcit user is returned
|
||||
// the PublishedCritera specifies which articles should be considered
|
||||
func (rdb SQLiteArticleDatasource) Count(u *User, c *Category, pc PublishedCriteria) (int, error) {
|
||||
var total int
|
||||
var stmt strings.Builder
|
||||
var args []interface{}
|
||||
var stmt bytes.Buffer
|
||||
|
||||
stmt.WriteString("SELECT count(a.id) FROM article a ")
|
||||
|
||||
|
@ -116,8 +121,8 @@ func (rdb SQLiteArticleDatasource) Count(u *User, c *Category, pc PublishedCrite
|
|||
return total, nil
|
||||
}
|
||||
|
||||
//Get returns a article by its id; if the user is not nil the article for this explcit user is returned
|
||||
//the PublishedCritera specifies which articles should be considered
|
||||
// Get returns a article by its id; if the user is not nil the article for this explcit user is returned
|
||||
// the PublishedCritera specifies which articles should be considered
|
||||
func (rdb SQLiteArticleDatasource) Get(articleID int, u *User, pc PublishedCriteria) (*Article, error) {
|
||||
var a Article
|
||||
var ru User
|
||||
|
@ -132,8 +137,8 @@ func (rdb SQLiteArticleDatasource) Get(articleID int, u *User, pc PublishedCrite
|
|||
return &a, nil
|
||||
}
|
||||
|
||||
//GetBySlug returns a article by its slug; if the user is not nil the article for this explcit user is returned
|
||||
//the PublishedCritera specifies which articles should be considered
|
||||
// GetBySlug returns a article by its slug; if the user is not nil the article for this explcit user is returned
|
||||
// the PublishedCritera specifies which articles should be considered
|
||||
func (rdb SQLiteArticleDatasource) GetBySlug(slug string, u *User, pc PublishedCriteria) (*Article, error) {
|
||||
var a Article
|
||||
var ru User
|
||||
|
@ -183,7 +188,7 @@ func (rdb SQLiteArticleDatasource) Delete(articleID int) error {
|
|||
}
|
||||
|
||||
func selectArticleStmt(db *sql.DB, articleID int, slug string, u *User, pc PublishedCriteria) *sql.Row {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
|
||||
var args []interface{}
|
||||
|
||||
|
@ -224,7 +229,7 @@ func selectArticleStmt(db *sql.DB, articleID int, slug string, u *User, pc Publi
|
|||
}
|
||||
|
||||
func selectArticlesStmt(db *sql.DB, u *User, c *Category, p *Pagination, pc PublishedCriteria) (*sql.Rows, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
var args []interface{}
|
||||
|
||||
stmt.WriteString("SELECT a.id, a.headline, a.teaser, a.content, a.published, a.published_on, a.slug, a.last_modified, ")
|
||||
|
|
|
@ -52,12 +52,12 @@ type CategoryDatasourceService interface {
|
|||
Delete(categoryID int) error
|
||||
}
|
||||
|
||||
//CategoryService containing the service to access categories
|
||||
// CategoryService containing the service to access categories
|
||||
type CategoryService struct {
|
||||
Datasource CategoryDatasourceService
|
||||
}
|
||||
|
||||
//SlugEscape escapes the slug for use in URLs
|
||||
// SlugEscape escapes the slug for use in URLs
|
||||
func (c Category) SlugEscape() string {
|
||||
return url.PathEscape(c.Slug)
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ func (cs CategoryService) List(fc FilterCriteria) ([]Category, error) {
|
|||
return cs.Datasource.List(fc)
|
||||
}
|
||||
|
||||
//Create creates a category
|
||||
// Create creates a category
|
||||
func (cs CategoryService) Create(c *Category) (int, error) {
|
||||
for i := 0; i < 10; i++ {
|
||||
c.Slug = slug.CreateURLSafeSlug(c.Name, i)
|
||||
|
@ -122,7 +122,7 @@ func (cs CategoryService) Create(c *Category) (int, error) {
|
|||
return cid, nil
|
||||
}
|
||||
|
||||
//Update updates a category
|
||||
// Update updates a category
|
||||
func (cs CategoryService) Update(c *Category) error {
|
||||
if err := c.validate(); err != nil {
|
||||
return err
|
||||
|
@ -131,7 +131,7 @@ func (cs CategoryService) Update(c *Category) error {
|
|||
return cs.Datasource.Update(c)
|
||||
}
|
||||
|
||||
//Delete removes a category
|
||||
// Delete removes a category
|
||||
func (cs CategoryService) Delete(id int) error {
|
||||
c, err := cs.Datasource.Get(id, AllCategories)
|
||||
|
||||
|
|
|
@ -3,10 +3,12 @@ package models
|
|||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SQLiteArticleDatasource providing an implementation of ArticleDatasourceService for SQLite
|
||||
// SQLiteCategoryDatasource providing an implementation of CategoryDatasourceService for SQLite
|
||||
type SQLiteCategoryDatasource struct {
|
||||
SQLConn *sql.DB
|
||||
}
|
||||
|
@ -34,7 +36,7 @@ func (rdb SQLiteCategoryDatasource) Create(c *Category) (int, error) {
|
|||
|
||||
func (rdb SQLiteCategoryDatasource) List(fc FilterCriteria) ([]Category, error) {
|
||||
var args []interface{}
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
|
||||
stmt.WriteString("SELECT DISTINCT c.id, c.name, c.slug, c.last_modified, ")
|
||||
stmt.WriteString("u.id, u.display_name, u.username, u.email, u.is_admin ")
|
||||
|
@ -60,7 +62,11 @@ func (rdb SQLiteCategoryDatasource) List(fc FilterCriteria) ([]Category, error)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
logger.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
var cs []Category
|
||||
|
||||
|
@ -131,7 +137,7 @@ func (rdb SQLiteCategoryDatasource) Get(categoryID int, fc FilterCriteria) (*Cat
|
|||
}
|
||||
|
||||
func (rdb SQLiteCategoryDatasource) GetBySlug(slug string, fc FilterCriteria) (*Category, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
|
||||
stmt.WriteString("SELECT c.id, c.name, c.slug, c.last_modified, ")
|
||||
stmt.WriteString("u.id, u.display_name, u.username, u.email, u.is_admin ")
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
package models
|
||||
|
||||
// JSONData represents arbritary JSON data
|
||||
// JSONData represents arbitrary JSON data
|
||||
type JSONData struct {
|
||||
Data interface{} `json:"data,-" xml:"data,-"`
|
||||
}
|
||||
|
||||
// XMLData represents arbritary XML data
|
||||
// XMLData represents arbitrary XML data
|
||||
type XMLData struct {
|
||||
Data interface{} `xml:"data,-"`
|
||||
HexEncode bool `xml:"-"`
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/settings"
|
||||
)
|
||||
|
||||
//File represents a file
|
||||
// File represents a file
|
||||
type File struct {
|
||||
ID int
|
||||
UniqueName string `json:"unique_name"`
|
||||
|
@ -33,15 +33,15 @@ type File struct {
|
|||
Author *User
|
||||
}
|
||||
|
||||
//FileInfo contains Path, Name and Extension of a file.
|
||||
//Use SplitFilename to split the information from a filename
|
||||
// FileInfo contains Path, Name and Extension of a file.
|
||||
// Use SplitFilename to split the information from a filename
|
||||
type FileInfo struct {
|
||||
Path string
|
||||
Name string
|
||||
Extension string
|
||||
}
|
||||
|
||||
//FileDatasourceService defines an interface for CRUD operations of files
|
||||
// FileDatasourceService defines an interface for CRUD operations of files
|
||||
type FileDatasourceService interface {
|
||||
Create(f *File) (int, error)
|
||||
Get(fileID int, u *User) (*File, error)
|
||||
|
@ -100,26 +100,26 @@ func SplitFilename(filename string) FileInfo {
|
|||
}
|
||||
}
|
||||
|
||||
//FileService containing the service to interact with files
|
||||
// FileService containing the service to interact with files
|
||||
type FileService struct {
|
||||
Datasource FileDatasourceService
|
||||
Config settings.File
|
||||
}
|
||||
|
||||
//GetByID returns the file based on the fileID; it the user is given and it is a non admin
|
||||
//only file specific to this user is returned
|
||||
// GetByID returns the file based on the fileID; it the user is given and it is a non admin
|
||||
// only file specific to this user is returned
|
||||
func (fs FileService) GetByID(fileID int, u *User) (*File, error) {
|
||||
return fs.Datasource.Get(fileID, u)
|
||||
}
|
||||
|
||||
//GetByUniqueName returns the file based on the unique name; it the user is given and it is a non admin
|
||||
//only file specific to this user is returned
|
||||
// GetByUniqueName returns the file based on the unique name; it the user is given and it is a non admin
|
||||
// only file specific to this user is returned
|
||||
func (fs FileService) GetByUniqueName(uniqueName string, u *User) (*File, error) {
|
||||
return fs.Datasource.GetByUniqueName(uniqueName, u)
|
||||
}
|
||||
|
||||
//List returns a list of files based on the filename; it the user is given and it is a non admin
|
||||
//only files specific to this user are returned
|
||||
// List returns a list of files based on the filename; it the user is given and it is a non admin
|
||||
// only files specific to this user are returned
|
||||
func (fs FileService) List(u *User, p *Pagination) ([]File, error) {
|
||||
return fs.Datasource.List(u, p)
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ func (fs FileService) ToggleInline(fileID int, u *User) error {
|
|||
return fs.Datasource.Update(f)
|
||||
}
|
||||
|
||||
//Delete deletes a file based on fileID; users which are not the owner are not allowed to remove files; except admins
|
||||
// Delete deletes a file based on fileID; users which are not the owner are not allowed to remove files; except admins
|
||||
func (fs FileService) Delete(fileID int, u *User) error {
|
||||
file, err := fs.Datasource.Get(fileID, u)
|
||||
|
||||
|
@ -175,7 +175,7 @@ func (fs FileService) Delete(fileID int, u *User) error {
|
|||
return os.Remove(filepath.Join(fs.Config.Location, file.UniqueName))
|
||||
}
|
||||
|
||||
//Upload uploaded files will be saved at the configured file location, filename is saved in the database
|
||||
// Upload uploaded files will be saved at the configured file location, filename is saved in the database
|
||||
func (fs FileService) Upload(f *File) (int, error) {
|
||||
if err := f.validate(); err != nil {
|
||||
return -1, err
|
||||
|
@ -256,7 +256,7 @@ func isDot(r rune) bool {
|
|||
return '.' == r
|
||||
}
|
||||
|
||||
//SanitizeFilename sanitizes a filename for safe use when serving file
|
||||
// sanitizeFilename sanitizes a filename for safe use when serving file
|
||||
func sanitizeFilename(s string) string {
|
||||
s = strings.ToValidUTF8(s, "")
|
||||
s = strings.TrimFunc(s, unicode.IsSpace)
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//SQLiteFileDatasource providing an implementation of FileDatasourceService using MariaDB
|
||||
// SQLiteFileDatasource providing an implementation of FileDatasourceService using MariaDB
|
||||
type SQLiteFileDatasource struct {
|
||||
SQLConn *sql.DB
|
||||
}
|
||||
|
||||
//GetByFilename returns the file based on the filename; it the user is given and it is a non admin
|
||||
//only file specific to this user is returned
|
||||
// GetByUniqueName returns the file based on the unique filename; it the user is given and it is a non admin
|
||||
// only file specific to this user is returned
|
||||
func (rdb SQLiteFileDatasource) GetByUniqueName(uniqueName string, u *User) (*File, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
var args []interface{}
|
||||
|
||||
stmt.WriteString("SELECT f.id, f.filename, f.unique_name, f.content_type, f.inline, f.size, f.last_modified, f.user_id, ")
|
||||
|
@ -46,10 +47,10 @@ func (rdb SQLiteFileDatasource) GetByUniqueName(uniqueName string, u *User) (*Fi
|
|||
return &f, nil
|
||||
}
|
||||
|
||||
//Get returns the file based on the filename; it the user is given and it is a non admin
|
||||
//only file specific to this user is returned
|
||||
// Get returns the file based on the filename; it the user is given and it is a non admin
|
||||
// only file specific to this user is returned
|
||||
func (rdb SQLiteFileDatasource) Get(fileID int, u *User) (*File, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
var args []interface{}
|
||||
|
||||
stmt.WriteString("SELECT f.id, f.filename, f.unique_name, f.content_type, f.inline, f.size, f.last_modified, f.user_id, ")
|
||||
|
@ -81,7 +82,7 @@ func (rdb SQLiteFileDatasource) Get(fileID int, u *User) (*File, error) {
|
|||
return &f, nil
|
||||
}
|
||||
|
||||
//Create inserts some file meta information into the database
|
||||
// Create inserts some file meta information into the database
|
||||
func (rdb SQLiteFileDatasource) Create(f *File) (int, error) {
|
||||
res, err := rdb.SQLConn.Exec("INSERT INTO file (filename, unique_name, content_type, inline, size, last_modified, user_id) VALUES(?, ?, ?, ?, ?, ?, ?)",
|
||||
f.FullFilename, f.UniqueName, f.ContentType, f.Inline, f.Size, time.Now(), f.Author.ID)
|
||||
|
@ -107,10 +108,10 @@ func (rdb SQLiteFileDatasource) Update(f *File) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//List returns a list of files based on the filename; it the user is given and it is a non admin
|
||||
//only files specific to this user are returned
|
||||
// List returns a list of files based on the filename; it the user is given and it is a non admin
|
||||
// only files specific to this user are returned
|
||||
func (rdb SQLiteFileDatasource) List(u *User, p *Pagination) ([]File, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
|
||||
var args []interface{}
|
||||
|
||||
|
@ -140,7 +141,13 @@ func (rdb SQLiteFileDatasource) List(u *User, p *Pagination) ([]File, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
defer func() {
|
||||
err := rows.Close()
|
||||
|
||||
if err != nil {
|
||||
logger.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
var files []File
|
||||
var f File
|
||||
|
@ -165,10 +172,10 @@ func (rdb SQLiteFileDatasource) List(u *User, p *Pagination) ([]File, error) {
|
|||
|
||||
}
|
||||
|
||||
//Count returns a number of files based on the filename; it the user is given and it is a non admin
|
||||
//only files specific to this user are counted
|
||||
// Count returns a number of files based on the filename; it the user is given and it is a non admin
|
||||
// only files specific to this user are counted
|
||||
func (rdb SQLiteFileDatasource) Count(u *User) (int, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
|
||||
var args []interface{}
|
||||
|
||||
|
@ -190,8 +197,8 @@ func (rdb SQLiteFileDatasource) Count(u *User) (int, error) {
|
|||
return total, nil
|
||||
}
|
||||
|
||||
//Delete deletes a file based on fileID; users which are not the owner are not allowed to remove files;
|
||||
//except admins
|
||||
// Delete deletes a file based on fileID; users which are not the owner are not allowed to remove files;
|
||||
// except admins
|
||||
func (rdb SQLiteFileDatasource) Delete(fileID int) error {
|
||||
if _, err := rdb.SQLConn.Exec("DELETE FROM file WHERE id=?", fileID); err != nil {
|
||||
return err
|
||||
|
|
|
@ -13,15 +13,11 @@ import (
|
|||
bf "github.com/russross/blackfriday/v2"
|
||||
)
|
||||
|
||||
// Defines the extensions that are used
|
||||
// ext Defines the extensions that are used
|
||||
var ext = bf.NoIntraEmphasis | bf.Tables | bf.FencedCode | bf.Autolink |
|
||||
bf.Strikethrough | bf.SpaceHeadings | bf.BackslashLineBreak |
|
||||
bf.DefinitionLists | bf.Footnotes | bf.HardLineBreak
|
||||
|
||||
// Defines the HTML rendering flags that are used
|
||||
var flags = bf.UseXHTML | bf.Smartypants | bf.SmartypantsFractions |
|
||||
bf.SmartypantsDashes | bf.SmartypantsLatexDashes | bf.TOC
|
||||
|
||||
var p *bluemonday.Policy
|
||||
|
||||
func init() {
|
||||
|
@ -30,7 +26,7 @@ func init() {
|
|||
p.AllowAttrs("style").OnElements("span")
|
||||
}
|
||||
|
||||
//MarkdownToHTML sanitizes and parses markdown to HTML
|
||||
// MarkdownToHTML sanitizes and parses markdown to HTML
|
||||
func MarkdownToHTML(md []byte) []byte {
|
||||
md = bytes.Replace(md, []byte("\r\n"), []byte("\n"), -1)
|
||||
unsafe := bf.Run((md), bf.WithExtensions(ext))
|
||||
|
|
|
@ -15,33 +15,33 @@ type Mailer struct {
|
|||
func (m Mailer) SendActivationLink(ui *UserInvite) {
|
||||
activation := m.AppConfig.Domain + "/admin/activate-account/" + ui.Hash
|
||||
|
||||
mail := mail.Mail{
|
||||
ml := mail.Mail{
|
||||
To: ui.Email,
|
||||
Subject: "You got an invitation",
|
||||
Body: fmt.Sprintf("Hi %s,\n\n you are invited join %s. To activate your account click the following link and enter a password %s", ui.DisplayName, m.AppConfig.Title, activation),
|
||||
}
|
||||
|
||||
m.Sender.SendAsync(mail)
|
||||
m.Sender.SendAsync(ml)
|
||||
}
|
||||
|
||||
func (m Mailer) SendPasswordChangeConfirmation(u *User) {
|
||||
mail := mail.Mail{
|
||||
ml := mail.Mail{
|
||||
To: u.Email,
|
||||
Subject: "Password change",
|
||||
Body: fmt.Sprintf("Hi %s,\n\nyour password change was successful.", u.DisplayName),
|
||||
}
|
||||
|
||||
m.Sender.SendAsync(mail)
|
||||
m.Sender.SendAsync(ml)
|
||||
}
|
||||
|
||||
func (m Mailer) SendPasswordResetLink(u *User, t *Token) {
|
||||
resetLink := m.AppConfig.Domain + "/admin/reset-password/" + t.Hash
|
||||
|
||||
mail := mail.Mail{
|
||||
ml := mail.Mail{
|
||||
To: u.Email,
|
||||
Subject: "Changing password instructions",
|
||||
Body: fmt.Sprintf("Hi %s,\n\nuse the following link to reset your password:\n\n%s", u.DisplayName, resetLink),
|
||||
}
|
||||
|
||||
m.Sender.SendAsync(mail)
|
||||
m.Sender.SendAsync(ml)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
//Pagination type is used to provide a page selector
|
||||
// Pagination type is used to provide a page selector
|
||||
type Pagination struct {
|
||||
Total int
|
||||
Limit int
|
||||
|
@ -19,12 +19,12 @@ type Pagination struct {
|
|||
RelURL string
|
||||
}
|
||||
|
||||
//Offset returns the offset where to start
|
||||
// Offset returns the offset where to start
|
||||
func (p Pagination) Offset() int {
|
||||
return (p.CurrentPage - 1) * p.Limit
|
||||
}
|
||||
|
||||
//url returns the absolute url
|
||||
// url returns the absolute url
|
||||
func (p Pagination) url() string {
|
||||
if p.RelURL[0] == '/' {
|
||||
return p.RelURL
|
||||
|
@ -32,12 +32,12 @@ func (p Pagination) url() string {
|
|||
return "/" + p.RelURL
|
||||
}
|
||||
|
||||
//pages returns the amount of pages
|
||||
// pages returns the amount of pages
|
||||
func (p Pagination) pages() int {
|
||||
return int(math.Ceil(float64(p.Total) / float64(p.Limit)))
|
||||
}
|
||||
|
||||
//hasNext returns true if a next page is available
|
||||
// hasNext returns true if a next page is available
|
||||
func (p Pagination) hasNext() bool {
|
||||
if p.CurrentPage*p.Limit >= p.Total {
|
||||
return false
|
||||
|
@ -45,17 +45,17 @@ func (p Pagination) hasNext() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
//hasMoreThanOnePage returns true if the bar has more than one page
|
||||
// hasMoreThanOnePage returns true if the bar has more than one page
|
||||
func (p Pagination) hasMoreThanOnePage() bool {
|
||||
return p.Limit < p.Total
|
||||
}
|
||||
|
||||
//hasPrevious returns true if a previous page is available
|
||||
// hasPrevious returns true if a previous page is available
|
||||
func (p Pagination) hasPrevious() bool {
|
||||
return !(p.CurrentPage == 1)
|
||||
}
|
||||
|
||||
//nextPage returns the next page
|
||||
// nextPage returns the next page
|
||||
func (p Pagination) nextPage() int {
|
||||
if !p.hasNext() {
|
||||
return p.CurrentPage
|
||||
|
@ -63,7 +63,7 @@ func (p Pagination) nextPage() int {
|
|||
return p.CurrentPage + 1
|
||||
}
|
||||
|
||||
//previousPage returns the previous page
|
||||
// previousPage returns the previous page
|
||||
func (p Pagination) previousPage() int {
|
||||
if !p.hasPrevious() {
|
||||
return p.CurrentPage
|
||||
|
@ -71,7 +71,7 @@ func (p Pagination) previousPage() int {
|
|||
return p.CurrentPage - 1
|
||||
}
|
||||
|
||||
//PaginationBar returns the HTML for the pagination bar which can be embedded
|
||||
// PaginationBar returns the HTML for the pagination bar which can be embedded
|
||||
func (p Pagination) PaginationBar() template.HTML {
|
||||
var sb strings.Builder
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/slug"
|
||||
)
|
||||
|
||||
//SiteDatasourceService defines an interface for CRUD operations on sites
|
||||
// SiteDatasourceService defines an interface for CRUD operations on sites
|
||||
type SiteDatasourceService interface {
|
||||
Create(s *Site) (int, error)
|
||||
List(pc PublishedCriteria, p *Pagination) ([]Site, error)
|
||||
|
@ -25,17 +25,17 @@ type SiteDatasourceService interface {
|
|||
Count(pc PublishedCriteria) (int, error)
|
||||
}
|
||||
|
||||
//Direction type to distinct if a site should be moved up or down
|
||||
// Direction type to distinct if a site should be moved up or down
|
||||
type Direction int
|
||||
|
||||
const (
|
||||
//Up for moving the site one up
|
||||
// Up for moving the site one up
|
||||
Up = iota
|
||||
//Down for moving the site one down
|
||||
// Down for moving the site one down
|
||||
Down
|
||||
)
|
||||
|
||||
//Site represents a site
|
||||
// Site represents a site
|
||||
type Site struct {
|
||||
ID int
|
||||
Title string
|
||||
|
@ -114,17 +114,17 @@ func (s *Site) validate(ds SiteDatasourceService, changeLink bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//SiteService containing the service to access site
|
||||
// SiteService containing the service to access site
|
||||
type SiteService struct {
|
||||
Datasource SiteDatasourceService
|
||||
}
|
||||
|
||||
//List returns all sites
|
||||
// List returns all sites
|
||||
func (ss SiteService) List(pc PublishedCriteria, p *Pagination) ([]Site, error) {
|
||||
return ss.Datasource.List(pc, p)
|
||||
}
|
||||
|
||||
//Publish switches the publish state of the site
|
||||
// Publish switches the publish state of the site
|
||||
func (ss SiteService) Publish(siteID int) error {
|
||||
s, err := ss.Datasource.Get(siteID, All)
|
||||
|
||||
|
@ -141,7 +141,7 @@ func (ss SiteService) Publish(siteID int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//Create creates a site
|
||||
// Create creates a site
|
||||
func (ss SiteService) Create(s *Site) (int, error) {
|
||||
if err := s.validate(ss.Datasource, true); err != nil {
|
||||
return -1, err
|
||||
|
@ -160,12 +160,12 @@ func (ss SiteService) Create(s *Site) (int, error) {
|
|||
return ss.Datasource.Create(s)
|
||||
}
|
||||
|
||||
//Order reorder the site
|
||||
// Order reorder the site
|
||||
func (ss SiteService) Order(siteID int, dir Direction) error {
|
||||
return ss.Datasource.Order(siteID, dir)
|
||||
}
|
||||
|
||||
//Update updates a site
|
||||
// Update updates a site
|
||||
func (ss SiteService) Update(s *Site) error {
|
||||
oldSite, err := ss.GetByID(s.ID, All)
|
||||
|
||||
|
@ -187,7 +187,7 @@ func (ss SiteService) Update(s *Site) error {
|
|||
return ss.Datasource.Update(s)
|
||||
}
|
||||
|
||||
//Delete deletes a site
|
||||
// Delete deletes a site
|
||||
func (ss SiteService) Delete(siteID int) error {
|
||||
s, err := ss.GetByID(siteID, All)
|
||||
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
)
|
||||
|
||||
//SQLiteSiteDatasource providing an implementation of SiteDatasourceService for sqlite
|
||||
// SQLiteSiteDatasource providing an implementation of SiteDatasourceService for sqlite
|
||||
type SQLiteSiteDatasource struct {
|
||||
SQLConn *sql.DB
|
||||
}
|
||||
|
||||
//List returns a array of sites
|
||||
// List returns a array of sites
|
||||
func (rdb SQLiteSiteDatasource) List(pc PublishedCriteria, p *Pagination) ([]Site, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
var args []interface{}
|
||||
|
||||
stmt.WriteString("SELECT s.id, s.title, s.link, s.section, s.content, s.published, s.published_on, s.last_modified, s.order_no, u.id, u.display_name, u.email, u.username ")
|
||||
|
@ -44,7 +44,11 @@ func (rdb SQLiteSiteDatasource) List(pc PublishedCriteria, p *Pagination) ([]Sit
|
|||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
logger.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
var sites []Site
|
||||
var s Site
|
||||
|
@ -67,9 +71,9 @@ func (rdb SQLiteSiteDatasource) List(pc PublishedCriteria, p *Pagination) ([]Sit
|
|||
return sites, nil
|
||||
}
|
||||
|
||||
//Get returns a site based on the site id
|
||||
// Get returns a site based on the site id
|
||||
func (rdb SQLiteSiteDatasource) Get(siteID int, pc PublishedCriteria) (*Site, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
var args []interface{}
|
||||
|
||||
stmt.WriteString("SELECT s.id, s.title, s.link, s.section, s.content, s.published, s.published_on, s.last_modified, s.order_no, u.id, u.display_name, u.email, u.username FROM site as s ")
|
||||
|
@ -96,9 +100,9 @@ func (rdb SQLiteSiteDatasource) Get(siteID int, pc PublishedCriteria) (*Site, er
|
|||
return &s, nil
|
||||
}
|
||||
|
||||
//GetByLink returns a site based on the provided link
|
||||
// GetByLink returns a site based on the provided link
|
||||
func (rdb SQLiteSiteDatasource) GetByLink(link string, pc PublishedCriteria) (*Site, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
var args []interface{}
|
||||
|
||||
stmt.WriteString("SELECT s.id, s.title, s.link, s.section, s.content, s.published, s.published_on, s.order_no, s.last_modified, u.id, u.display_name, u.email, u.username FROM site as s ")
|
||||
|
@ -125,7 +129,7 @@ func (rdb SQLiteSiteDatasource) GetByLink(link string, pc PublishedCriteria) (*S
|
|||
return &s, nil
|
||||
}
|
||||
|
||||
//Publish publishes or unpublishes a site
|
||||
// Publish publishes or unpublishes a site
|
||||
func (rdb SQLiteSiteDatasource) Publish(s *Site) error {
|
||||
publishOn := NullTime{Valid: false}
|
||||
|
||||
|
@ -139,7 +143,7 @@ func (rdb SQLiteSiteDatasource) Publish(s *Site) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//Create creates a site
|
||||
// Create creates a site
|
||||
func (rdb SQLiteSiteDatasource) Create(s *Site) (int, error) {
|
||||
res, err := rdb.SQLConn.Exec("INSERT INTO site (title, link, section, content, published, published_on, last_modified, order_no, user_id) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
s.Title, s.Link, s.Section, s.Content, s.Published, s.PublishedOn, time.Now(), s.OrderNo, s.Author.ID)
|
||||
|
@ -157,7 +161,7 @@ func (rdb SQLiteSiteDatasource) Create(s *Site) (int, error) {
|
|||
return int(i), nil
|
||||
}
|
||||
|
||||
//Order moves a site up or down
|
||||
// Order moves a site up or down
|
||||
func (rdb SQLiteSiteDatasource) Order(id int, d Direction) error {
|
||||
tx, err := rdb.SQLConn.Begin()
|
||||
|
||||
|
@ -168,7 +172,12 @@ func (rdb SQLiteSiteDatasource) Order(id int, d Direction) error {
|
|||
defer func() {
|
||||
if err != nil {
|
||||
logger.Log.Error("error during ordering of sites ", err)
|
||||
tx.Rollback()
|
||||
|
||||
err := tx.Rollback()
|
||||
|
||||
if err != nil {
|
||||
logger.Log.Error("error during transaction rollback ", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -185,7 +194,9 @@ func (rdb SQLiteSiteDatasource) Order(id int, d Direction) error {
|
|||
} else if d == Down {
|
||||
var max int
|
||||
|
||||
tx.QueryRow("SELECT MAX(order_no) AS max FROM site").Scan(&max)
|
||||
if err := tx.QueryRow("SELECT MAX(order_no) AS max FROM site").Scan(&max); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = tx.Exec("UPDATE site "+
|
||||
"SET order_no=(SELECT order_no AS swap_el FROM site WHERE id=?) "+
|
||||
|
@ -210,7 +221,7 @@ func (rdb SQLiteSiteDatasource) Order(id int, d Direction) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//Update updates a site
|
||||
// Update updates a site
|
||||
func (rdb SQLiteSiteDatasource) Update(s *Site) error {
|
||||
if _, err := rdb.SQLConn.Exec("UPDATE site SET title=?, link=?, section=?, content=?, last_modified=? WHERE id=?", s.Title, s.Link, s.Section, s.Content, time.Now(), s.ID); err != nil {
|
||||
return err
|
||||
|
@ -219,9 +230,9 @@ func (rdb SQLiteSiteDatasource) Update(s *Site) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//Count returns the amount of sites
|
||||
// Count returns the amount of sites
|
||||
func (rdb SQLiteSiteDatasource) Count(pc PublishedCriteria) (int, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
|
||||
stmt.WriteString("SELECT count(id) FROM site ")
|
||||
|
||||
|
@ -240,7 +251,7 @@ func (rdb SQLiteSiteDatasource) Count(pc PublishedCriteria) (int, error) {
|
|||
return total, nil
|
||||
}
|
||||
|
||||
//Max returns the maximum order number
|
||||
// Max returns the maximum order number
|
||||
func (rdb SQLiteSiteDatasource) Max() (int, error) {
|
||||
var max sql.NullInt64
|
||||
|
||||
|
@ -255,7 +266,7 @@ func (rdb SQLiteSiteDatasource) Max() (int, error) {
|
|||
return int(max.Int64), nil
|
||||
}
|
||||
|
||||
//Delete deletes a site and updates the order numbers
|
||||
// Delete deletes a site and updates the order numbers
|
||||
func (rdb SQLiteSiteDatasource) Delete(s *Site) error {
|
||||
tx, err := rdb.SQLConn.Begin()
|
||||
|
||||
|
@ -265,8 +276,11 @@ func (rdb SQLiteSiteDatasource) Delete(s *Site) error {
|
|||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
logger.Log.Error("error during delete transaction", err)
|
||||
tx.Rollback()
|
||||
logger.Log.Errorf("error site removal not successful %v", err)
|
||||
if err := tx.Rollback(); err != nil {
|
||||
logger.Log.Errorf("could not rollback transaction during site removal %v", err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -5,15 +5,15 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
//AdminCriteria specifies which type of users should be considered
|
||||
// AdminCriteria specifies which type of users should be considered
|
||||
type AdminCriteria int
|
||||
|
||||
const (
|
||||
//OnlyAdmins conider only published
|
||||
// OnlyAdmins consider only admins
|
||||
OnlyAdmins = iota
|
||||
//NoAdmins conider no admins
|
||||
// NoAdmins consider no admins
|
||||
NoAdmins
|
||||
//AllUser conider all users
|
||||
// AllUser consider all users
|
||||
AllUser
|
||||
)
|
||||
|
||||
|
@ -21,15 +21,15 @@ const (
|
|||
type PublishedCriteria int
|
||||
|
||||
const (
|
||||
// OnlyPublished conider only published
|
||||
// OnlyPublished consider only published
|
||||
OnlyPublished = iota
|
||||
// NotPublished conider only not published
|
||||
// NotPublished consider only not published
|
||||
NotPublished
|
||||
// All conider both published and not published
|
||||
// All consider both published and not published
|
||||
All
|
||||
)
|
||||
|
||||
//NullTime represents a time which may not valid if time is null
|
||||
// NullTime represents a time which may not valid if time is null
|
||||
type NullTime struct {
|
||||
Time time.Time
|
||||
Valid bool
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
)
|
||||
|
||||
//TokenDatasourceService defines an interface for CRUD operations for tokens
|
||||
// TokenDatasourceService defines an interface for CRUD operations for tokens
|
||||
type TokenDatasourceService interface {
|
||||
Create(t *Token) (int, error)
|
||||
Get(hash string, tt TokenType) (*Token, error)
|
||||
|
@ -20,7 +20,7 @@ type TokenDatasourceService interface {
|
|||
Remove(hash string, tt TokenType) error
|
||||
}
|
||||
|
||||
//Token represents a token
|
||||
// Token represents a token
|
||||
type Token struct {
|
||||
ID int
|
||||
Hash string
|
||||
|
@ -31,13 +31,13 @@ type Token struct {
|
|||
}
|
||||
|
||||
const (
|
||||
//PasswordReset token generated for resetting passwords
|
||||
// PasswordReset token generated for resetting passwords
|
||||
PasswordReset = iota
|
||||
)
|
||||
|
||||
var types = [...]string{"password_reset"}
|
||||
|
||||
//TokenType specifies the type where token can be used
|
||||
// TokenType specifies the type where token can be used
|
||||
type TokenType int
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
|
@ -61,12 +61,12 @@ func (tt TokenType) String() string {
|
|||
return types[tt]
|
||||
}
|
||||
|
||||
//TokenService containing the service to access tokens
|
||||
// TokenService containing the service to access tokens
|
||||
type TokenService struct {
|
||||
Datasource TokenDatasourceService
|
||||
}
|
||||
|
||||
//Create creates a new token
|
||||
// Create creates a new token
|
||||
func (ts TokenService) Create(t *Token) error {
|
||||
t.Hash = crypt.RandomHash(32)
|
||||
|
||||
|
@ -77,8 +77,8 @@ func (ts TokenService) Create(t *Token) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//Get token for a defined token type expires after a defined time
|
||||
//Expired token will be removed
|
||||
// Get token for a defined token type expires after a defined time
|
||||
// Expired token will be removed
|
||||
func (ts TokenService) Get(hash string, tt TokenType, expireAfter time.Duration) (*Token, error) {
|
||||
token, err := ts.Datasource.Get(hash, tt)
|
||||
|
||||
|
@ -98,7 +98,7 @@ func (ts TokenService) Get(hash string, tt TokenType, expireAfter time.Duration)
|
|||
return token, nil
|
||||
}
|
||||
|
||||
//RateLimit returns an error if a token is requested greater three times in a time span of 15 minutes
|
||||
// RateLimit returns an error if a token is requested greater three times in a time span of 15 minutes
|
||||
func (ts TokenService) RateLimit(userID int, tt TokenType) error {
|
||||
tokens, err := ts.Datasource.ListByUser(userID, tt)
|
||||
|
||||
|
@ -122,7 +122,7 @@ func (ts TokenService) RateLimit(userID int, tt TokenType) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//Remove removes a token
|
||||
// Remove removes a token
|
||||
func (ts TokenService) Remove(hash string, tt TokenType) error {
|
||||
return ts.Datasource.Remove(hash, tt)
|
||||
}
|
||||
|
|
|
@ -2,15 +2,16 @@ package models
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
"time"
|
||||
)
|
||||
|
||||
//SQLiteTokenDatasource providing an implementation of TokenDatasourceService using MariaDB
|
||||
// SQLiteTokenDatasource providing an implementation of TokenDatasourceService using MariaDB
|
||||
type SQLiteTokenDatasource struct {
|
||||
SQLConn *sql.DB
|
||||
}
|
||||
|
||||
//Create creates a new token
|
||||
// Create creates a new token
|
||||
func (rdb SQLiteTokenDatasource) Create(t *Token) (int, error) {
|
||||
res, err := rdb.SQLConn.Exec("INSERT INTO token (hash, requested_at, token_type, user_id) VALUES(?, ?, ?, ?)",
|
||||
t.Hash, time.Now(), t.Type, t.Author.ID)
|
||||
|
@ -28,7 +29,7 @@ func (rdb SQLiteTokenDatasource) Create(t *Token) (int, error) {
|
|||
return int(i), nil
|
||||
}
|
||||
|
||||
//Get gets a token based on the hash and the token type
|
||||
// Get gets a token based on the hash and the token type
|
||||
func (rdb SQLiteTokenDatasource) Get(hash string, tt TokenType) (*Token, error) {
|
||||
var t Token
|
||||
var u User
|
||||
|
@ -43,7 +44,7 @@ func (rdb SQLiteTokenDatasource) Get(hash string, tt TokenType) (*Token, error)
|
|||
return &t, nil
|
||||
}
|
||||
|
||||
//ListByUser receives all tokens based on the user id and the token type ordered by requested
|
||||
// ListByUser receives all tokens based on the user id and the token type ordered by requested
|
||||
func (rdb SQLiteTokenDatasource) ListByUser(userID int, tt TokenType) ([]Token, error) {
|
||||
rows, err := rdb.SQLConn.Query("SELECT t.id, t.hash, t.requested_at, t.token_type, t.user_id FROM token as t WHERE t.user_id=? AND t.token_type=? ", userID, tt.String())
|
||||
|
||||
|
@ -51,7 +52,11 @@ func (rdb SQLiteTokenDatasource) ListByUser(userID int, tt TokenType) ([]Token,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
logger.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
tokens := []Token{}
|
||||
|
||||
|
@ -70,7 +75,7 @@ func (rdb SQLiteTokenDatasource) ListByUser(userID int, tt TokenType) ([]Token,
|
|||
return tokens, nil
|
||||
}
|
||||
|
||||
//Remove removes a token based on the hash
|
||||
// Remove removes a token based on the hash
|
||||
func (rdb SQLiteTokenDatasource) Remove(hash string, tt TokenType) error {
|
||||
if _, err := rdb.SQLConn.Exec("DELETE FROM token WHERE hash=? AND token_type=? ", hash, tt.String()); err != nil {
|
||||
return err
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
//UserDatasourceService defines an interface for CRUD operations for users
|
||||
// UserDatasourceService defines an interface for CRUD operations for users
|
||||
type UserDatasourceService interface {
|
||||
Create(u *User) (int, error)
|
||||
List(p *Pagination) ([]User, error)
|
||||
|
@ -31,7 +31,7 @@ type UserDatasourceService interface {
|
|||
Remove(userID int) error
|
||||
}
|
||||
|
||||
//User represents a user
|
||||
// User represents a user
|
||||
type User struct {
|
||||
ID int
|
||||
Username string
|
||||
|
@ -45,18 +45,14 @@ type User struct {
|
|||
IsAdmin bool
|
||||
}
|
||||
|
||||
const (
|
||||
bcryptRounds = 12
|
||||
)
|
||||
|
||||
//UserService containing the service to access users
|
||||
// UserService containing the service to access users
|
||||
type UserService struct {
|
||||
Datasource UserDatasourceService
|
||||
Config settings.User
|
||||
UserInterceptor UserInterceptor
|
||||
}
|
||||
|
||||
//UserInterceptor will be executed before and after updating/creating users
|
||||
// UserInterceptor will be executed before and after updating/creating users
|
||||
type UserInterceptor interface {
|
||||
PreCreate(user *User) error
|
||||
PostCreate(user *User) error
|
||||
|
@ -163,17 +159,17 @@ func (us UserService) duplicateUsername(username string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//Count returns the amount of users
|
||||
// Count returns the amount of users
|
||||
func (us UserService) Count(a AdminCriteria) (int, error) {
|
||||
return us.Datasource.Count(a)
|
||||
}
|
||||
|
||||
//List returns a list of users. Limits the amount based on the defined pagination
|
||||
// List returns a list of users. Limits the amount based on the defined pagination
|
||||
func (us UserService) List(p *Pagination) ([]User, error) {
|
||||
return us.Datasource.List(p)
|
||||
}
|
||||
|
||||
//GetByID gets the user based on the given id; will not contain the user password
|
||||
// GetByID gets the user based on the given id; will not contain the user password
|
||||
func (us UserService) GetByID(userID int) (*User, error) {
|
||||
u, err := us.Datasource.Get(userID)
|
||||
|
||||
|
@ -187,7 +183,7 @@ func (us UserService) GetByID(userID int) (*User, error) {
|
|||
return u, nil
|
||||
}
|
||||
|
||||
//GetByUsername gets the user based on the given username; will contain the user password
|
||||
// GetByUsername gets the user based on the given username; will contain the user password
|
||||
func (us UserService) GetByUsername(username string) (*User, error) {
|
||||
u, err := us.Datasource.GetByUsername(username)
|
||||
if err != nil {
|
||||
|
@ -200,7 +196,7 @@ func (us UserService) GetByUsername(username string) (*User, error) {
|
|||
return u, nil
|
||||
}
|
||||
|
||||
//GetByMail gets the user based on the given mail; will contain the user password
|
||||
// GetByMail gets the user based on the given mail; will contain the user password
|
||||
func (us UserService) GetByMail(mail string) (*User, error) {
|
||||
u, err := us.Datasource.GetByMail(mail)
|
||||
|
||||
|
@ -214,8 +210,8 @@ func (us UserService) GetByMail(mail string) (*User, error) {
|
|||
return u, nil
|
||||
}
|
||||
|
||||
//Create creates the user
|
||||
//If an UserInterceptor is available the action PreCreate is executed before creating and PostCreate after creating the user
|
||||
// Create creates the user
|
||||
// If an UserInterceptor is available the action PreCreate is executed before creating and PostCreate after creating the user
|
||||
func (us UserService) Create(u *User) (int, error) {
|
||||
if us.UserInterceptor != nil {
|
||||
if err := us.UserInterceptor.PreCreate(u); err != nil {
|
||||
|
@ -229,7 +225,7 @@ func (us UserService) Create(u *User) (int, error) {
|
|||
|
||||
salt := crypt.GenerateSalt()
|
||||
saltedPassword := append(u.PlainPassword[:], salt[:]...)
|
||||
password, err := crypt.CryptPassword([]byte(saltedPassword), bcryptRounds)
|
||||
password, err := crypt.CryptPassword([]byte(saltedPassword))
|
||||
|
||||
if err != nil {
|
||||
return -1, err
|
||||
|
@ -312,7 +308,7 @@ func (us UserService) Update(u *User, changePassword bool) error {
|
|||
if changePassword {
|
||||
salt := crypt.GenerateSalt()
|
||||
saltedPassword := append(u.PlainPassword[:], salt[:]...)
|
||||
password, err := crypt.CryptPassword([]byte(saltedPassword), bcryptRounds)
|
||||
password, err := crypt.CryptPassword([]byte(saltedPassword))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -417,7 +413,7 @@ func (us UserService) Remove(u *User) error {
|
|||
return err
|
||||
}
|
||||
|
||||
//OneAdmin returns true if there is only one admin
|
||||
// OneAdmin returns true if there is only one admin
|
||||
func (us UserService) OneAdmin() (bool, error) {
|
||||
c, err := us.Datasource.Count(OnlyAdmins)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"git.hoogi.eu/snafu/go-blog/mail"
|
||||
)
|
||||
|
||||
//UserInvite represents a new invited user
|
||||
// UserInvite represents a new invited user
|
||||
type UserInvite struct {
|
||||
ID int
|
||||
Hash string
|
||||
|
@ -29,7 +29,7 @@ func (ui UserInvite) Copy() *User {
|
|||
}
|
||||
}
|
||||
|
||||
//UserInviteDatasourceService defines an interface for CRUD operations for users
|
||||
// UserInviteDatasourceService defines an interface for CRUD operations for users
|
||||
type UserInviteDatasourceService interface {
|
||||
List() ([]UserInvite, error)
|
||||
Get(inviteID int) (*UserInvite, error)
|
||||
|
@ -39,7 +39,7 @@ type UserInviteDatasourceService interface {
|
|||
Remove(inviteID int) error
|
||||
}
|
||||
|
||||
//UserInviteService
|
||||
// UserInviteService
|
||||
type UserInviteService struct {
|
||||
Datasource UserInviteDatasourceService
|
||||
UserService UserService
|
||||
|
|
|
@ -1,37 +1,33 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
"time"
|
||||
)
|
||||
|
||||
//SQLiteUserInviteDatasource
|
||||
// SQLiteUserInviteDatasource
|
||||
type SQLiteUserInviteDatasource struct {
|
||||
SQLConn *sql.DB
|
||||
}
|
||||
|
||||
func (rdb SQLiteUserInviteDatasource) List() ([]UserInvite, error) {
|
||||
var stmt bytes.Buffer
|
||||
var args []interface{}
|
||||
var invites []UserInvite
|
||||
var ui UserInvite
|
||||
var u User
|
||||
|
||||
stmt.WriteString("SELECT ui.id, ui.username, ui.email, ui.display_name, ui.created_at, ui.is_admin, ")
|
||||
stmt.WriteString("u.id, u.username, u.email, u.display_name ")
|
||||
stmt.WriteString("FROM user_invite as ui ")
|
||||
stmt.WriteString("INNER JOIN user as u ")
|
||||
stmt.WriteString("ON u.id = ui.created_by ")
|
||||
stmt.WriteString("ORDER BY ui.username ASC ")
|
||||
|
||||
rows, err := rdb.SQLConn.Query(stmt.String(), args...)
|
||||
rows, err := rdb.SQLConn.Query("SELECT ui.id, ui.username, ui.email, ui.display_name, ui.created_at, ui.is_admin," +
|
||||
" u.id, u.username, u.email, u.display_name FROM user_invite as ui INNER JOIN user as u ON u.id = ui.created_by ORDER BY ui.username ASC")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
logger.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
for rows.Next() {
|
||||
if err = rows.Scan(&ui.ID, &ui.Username, &ui.Email, &ui.DisplayName, &ui.CreatedAt, &ui.IsAdmin, &u.ID, &u.Username, &u.Email, &u.DisplayName); err != nil {
|
||||
|
@ -95,7 +91,7 @@ func (rdb SQLiteUserInviteDatasource) Update(ui *UserInvite) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//Create creates an new user invitation
|
||||
// Create creates an new user invitation
|
||||
func (rdb SQLiteUserInviteDatasource) Create(ui *UserInvite) (int, error) {
|
||||
res, err := rdb.SQLConn.Exec("INSERT INTO user_invite (hash, username, email, display_name, is_admin, created_at, created_by) VALUES(?, ?, ?, ?, ?, ?, ?);",
|
||||
ui.Hash, ui.Username, ui.Email, ui.DisplayName, ui.IsAdmin, time.Now(), ui.CreatedBy.ID)
|
||||
|
@ -113,7 +109,7 @@ func (rdb SQLiteUserInviteDatasource) Create(ui *UserInvite) (int, error) {
|
|||
return int(i), nil
|
||||
}
|
||||
|
||||
//Count retuns the amount of users invitations
|
||||
// Count retuns the amount of users invitations
|
||||
func (rdb SQLiteUserInviteDatasource) Count() (int, error) {
|
||||
var total int
|
||||
|
||||
|
@ -124,7 +120,7 @@ func (rdb SQLiteUserInviteDatasource) Count() (int, error) {
|
|||
return total, nil
|
||||
}
|
||||
|
||||
//Removes an user invitation
|
||||
// Remove removes an user invitation
|
||||
func (rdb SQLiteUserInviteDatasource) Remove(inviteID int) error {
|
||||
if _, err := rdb.SQLConn.Exec("DELETE FROM user_invite WHERE id=?", inviteID); err != nil {
|
||||
return err
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"git.hoogi.eu/snafu/go-blog/logger"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//SQLiteUserDatasource providing an implementation of UserDatasourceService using SQLite
|
||||
// SQLiteUserDatasource providing an implementation of UserDatasourceService using SQLite
|
||||
type SQLiteUserDatasource struct {
|
||||
SQLConn *sql.DB
|
||||
}
|
||||
|
||||
//List returns a list of user
|
||||
// List returns a list of user
|
||||
func (rdb SQLiteUserDatasource) List(p *Pagination) ([]User, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
var args []interface{}
|
||||
var users []User
|
||||
var u User
|
||||
|
@ -31,7 +32,11 @@ func (rdb SQLiteUserDatasource) List(p *Pagination) ([]User, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
logger.Log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
for rows.Next() {
|
||||
if err = rows.Scan(&u.ID, &u.Username, &u.Email, &u.DisplayName, &u.LastModified, &u.Active, &u.IsAdmin); err != nil {
|
||||
|
@ -48,7 +53,7 @@ func (rdb SQLiteUserDatasource) List(p *Pagination) ([]User, error) {
|
|||
return users, nil
|
||||
}
|
||||
|
||||
//Get gets an user by his userID
|
||||
// Get gets an user by his userID
|
||||
func (rdb SQLiteUserDatasource) Get(userID int) (*User, error) {
|
||||
var u User
|
||||
|
||||
|
@ -62,7 +67,7 @@ func (rdb SQLiteUserDatasource) Get(userID int) (*User, error) {
|
|||
return &u, nil
|
||||
}
|
||||
|
||||
//GetByMail gets an user by his mail, includes the password and salt
|
||||
// GetByMail gets an user by his mail, includes the password and salt
|
||||
func (rdb SQLiteUserDatasource) GetByMail(mail string) (*User, error) {
|
||||
var u User
|
||||
|
||||
|
@ -73,7 +78,7 @@ func (rdb SQLiteUserDatasource) GetByMail(mail string) (*User, error) {
|
|||
return &u, nil
|
||||
}
|
||||
|
||||
//GetByUsername gets an user by his username, includes the password and salt
|
||||
// GetByUsername gets an user by his username, includes the password and salt
|
||||
func (rdb SQLiteUserDatasource) GetByUsername(username string) (*User, error) {
|
||||
var u User
|
||||
|
||||
|
@ -84,7 +89,7 @@ func (rdb SQLiteUserDatasource) GetByUsername(username string) (*User, error) {
|
|||
return &u, nil
|
||||
}
|
||||
|
||||
//Create creates an new user
|
||||
// Create creates an new user
|
||||
func (rdb SQLiteUserDatasource) Create(u *User) (int, error) {
|
||||
res, err := rdb.SQLConn.Exec("INSERT INTO user (salt, password, username, email, display_name, last_modified, active, is_admin) VALUES(?, ?, ?, ?, ?, ?, ?, ?);",
|
||||
u.Salt, u.Password, u.Username, u.Email, u.DisplayName, time.Now(), u.Active, u.IsAdmin)
|
||||
|
@ -101,9 +106,9 @@ func (rdb SQLiteUserDatasource) Create(u *User) (int, error) {
|
|||
return int(i), nil
|
||||
}
|
||||
|
||||
//Update updates an user
|
||||
// Update updates an user
|
||||
func (rdb SQLiteUserDatasource) Update(u *User, changePassword bool) error {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
var args []interface{}
|
||||
|
||||
stmt.WriteString("UPDATE user SET display_name=?, username=?, email=?, last_modified=?, active=?, is_admin=? ")
|
||||
|
@ -125,9 +130,9 @@ func (rdb SQLiteUserDatasource) Update(u *User, changePassword bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
//Count returns the amount of users matches the AdminCriteria
|
||||
// Count returns the amount of users matches the AdminCriteria
|
||||
func (rdb SQLiteUserDatasource) Count(ac AdminCriteria) (int, error) {
|
||||
var stmt bytes.Buffer
|
||||
var stmt strings.Builder
|
||||
stmt.WriteString("SELECT count(id) FROM user ")
|
||||
|
||||
if ac == OnlyAdmins {
|
||||
|
@ -145,7 +150,7 @@ func (rdb SQLiteUserDatasource) Count(ac AdminCriteria) (int, error) {
|
|||
return total, nil
|
||||
}
|
||||
|
||||
//Removes an user
|
||||
// Remove removes an user
|
||||
func (rdb SQLiteUserDatasource) Remove(userID int) error {
|
||||
if _, err := rdb.SQLConn.Exec("DELETE FROM user WHERE id=?", userID); err != nil {
|
||||
return err
|
||||
|
|
|
@ -18,13 +18,13 @@ import (
|
|||
"github.com/justinas/alice"
|
||||
)
|
||||
|
||||
//InitRoutes initializes restricted and public routes
|
||||
// InitRoutes initializes restricted and public routes
|
||||
func InitRoutes(ctx *m.AppContext, cfg *settings.Settings) *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
router = router.StrictSlash(false)
|
||||
sr := router.PathPrefix("/").Subrouter()
|
||||
|
||||
csrf :=
|
||||
rf :=
|
||||
csrf.Protect([]byte(cfg.CSRF.RandomKey),
|
||||
csrf.Secure(cfg.CSRF.CookieSecure),
|
||||
csrf.FieldName(cfg.CSRF.CookieName),
|
||||
|
@ -45,7 +45,7 @@ func InitRoutes(ctx *m.AppContext, cfg *settings.Settings) *mux.Router {
|
|||
|
||||
ar := router.PathPrefix("/admin").Subrouter()
|
||||
|
||||
restrictedChain := chain.Append(csrf).Append(ctx.AuthHandler)
|
||||
restrictedChain := chain.Append(rf).Append(ctx.AuthHandler)
|
||||
|
||||
restrictedRoutes(ctx, ar, restrictedChain)
|
||||
|
||||
|
@ -89,7 +89,7 @@ func fileLoggingHandler(accessLogPath string) (flh func(http.Handler) http.Handl
|
|||
}
|
||||
|
||||
func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain) {
|
||||
//article
|
||||
// article
|
||||
router.Handle("/articles", chain.Then(useTemplateHandler(ctx, handler.AdminListArticlesHandler))).Methods("GET")
|
||||
router.Handle("/articles/page/{page}", chain.Then(useTemplateHandler(ctx, handler.AdminListArticlesHandler))).Methods("GET")
|
||||
router.Handle("/article/new", chain.Then(useTemplateHandler(ctx, handler.AdminArticleNewHandler))).Methods("GET")
|
||||
|
@ -102,7 +102,7 @@ func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain)
|
|||
router.Handle("/article/delete/{articleID}", chain.Then(useTemplateHandler(ctx, handler.AdminArticleDeletePostHandler))).Methods("POST")
|
||||
router.Handle("/article/{articleID}", chain.Then(useTemplateHandler(ctx, handler.AdminPreviewArticleByIDHandler))).Methods("GET")
|
||||
|
||||
//user
|
||||
// user
|
||||
router.Handle("/user/profile", chain.Then(useTemplateHandler(ctx, handler.AdminProfileHandler))).Methods("GET")
|
||||
router.Handle("/user/profile", chain.Then(useTemplateHandler(ctx, handler.AdminProfilePostHandler))).Methods("POST")
|
||||
router.Handle("/users", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUsersHandler))).Methods("GET")
|
||||
|
@ -114,14 +114,14 @@ func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain)
|
|||
router.Handle("/user/delete/{userID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserDeleteHandler))).Methods("GET")
|
||||
router.Handle("/user/delete/{userID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserDeletePostHandler))).Methods("POST")
|
||||
|
||||
//user invites
|
||||
// user invites
|
||||
router.Handle("/user-invite/new", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteNewHandler))).Methods("GET")
|
||||
router.Handle("/user-invite/new", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteNewPostHandler))).Methods("POST")
|
||||
router.Handle("/user-invite/resend/{inviteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteResendPostHandler))).Methods("POST")
|
||||
router.Handle("/user-invite/delete/{inviteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteDeleteHandler))).Methods("GET")
|
||||
router.Handle("/user-invite/delete/{inviteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminUserInviteDeletePostHandler))).Methods("POST")
|
||||
|
||||
//site
|
||||
// site
|
||||
router.Handle("/sites", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminSitesHandler))).Methods("GET")
|
||||
router.Handle("/site/page/{page}", chain.Then(useTemplateHandler(ctx, handler.AdminSitesHandler))).Methods("GET")
|
||||
router.Handle("/site/new", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminSiteNewHandler))).Methods("GET")
|
||||
|
@ -135,7 +135,7 @@ func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain)
|
|||
router.Handle("/site/order/{siteID}", chain.Append(ctx.RequireAdmin).Then(useTemplateHandler(ctx, handler.AdminSiteOrderHandler))).Methods("POST")
|
||||
router.Handle("/site/{siteID:[0-9]+}}", chain.Then(useTemplateHandler(ctx, handler.AdminGetSiteHandler))).Methods("GET")
|
||||
|
||||
//article
|
||||
// article
|
||||
router.Handle("/categories", chain.Then(useTemplateHandler(ctx, handler.AdminListCategoriesHandler))).Methods("GET")
|
||||
router.Handle("/category/{categoryID:[0-9]+}}", chain.Then(useTemplateHandler(ctx, handler.AdminGetCategoryHandler))).Methods("POST")
|
||||
router.Handle("/category/new", chain.Then(useTemplateHandler(ctx, handler.AdminCategoryNewHandler))).Methods("GET")
|
||||
|
@ -145,7 +145,7 @@ func restrictedRoutes(ctx *m.AppContext, router *mux.Router, chain alice.Chain)
|
|||
router.Handle("/category/delete/{categoryID}", chain.Then(useTemplateHandler(ctx, handler.AdminCategoryDeleteHandler))).Methods("GET")
|
||||
router.Handle("/category/delete/{categoryID}", chain.Then(useTemplateHandler(ctx, handler.AdminCategoryDeletePostHandler))).Methods("POST")
|
||||
|
||||
//file
|
||||
// file
|
||||
router.Handle("/files", chain.Then(useTemplateHandler(ctx, handler.AdminListFilesHandler))).Methods("GET")
|
||||
router.Handle("/files/page/{page}", chain.Then(useTemplateHandler(ctx, handler.AdminListFilesHandler))).Methods("GET")
|
||||
router.Handle("/file/upload", chain.Then(useTemplateHandler(ctx, handler.AdminUploadFileHandler))).Methods("GET")
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//Package cfg parses and validates the configuration
|
||||
// Package settings parses and validates the configuration
|
||||
package settings
|
||||
|
||||
import (
|
||||
|
@ -55,7 +55,7 @@ func (afe *AllowedFileExts) Unmarshal(value string) error {
|
|||
|
||||
kv[trimmed] = trimmed
|
||||
|
||||
*afe = AllowedFileExts(kv)
|
||||
*afe = kv
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -183,7 +183,7 @@ func LoadConfig(filename string) (*Settings, error) {
|
|||
}
|
||||
|
||||
func (cfg *Settings) CheckConfig() error {
|
||||
//check log file is rw in production mode
|
||||
// check log file is rw in production mode
|
||||
if cfg.Environment != "dev" {
|
||||
if _, err := os.OpenFile(cfg.Log.File, os.O_RDONLY|os.O_CREATE, 0640); err != nil {
|
||||
return fmt.Errorf("config 'log_file': could not open log file %s error %v", cfg.Log.File, err)
|
||||
|
@ -258,7 +258,7 @@ func (cfg *Settings) CheckConfig() error {
|
|||
cfg.Application.Favicon = "assets/favicon.ico"
|
||||
}
|
||||
|
||||
//server settings
|
||||
// server settings
|
||||
if cfg.Server.UseTLS {
|
||||
if _, err := os.Open(cfg.Server.Cert); err != nil {
|
||||
return fmt.Errorf("config: could not open certificate %s error %v", cfg.Server.Cert, err)
|
||||
|
@ -285,7 +285,7 @@ func (cfg *Settings) GenerateCSRF() (bool, error) {
|
|||
var b []byte
|
||||
|
||||
if _, err := os.Stat(csrfTokenFilename); os.IsNotExist(err) {
|
||||
//create a random csrf token
|
||||
// create a random csrf token
|
||||
b = crypt.AlphaUpperLowerNumericSpecial.RandomSequence(32)
|
||||
|
||||
err := ioutil.WriteFile(csrfTokenFilename, b, 0640)
|
||||
|
@ -298,7 +298,7 @@ func (cfg *Settings) GenerateCSRF() (bool, error) {
|
|||
|
||||
return true, nil
|
||||
} else {
|
||||
//read existing csrf token
|
||||
// read existing csrf token
|
||||
b, err = ioutil.ReadFile(csrfTokenFilename)
|
||||
|
||||
if err != nil {
|
||||
|
|
16
slug/slug.go
16
slug/slug.go
|
@ -1,7 +1,6 @@
|
|||
package slug
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -10,7 +9,7 @@ import (
|
|||
|
||||
var multipleDashes = regexp.MustCompile(`[-]{2,}`)
|
||||
|
||||
//CreateURLSafeSlug creates a URL safe slug to use in URL
|
||||
// CreateURLSafeSlug creates a URL safe slug to use in URL
|
||||
func CreateURLSafeSlug(input string, suffix int) string {
|
||||
input = strings.Replace(input, "-", "", -1)
|
||||
|
||||
|
@ -35,16 +34,3 @@ func CreateURLSafeSlug(input string, suffix int) string {
|
|||
|
||||
return input
|
||||
}
|
||||
|
||||
func substitute(input string, subs map[rune]string) string {
|
||||
var b bytes.Buffer
|
||||
|
||||
for _, c := range input {
|
||||
if _, ok := subs[c]; ok {
|
||||
b.WriteString(subs[c])
|
||||
} else {
|
||||
b.WriteRune(c)
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue