WIP
This commit is contained in:
		
							parent
							
								
									96b0c888ed
								
							
						
					
					
						commit
						bc3b437ebc
					
				
							
								
								
									
										132
									
								
								cmd/cmd.go
									
									
									
									
									
								
							
							
						
						
									
										132
									
								
								cmd/cmd.go
									
									
									
									
									
								
							| @ -1,13 +1,8 @@ | |||||||
| package cmd | package cmd | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|     "fmt" |  | ||||||
|     "errors" |  | ||||||
|     "reichard.io/imagini/routes" |     "reichard.io/imagini/routes" | ||||||
|     "reichard.io/imagini/internal/db" |     "reichard.io/imagini/internal/context" | ||||||
|     "reichard.io/imagini/internal/auth" |  | ||||||
|     "reichard.io/imagini/internal/models" |  | ||||||
|     "reichard.io/imagini/internal/config" |  | ||||||
| 
 | 
 | ||||||
|     "github.com/urfave/cli/v2" |     "github.com/urfave/cli/v2" | ||||||
|     "net/http" |     "net/http" | ||||||
| @ -21,67 +16,72 @@ var CmdServe = cli.Command{ | |||||||
|     Action:  serveWeb, |     Action:  serveWeb, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var CmdDBTest = cli.Command{ | // var CmdDBTest = cli.Command{ | ||||||
|     Name:    "test", | //     Name:    "test", | ||||||
|     Aliases: []string{"t"}, | //     Aliases: []string{"t"}, | ||||||
|     Usage:   "test db.", | //     Usage:   "test db.", | ||||||
|     Action:  testDatabase, | //     Action:  testDatabase, | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func serveWeb(ctx *cli.Context) error { |  | ||||||
|     log.Info("Serving Web") |  | ||||||
|     routes.RegisterRoutes() |  | ||||||
|     if err := http.ListenAndServe(":8080", nil); err != nil { |  | ||||||
|         log.Fatal(err) |  | ||||||
|     } |  | ||||||
|     return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func testDatabase(ctx *cli.Context) error { |  | ||||||
|     log.Info("Testing Database") |  | ||||||
|     c := config.NewConfig() |  | ||||||
|     db.ConnectDB(c) |  | ||||||
| 
 |  | ||||||
|     err := auth.CreateUser(models.User{ |  | ||||||
|         Username: "User12346", |  | ||||||
|         Email: "user26@evan.pub", |  | ||||||
|         FirstName: "User", |  | ||||||
|         LastName: "Reichard", |  | ||||||
|         AuthType: "Local", |  | ||||||
|     }, "myPassword123") |  | ||||||
| 
 |  | ||||||
|     if err != nil { |  | ||||||
|         fmt.Println(err) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     resp := auth.AuthenticateUser("User123", "myPassword123") |  | ||||||
|     if resp == true { |  | ||||||
|         log.Info("USER SUCCESSFULLY AUTHENTICATED BY USERNAME") |  | ||||||
|     }else { |  | ||||||
|         log.Info("USER NOT AUTHENTICATED") |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     resp = auth.AuthenticateUser("user@evan.pub", "myPassword123") |  | ||||||
|     if resp == true { |  | ||||||
|         log.Info("USER SUCCESSFULLY AUTHENTICATED BY EMAIL") |  | ||||||
|     }else { |  | ||||||
|         log.Info("USER NOT AUTHENTICATED") |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     resp = auth.AuthenticateUser("user@evan.pub", "myPassword12") |  | ||||||
|     if resp == true { |  | ||||||
|         log.Info("USER SUCCESSFULLY AUTHENTICATED BY EMAIL") |  | ||||||
|     }else { |  | ||||||
|         log.Info("USER NOT AUTHENTICATED") |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // foundUser, err := db.GetUser(db.User{Username: "User123"}) |  | ||||||
| 
 |  | ||||||
|     // if errors.Is(err, gorm.ErrRecordNotFound) { |  | ||||||
|     //     log.Warn("RECORD NOT FOUND") |  | ||||||
|     // } else { |  | ||||||
|     //     log.Info("FOUND USER", foundUser) |  | ||||||
| // } | // } | ||||||
| 
 | 
 | ||||||
|  | func serveWeb(cliCtx *cli.Context) error { | ||||||
|  |     log.Info("Serving Web") | ||||||
|  | 
 | ||||||
|  |     ctx := context.NewImaginiContext() | ||||||
|  |     routes.RegisterRoutes(ctx) | ||||||
|  |     //listener, _ := net.Listen("tcp", ctx.Config.ListenPort) | ||||||
|  | 
 | ||||||
|  |     if err := http.ListenAndServe(":" + ctx.Config.ListenPort, nil); err != nil { | ||||||
|  |         log.Fatal(err) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     return nil |     return nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // func testDatabase(cliCtx *cli.Context) error { | ||||||
|  | //     log.Info("Testing Database") | ||||||
|  | //     c := config.NewConfig() | ||||||
|  | //     db.ConnectDB(c) | ||||||
|  | //  | ||||||
|  | //     err := auth.CreateUser(models.User{ | ||||||
|  | //         Username: "User123", | ||||||
|  | //         Email: "user26@evan.pub", | ||||||
|  | //         FirstName: "User", | ||||||
|  | //         LastName: "Reichard", | ||||||
|  | //         AuthType: "Local", | ||||||
|  | //     }, "myPassword123") | ||||||
|  | //  | ||||||
|  | //     if err != nil { | ||||||
|  | //         fmt.Println(err) | ||||||
|  | //     } | ||||||
|  | //  | ||||||
|  | //     resp := auth.AuthenticateUser(models.APICredentials{User:"User123", Password: "myPassword123"}) | ||||||
|  | //     if resp == true { | ||||||
|  | //         log.Info("USER SUCCESSFULLY AUTHENTICATED BY USERNAME") | ||||||
|  | //     }else { | ||||||
|  | //         log.Info("USER NOT AUTHENTICATED") | ||||||
|  | //     } | ||||||
|  | //  | ||||||
|  | //     resp = auth.AuthenticateUser(models.APICredentials{User:"user26@evan.pub", Password: "myPassword123"}) | ||||||
|  | //     if resp == true { | ||||||
|  | //         log.Info("USER SUCCESSFULLY AUTHENTICATED BY EMAIL") | ||||||
|  | //     }else { | ||||||
|  | //         log.Info("USER NOT AUTHENTICATED") | ||||||
|  | //     } | ||||||
|  | //  | ||||||
|  | //     resp = auth.AuthenticateUser(models.APICredentials{User:"user@evan.pub", Password: "myPassword12"}) | ||||||
|  | //     if resp == true { | ||||||
|  | //         log.Info("USER SUCCESSFULLY AUTHENTICATED BY EMAIL") | ||||||
|  | //     }else { | ||||||
|  | //         log.Info("USER NOT AUTHENTICATED") | ||||||
|  | //     } | ||||||
|  | //  | ||||||
|  | //     // foundUser, err := db.GetUser(db.User{Username: "User123"}) | ||||||
|  | //  | ||||||
|  | //     // if errors.Is(err, gorm.ErrRecordNotFound) { | ||||||
|  | //     //     log.Warn("RECORD NOT FOUND") | ||||||
|  | //     // } else { | ||||||
|  | //     //     log.Info("FOUND USER", foundUser) | ||||||
|  | //     // } | ||||||
|  | //  | ||||||
|  | //     return nil | ||||||
|  | // } | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								imagini.db
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								imagini.db
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -3,20 +3,21 @@ package auth | |||||||
| import ( | import ( | ||||||
|     "errors" |     "errors" | ||||||
| 	"gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
|     "reichard.io/imagini/internal/db" |     "reichard.io/imagini/internal/query" | ||||||
|  |     "reichard.io/imagini/internal/models" | ||||||
|     log "github.com/sirupsen/logrus" |     log "github.com/sirupsen/logrus" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func AuthenticateUser(userIdentifier string, userPassword string) bool { | func AuthenticateUser(db *gorm.DB, creds models.APICredentials) bool { | ||||||
|     // By Username |     // By Username | ||||||
|     foundUser, err := db.GetUser(db.User{Username: userIdentifier}) |     foundUser, err := query.User(db, models.User{Username: creds.User}) | ||||||
|     if errors.Is(err, gorm.ErrRecordNotFound) { |     if errors.Is(err, gorm.ErrRecordNotFound) { | ||||||
|         foundUser, err = db.GetUser(db.User{Email: userIdentifier}) |         foundUser, err = query.User(db, models.User{Email: creds.User}) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Error Checking |     // Error Checking | ||||||
|     if errors.Is(err, gorm.ErrRecordNotFound) { |     if errors.Is(err, gorm.ErrRecordNotFound) { | ||||||
|         log.Warn("[auth] User not found: ", userIdentifier) |         log.Warn("[auth] User not found: ", creds.User) | ||||||
|         return false |         return false | ||||||
|     } else if err != nil { |     } else if err != nil { | ||||||
|         log.Error(err) |         log.Error(err) | ||||||
| @ -28,9 +29,9 @@ func AuthenticateUser(userIdentifier string, userPassword string) bool { | |||||||
|     // Determine Type |     // Determine Type | ||||||
|     switch foundUser.AuthType { |     switch foundUser.AuthType { | ||||||
|     case "Local": |     case "Local": | ||||||
|         return authenticateLocalUser(foundUser, userPassword) |         return authenticateLocalUser(foundUser, creds.Password) | ||||||
|     case "LDAP": |     case "LDAP": | ||||||
|         return authenticateLDAPUser(foundUser, userPassword) |         return authenticateLDAPUser(foundUser, creds.Password) | ||||||
|     default: |     default: | ||||||
|         return false |         return false | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,9 +1,9 @@ | |||||||
| package auth | package auth | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|     "reichard.io/imagini/internal/db" |     "reichard.io/imagini/internal/models" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func authenticateLDAPUser(user db.User, pw string) bool { | func authenticateLDAPUser(user models.User, pw string) bool { | ||||||
|     return false |     return false | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,23 +5,24 @@ import ( | |||||||
| 	"gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
|     "golang.org/x/crypto/bcrypt" |     "golang.org/x/crypto/bcrypt" | ||||||
|     log "github.com/sirupsen/logrus" |     log "github.com/sirupsen/logrus" | ||||||
|     "reichard.io/imagini/internal/db" |     "reichard.io/imagini/internal/query" | ||||||
|  |     "reichard.io/imagini/internal/models" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func authenticateLocalUser(user db.User, pw string) bool { | func authenticateLocalUser(user models.User, pw string) bool { | ||||||
|     bPassword :=[]byte(pw) |     bPassword :=[]byte(pw) | ||||||
|     err := bcrypt.CompareHashAndPassword([]byte(user.HashedPassword), bPassword) |     err := bcrypt.CompareHashAndPassword([]byte(user.HashedPassword), bPassword) | ||||||
|     if err == nil { |     if err == nil { | ||||||
|         log.Info("[local] Authentication successfull: ", user.Username) |         log.Info("[auth] Authentication successfull: ", user.Username) | ||||||
|         return true |         return true | ||||||
|     } |     } | ||||||
|     log.Warn("[local] Authentication failed: ", user.Username) |     log.Warn("[auth] Authentication failed: ", user.Username) | ||||||
|     return false |     return false | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func CreateUser(user db.User, pw string) error { | func CreateUser(db *gorm.DB, user models.User, pw string) error { | ||||||
|     log.Info("[local] Creating user: ", user.Username) |     log.Info("[auth] Creating user: ", user.Username) | ||||||
|     _, err := db.GetUser(user) |     _, err := query.User(db, user) | ||||||
|     if !errors.Is(err, gorm.ErrRecordNotFound) { |     if !errors.Is(err, gorm.ErrRecordNotFound) { | ||||||
|         log.Warn("[auth] User already exists: ", user.Username) |         log.Warn("[auth] User already exists: ", user.Username) | ||||||
|         return errors.New("User already exists") |         return errors.New("User already exists") | ||||||
| @ -33,5 +34,5 @@ func CreateUser(user db.User, pw string) error { | |||||||
|         return err |         return err | ||||||
|     } |     } | ||||||
|     user.HashedPassword = string(hashedPassword) |     user.HashedPassword = string(hashedPassword) | ||||||
|     return db.CreateUser(user) |     return query.CreateUser(db, user) | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ type Config struct { | |||||||
|     DataPath    string |     DataPath    string | ||||||
|     ConfigPath  string |     ConfigPath  string | ||||||
|     JWTSecret   string |     JWTSecret   string | ||||||
|  |     ListenPort  string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewConfig() *Config { | func NewConfig() *Config { | ||||||
| @ -21,6 +22,7 @@ func NewConfig() *Config { | |||||||
|         ConfigPath: getEnv("CONFIG_PATH",       "/config"), |         ConfigPath: getEnv("CONFIG_PATH",       "/config"), | ||||||
|         DataPath:   getEnv("DATA_PATH",         "/data"), |         DataPath:   getEnv("DATA_PATH",         "/data"), | ||||||
|         JWTSecret:  getEnv("JWT_SECRET",        "58b9340c0472cf045db226bc445966524e780cd38bc3dd707afce80c95d4de6f"), |         JWTSecret:  getEnv("JWT_SECRET",        "58b9340c0472cf045db226bc445966524e780cd38bc3dd707afce80c95d4de6f"), | ||||||
|  |         ListenPort: getEnv("LISTEN_PORT",       "8484"), | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										21
									
								
								internal/context/context.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								internal/context/context.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | package context | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"gorm.io/gorm" | ||||||
|  |     "reichard.io/imagini/internal/query" | ||||||
|  |     "reichard.io/imagini/internal/config" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type ImaginiContext struct { | ||||||
|  |     DB      *gorm.DB | ||||||
|  |     Config  *config.Config | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func NewImaginiContext() *ImaginiContext { | ||||||
|  |     c := config.NewConfig() | ||||||
|  |     gormDB := query.NewDB(c) | ||||||
|  |     return &ImaginiContext{ | ||||||
|  |         DB: gormDB, | ||||||
|  |         Config: c, | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								internal/models/api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								internal/models/api.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | package models | ||||||
|  | 
 | ||||||
|  | type APICredentials struct { | ||||||
|  |     User        string  `json:"user"` | ||||||
|  |     Password    string  `json:"password"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type APIMeta struct { | ||||||
|  |     Count   int     `json:"count"` | ||||||
|  |     Page    int     `json:"page"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type APIError struct { | ||||||
|  |     Message string  `json:"message"` | ||||||
|  |     Code    int     `json:"code"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type APIResponse struct { | ||||||
|  |     Data    []interface{}   `json:"data"` | ||||||
|  |     Meta    APIMeta         `json:"meta"` | ||||||
|  |     Error   APIError        `json:"error"` | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								internal/models/db.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								internal/models/db.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | package models | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  |     "gorm.io/gorm" | ||||||
|  |     "time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type ServerSetting struct { | ||||||
|  |     gorm.Model | ||||||
|  |     Name        string  `json:"name"` | ||||||
|  |     Description string  `json:"description"` | ||||||
|  |     Value       string  `json:"value"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type User struct { | ||||||
|  |     gorm.Model | ||||||
|  |     Email           string  `json:"email" gorm:"unique;not null"` | ||||||
|  |     Username        string  `json:"username" gorm:"unique;not null"` | ||||||
|  |     FirstName       string  `json:"first_name"` | ||||||
|  |     LastName        string  `json:"last_name"` | ||||||
|  |     AuthType        string  `json:"auth_type"` | ||||||
|  |     HashedPassword  string  `json:"hashed_password"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type MediaItem struct { | ||||||
|  |     gorm.Model | ||||||
|  |     User        User        `json:"user" gorm:"ForeignKey:ID"` | ||||||
|  |     EXIFDate    time.Time   `json:"exif_date"` | ||||||
|  |     Latitude    string      `json:"latitude"` | ||||||
|  |     Longitude   string      `json:"longitude"` | ||||||
|  |     MediaType   uint        `json:"media_type"` | ||||||
|  |     RelPath     string      `json:"rel_path"` | ||||||
|  |     Tags        []Tag       `json:"tags" gorm:"many2many:media_tags;"` | ||||||
|  |     Albums      []Album     `json:"albums" gorm:"many2many:media_albums;"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type Tag struct { | ||||||
|  |     gorm.Model | ||||||
|  |     Name        string  `json:"name"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type Album struct { | ||||||
|  |     gorm.Model | ||||||
|  |     Name        string  `json:"name"` | ||||||
|  | } | ||||||
| @ -1,45 +0,0 @@ | |||||||
| package models |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
|     "gorm.io/gorm" |  | ||||||
|     "time" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| type ServerSetting struct { |  | ||||||
|     gorm.Model |  | ||||||
|     Name        string |  | ||||||
|     Description string |  | ||||||
|     Value       string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type User struct { |  | ||||||
|     gorm.Model |  | ||||||
|     Email           string  `gorm:"unique;not null"` |  | ||||||
|     Username        string  `gorm:"unique;not null"` |  | ||||||
|     FirstName       string |  | ||||||
|     LastName        string |  | ||||||
|     AuthType        string |  | ||||||
|     HashedPassword  string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type MediaItem struct { |  | ||||||
|     gorm.Model |  | ||||||
|     User        User        `gorm:"ForeignKey:ID"` |  | ||||||
|     EXIFDate    time.Time |  | ||||||
|     Latitude    string |  | ||||||
|     Longitude   string |  | ||||||
|     MediaType   uint |  | ||||||
|     RelPath     string |  | ||||||
|     Tags        []Tag      `gorm:"many2many:media_tags;"` |  | ||||||
|     Albums      []Album    `gorm:"many2many:media_albums;"` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type Tag struct { |  | ||||||
|     gorm.Model |  | ||||||
|     Name        string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type Album struct { |  | ||||||
|     gorm.Model |  | ||||||
|     Name        string |  | ||||||
| } |  | ||||||
| @ -1,4 +1,4 @@ | |||||||
| package db | package query | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"log" | 	"log" | ||||||
| @ -13,13 +13,12 @@ import ( | |||||||
| 	"reichard.io/imagini/internal/models" | 	"reichard.io/imagini/internal/models" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var db *gorm.DB | func NewDB(c *config.Config) *gorm.DB { | ||||||
| 
 |  | ||||||
| func ConnectDB(c *config.Config) { |  | ||||||
|     gormConfig := &gorm.Config{ |     gormConfig := &gorm.Config{ | ||||||
|         PrepareStmt: true, |         PrepareStmt: true, | ||||||
|         Logger: logger.Default.LogMode(logger.Silent), |         Logger: logger.Default.LogMode(logger.Silent), | ||||||
|     } |     } | ||||||
|  |     var db *gorm.DB | ||||||
| 
 | 
 | ||||||
|     if c.DBType == "SQLite" { |     if c.DBType == "SQLite" { | ||||||
|         dbLocation := path.Join(c.ConfigPath, "imagini.db") |         dbLocation := path.Join(c.ConfigPath, "imagini.db") | ||||||
| @ -34,9 +33,10 @@ func ConnectDB(c *config.Config) { | |||||||
|     db.AutoMigrate(&models.MediaItem{}) |     db.AutoMigrate(&models.MediaItem{}) | ||||||
|     db.AutoMigrate(&models.Tag{}) |     db.AutoMigrate(&models.Tag{}) | ||||||
|     db.AutoMigrate(&models.Album{}) |     db.AutoMigrate(&models.Album{}) | ||||||
|  |     return db | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func ItemsFromAlbum(user models.User, album models.Album) []models.MediaItem { | func ItemsFromAlbum(db *gorm.DB, user models.User, album models.Album) []models.MediaItem { | ||||||
|     var mediaItems []models.MediaItem |     var mediaItems []models.MediaItem | ||||||
|     // db.Table("media_albums"). |     // db.Table("media_albums"). | ||||||
|     //     Select("media_item.*"). |     //     Select("media_item.*"). | ||||||
| @ -1,4 +1,4 @@ | |||||||
| package db | package query | ||||||
| 
 | 
 | ||||||
| import "errors" | import "errors" | ||||||
| 
 | 
 | ||||||
| @ -1,15 +1,16 @@ | |||||||
| package db | package query | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"gorm.io/gorm" | ||||||
| 	"reichard.io/imagini/internal/models" | 	"reichard.io/imagini/internal/models" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func CreateUser (user models.User) error { | func CreateUser (db *gorm.DB, user models.User) error { | ||||||
|     err := db.Create(&user).Error |     err := db.Create(&user).Error | ||||||
|     return err |     return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func User (user models.User) (models.User, error) { | func User (db *gorm.DB, user models.User) (models.User, error) { | ||||||
|     var foundUser models.User |     var foundUser models.User | ||||||
|     var count int64 |     var count int64 | ||||||
|     err := db.Where(&user).First(&foundUser).Count(&count).Error |     err := db.Where(&user).First(&foundUser).Count(&count).Error | ||||||
							
								
								
									
										2
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.go
									
									
									
									
									
								
							| @ -30,7 +30,7 @@ func main() { | |||||||
|         Usage: "A self hosted photo library.", |         Usage: "A self hosted photo library.", | ||||||
|         Commands: []*cli.Command{ |         Commands: []*cli.Command{ | ||||||
|             &cmd.CmdServe, |             &cmd.CmdServe, | ||||||
|             &cmd.CmdDBTest, | //            &cmd.CmdDBTest, | ||||||
|         }, |         }, | ||||||
|     } |     } | ||||||
|     err := app.Run(os.Args) |     err := app.Run(os.Args) | ||||||
|  | |||||||
| @ -4,6 +4,6 @@ import ( | |||||||
|     "net/http" |     "net/http" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func albumsHandler(w http.ResponseWriter, r *http.Request) { | func (ctx *ImaginiContext) albumsHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,13 +1,70 @@ | |||||||
| package routes | package routes | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  |     "time" | ||||||
|  |     "encoding/json" | ||||||
|     "net/http" |     "net/http" | ||||||
|  | 
 | ||||||
|  |     "reichard.io/imagini/internal/auth" | ||||||
|  |     "reichard.io/imagini/internal/models" | ||||||
|  |     // log "github.com/sirupsen/logrus" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func loginHandler(w http.ResponseWriter, r *http.Request) { | func (ctx *ImaginiContext) loginHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 
 |     if r.Method != http.MethodPost { | ||||||
|  |         JSONError(w, "Method is not supported.", http.StatusMethodNotAllowed) | ||||||
|  |         return | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| func logoutHandler(w http.ResponseWriter, r *http.Request) { |     // Decode into Struct | ||||||
| 
 |     var creds models.APICredentials | ||||||
|  |     err := json.NewDecoder(r.Body).Decode(&creds) | ||||||
|  |     if err != nil { | ||||||
|  |         JSONError(w, "Invalid parameters.", http.StatusBadRequest) | ||||||
|  |         return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Validate | ||||||
|  |     if creds.User == "" || creds.Password == "" { | ||||||
|  |         JSONError(w, "Invalid parameters.", http.StatusBadRequest) | ||||||
|  |         return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // TODO: Is user already logged in? If so refresh token, if different user, kill session and log in new user? | ||||||
|  | 
 | ||||||
|  |     // Do login | ||||||
|  |     resp := auth.AuthenticateUser(ctx.DB, creds) | ||||||
|  |     if resp == true { | ||||||
|  |         // Return Success | ||||||
|  |         cookie := http.Cookie{ | ||||||
|  |             Name:   "Token", | ||||||
|  |             Value:  "testToken", | ||||||
|  |         } | ||||||
|  |         http.SetCookie(w, &cookie) | ||||||
|  |         JSONSuccess(w, "Login success.", http.StatusOK) | ||||||
|  |     }else { | ||||||
|  |         // Return Failure | ||||||
|  |         JSONError(w, "Invalid credentials.", http.StatusUnauthorized) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (ctx *ImaginiContext) logoutHandler(w http.ResponseWriter, r *http.Request) { | ||||||
|  |     if r.Method != http.MethodPost { | ||||||
|  |         http.Error(w, "Method is not supported.", http.StatusMethodNotAllowed) | ||||||
|  |         return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Do logout | ||||||
|  | 
 | ||||||
|  |     // TODO: Clear Session Server Side | ||||||
|  | 
 | ||||||
|  |     // Tell Client to Expire Token | ||||||
|  |     cookie := &http.Cookie{ | ||||||
|  |         Name:       "Token", | ||||||
|  |         Value:      "", | ||||||
|  |         Path:       "/", | ||||||
|  |         Expires:    time.Unix(0, 0), | ||||||
|  |         HttpOnly:   true, | ||||||
|  |     } | ||||||
|  |     http.SetCookie(w, cookie) | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,6 +4,6 @@ import ( | |||||||
|     "net/http" |     "net/http" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func infoHandler(w http.ResponseWriter, r *http.Request) { | func (ctx *ImaginiContext) infoHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,6 +4,6 @@ import ( | |||||||
|     "net/http" |     "net/http" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func mediaItemsHandler(w http.ResponseWriter, r *http.Request) { | func (ctx *ImaginiContext) mediaItemsHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,25 +1,57 @@ | |||||||
| package routes | package routes | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  |     "encoding/json" | ||||||
|     "net/http" |     "net/http" | ||||||
|  |     "reichard.io/imagini/internal/context" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func RegisterRoutes() { | type ImaginiContext struct { | ||||||
|     http.HandleFunc("/MediaItems", mediaItemsHandler) |     *context.ImaginiContext | ||||||
|     http.HandleFunc("/Upload",     uploadHandler) |  | ||||||
|     http.HandleFunc("/Albums",     albumsHandler) |  | ||||||
|     http.HandleFunc("/Logout",     logoutHandler) |  | ||||||
|     http.HandleFunc("/Login",      loginHandler) |  | ||||||
|     http.HandleFunc("/Users",      usersHandler) |  | ||||||
|     http.HandleFunc("/Tags",       tagsHandler) |  | ||||||
|     http.HandleFunc("/Info",       infoHandler) |  | ||||||
|     http.HandleFunc("/Me",         meHandler) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|     // Examples: | func RegisterRoutes(cctx *context.ImaginiContext) { | ||||||
|     //  [POST] /Login { user: <USER_OR_EMAIL>, password: <PASSWORD> } |     ctx := &ImaginiContext{cctx} | ||||||
|     //  [POST] /Logout |     http.HandleFunc("/MediaItems", ctx.mediaItemsHandler) | ||||||
|     //  [GET]  /MediaItems |     http.HandleFunc("/Upload",     ctx.uploadHandler) | ||||||
|  |     http.HandleFunc("/Albums",     ctx.albumsHandler) | ||||||
|  |     http.HandleFunc("/Logout",     ctx.logoutHandler) | ||||||
|  |     http.HandleFunc("/Login",      ctx.loginHandler) | ||||||
|  |     http.HandleFunc("/Users",      ctx.usersHandler) | ||||||
|  |     http.HandleFunc("/Tags",       ctx.tagsHandler) | ||||||
|  |     http.HandleFunc("/Info",       ctx.infoHandler) | ||||||
|  |     http.HandleFunc("/Me",         ctx.meHandler) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // https://stackoverflow.com/a/59764037 | ||||||
|  | func JSONError(w http.ResponseWriter, err string, code int) { | ||||||
|  |     w.Header().Set("Content-Type", "application/json; charset=utf-8") | ||||||
|  |     w.Header().Set("X-Content-Type-Options", "nosniff") | ||||||
|  |     w.WriteHeader(code) | ||||||
|  |     json.NewEncoder(w).Encode(map[string]interface{}{"error": err}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func JSONSuccess(w http.ResponseWriter, msg string, code int) { | ||||||
|  |     w.Header().Set("Content-Type", "application/json; charset=utf-8") | ||||||
|  |     w.Header().Set("X-Content-Type-Options", "nosniff") | ||||||
|  |     w.WriteHeader(code) | ||||||
|  |     json.NewEncoder(w).Encode(map[string]interface{}{"success": msg}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // METHOD: | ||||||
|  | //    switch r.Method { | ||||||
|  | //    case http.MethodGet: | ||||||
|  | //        // Serve the resource. | ||||||
|  | //    case http.MethodPost: | ||||||
|  | //        // Create a new record. | ||||||
|  | //    case http.MethodPut: | ||||||
|  | //        // Update an existing record. | ||||||
|  | //    case http.MethodDelete: | ||||||
|  | //        // Remove the record. | ||||||
|  | //    default: | ||||||
|  | //        // Give an error message. | ||||||
|  | //    } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| // commonMiddleware := []Middleware{ | // commonMiddleware := []Middleware{ | ||||||
| //   logMiddleware, | //   logMiddleware, | ||||||
| @ -45,16 +77,6 @@ func RegisterRoutes() { | |||||||
| //  query := r.URL.Query() | //  query := r.URL.Query() | ||||||
| //  filters, present := query["filters"] | //  filters, present := query["filters"] | ||||||
| 
 | 
 | ||||||
| // HTTP Errors |  | ||||||
| //  if r.Method != "GET" { |  | ||||||
| //      http.Error(w, "Method is not supported.", http.StatusNotFound) |  | ||||||
| //      return |  | ||||||
| //  } |  | ||||||
| //  if r.URL.Path != "/hello" { |  | ||||||
| //      http.Error(w, "404 not found.", http.StatusNotFound) |  | ||||||
| //      return |  | ||||||
| //  } |  | ||||||
| 
 |  | ||||||
| // func uploadsHandler() http.Handler { | // func uploadsHandler() http.Handler { | ||||||
| //     store := filestore.FileStore{ | //     store := filestore.FileStore{ | ||||||
| // 		Path: "./Uploads", | // 		Path: "./Uploads", | ||||||
|  | |||||||
| @ -4,6 +4,6 @@ import ( | |||||||
|     "net/http" |     "net/http" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func tagsHandler(w http.ResponseWriter, r *http.Request) { | func (ctx *ImaginiContext) tagsHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,6 +4,6 @@ import ( | |||||||
|     "net/http" |     "net/http" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func uploadHandler(w http.ResponseWriter, r *http.Request) { | func (ctx *ImaginiContext) uploadHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,12 +2,38 @@ package routes | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|     "net/http" |     "net/http" | ||||||
|  |     log "github.com/sirupsen/logrus" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func usersHandler(w http.ResponseWriter, r *http.Request) { | func (ctx *ImaginiContext) usersHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 
 |     if r.Method == http.MethodPost { | ||||||
|  |         // CREATE | ||||||
|  |     } else if r.Method == http.MethodPut { | ||||||
|  |         // UPDATE / REPLACE | ||||||
|  |     } else if r.Method == http.MethodPatch { | ||||||
|  |         // UPDATE / MODIFY | ||||||
|  |     } else if r.Method == http.MethodDelete { | ||||||
|  |         // DELETE | ||||||
|  |     } else if r.Method == http.MethodGet { | ||||||
|  |         // GET | ||||||
|  |     } else { | ||||||
|  |         JSONError(w, "Method is not supported.", http.StatusMethodNotAllowed) | ||||||
|  |         return | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func meHandler(w http.ResponseWriter, r *http.Request) { | func (ctx *ImaginiContext) meHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 
 |     if r.Method != http.MethodGet { | ||||||
|  |         JSONError(w, "Method is not supported.", http.StatusMethodNotAllowed) | ||||||
|  |         return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Get Authenticated User & Return Object | ||||||
|  |     authCookie, err := r.Cookie("Token") | ||||||
|  |     if err != nil { | ||||||
|  |         log.Error("[routes] ", err) | ||||||
|  |         return | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     log.Info("[routes] INFO: ", authCookie) | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user