diff options
| -rw-r--r-- | charakterin.go | 92 | ||||
| -rw-r--r-- | user.go | 45 |
2 files changed, 122 insertions, 15 deletions
diff --git a/charakterin.go b/charakterin.go index 415c94b..2878f1f 100644 --- a/charakterin.go +++ b/charakterin.go | |||
| @@ -3,13 +3,17 @@ package charakterin | |||
| 3 | import ( | 3 | import ( |
| 4 | "database/sql" | 4 | "database/sql" |
| 5 | "errors" | 5 | "errors" |
| 6 | "fmt" | ||
| 6 | "io/ioutil" | 7 | "io/ioutil" |
| 7 | "log" | 8 | "log" |
| 8 | "net/http" | 9 | "net/http" |
| 9 | "net/url" | 10 | "net/url" |
| 10 | "time" | ||
| 11 | "regexp" | 11 | "regexp" |
| 12 | "time" | ||
| 13 | |||
| 14 | "fagott.pw/goanilist" | ||
| 12 | 15 | ||
| 16 | "github.com/julienschmidt/httprouter" | ||
| 13 | _ "github.com/lib/pq" | 17 | _ "github.com/lib/pq" |
| 14 | ) | 18 | ) |
| 15 | 19 | ||
| @@ -22,12 +26,10 @@ const ( | |||
| 22 | 26 | ||
| 23 | // Renderer wird verwendet, um die Routen (bspw. Login-Route) zu rendern. Damit bleibt Charakterin selbst ohne Template. | 27 | // Renderer wird verwendet, um die Routen (bspw. Login-Route) zu rendern. Damit bleibt Charakterin selbst ohne Template. |
| 24 | type Renderer interface { | 28 | type Renderer interface { |
| 25 | // RenderLoginPage zeigt die Login-Seite an. | ||
| 26 | RenderLoginPage(w http.ResponseWriter, data map[string]interface{}) | 29 | RenderLoginPage(w http.ResponseWriter, data map[string]interface{}) |
| 27 | // RenderRegistrationPage zeigt die Registrations-Seite an. | ||
| 28 | RenderRegistrationPage(w http.ResponseWriter, data map[string]interface{}) | 30 | RenderRegistrationPage(w http.ResponseWriter, data map[string]interface{}) |
| 29 | // RenderUserSettingsPage zeigt die Seite für die Benutzereinstellungen an. | ||
| 30 | RenderUserSettingsPage(w http.ResponseWriter, data map[string]interface{}) | 31 | RenderUserSettingsPage(w http.ResponseWriter, data map[string]interface{}) |
| 32 | RenderAPICouplePage(w http.ResponseWriter, data map[string]interface{}) | ||
| 31 | } | 33 | } |
| 32 | 34 | ||
| 33 | // Charakterin ist das tolle Login- und Accountmanagementsystem. | 35 | // Charakterin ist das tolle Login- und Accountmanagementsystem. |
| @@ -35,6 +37,9 @@ type Charakterin struct { | |||
| 35 | renderer Renderer | 37 | renderer Renderer |
| 36 | FallbackRoute string | 38 | FallbackRoute string |
| 37 | Database *sql.DB | 39 | Database *sql.DB |
| 40 | |||
| 41 | anilistClientID string | ||
| 42 | anilistClientSecret string | ||
| 38 | } | 43 | } |
| 39 | 44 | ||
| 40 | var reEmail, _ = regexp.Compile(`(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,})`) | 45 | var reEmail, _ = regexp.Compile(`(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,})`) |
| @@ -47,9 +52,8 @@ func New(db *sql.DB) *Charakterin { | |||
| 47 | return nil | 52 | return nil |
| 48 | } | 53 | } |
| 49 | return &Charakterin{ | 54 | return &Charakterin{ |
| 50 | nil, | 55 | FallbackRoute: "/", |
| 51 | "/", | 56 | Database: db, |
| 52 | db, | ||
| 53 | } | 57 | } |
| 54 | } | 58 | } |
| 55 | 59 | ||
| @@ -58,6 +62,11 @@ func (c *Charakterin) UseRenderer(renderer Renderer) { | |||
| 58 | c.renderer = renderer | 62 | c.renderer = renderer |
| 59 | } | 63 | } |
| 60 | 64 | ||
| 65 | func (c *Charakterin) EnableAnilistAPI(id, secret string) { | ||
| 66 | c.anilistClientID = id | ||
| 67 | c.anilistClientSecret = secret | ||
| 68 | } | ||
| 69 | |||
| 61 | // DisplayLoginWithData rendert die Loginseite mit Daten (vorheriger Benutzer, Fehlermeldung) | 70 | // DisplayLoginWithData rendert die Loginseite mit Daten (vorheriger Benutzer, Fehlermeldung) |
| 62 | func (c *Charakterin) DisplayLoginWithData(w http.ResponseWriter, r *http.Request, data map[string]interface{}) { | 71 | func (c *Charakterin) DisplayLoginWithData(w http.ResponseWriter, r *http.Request, data map[string]interface{}) { |
| 63 | if c.IsLoggedIn(r) { | 72 | if c.IsLoggedIn(r) { |
| @@ -386,6 +395,44 @@ func (c *Charakterin) Register(w http.ResponseWriter, r *http.Request) { | |||
| 386 | http.Redirect(w, r, c.FallbackRoute, 302) | 395 | http.Redirect(w, r, c.FallbackRoute, 302) |
| 387 | } | 396 | } |
| 388 | 397 | ||
| 398 | func (c *Charakterin) DisplayAPICouplePage(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { | ||
| 399 | user, err := c.GetUserFromRequest(r) | ||
| 400 | if err != nil { | ||
| 401 | http.Error(w, "403", http.StatusForbidden) | ||
| 402 | return | ||
| 403 | } | ||
| 404 | data := make(map[string]interface{}) | ||
| 405 | data["user"] = user | ||
| 406 | data["name"] = ps.ByName("type") | ||
| 407 | c.renderer.RenderAPICouplePage(w, data) | ||
| 408 | } | ||
| 409 | |||
| 410 | func (c *Charakterin) CoupleAPI(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { | ||
| 411 | user, err := c.GetUserFromRequest(r) | ||
| 412 | if err != nil { | ||
| 413 | http.Error(w, "403", http.StatusForbidden) | ||
| 414 | return | ||
| 415 | } | ||
| 416 | body, err := readBody(r) | ||
| 417 | if err != nil { | ||
| 418 | http.Error(w, "400", http.StatusBadRequest) | ||
| 419 | return | ||
| 420 | } | ||
| 421 | switch ps.ByName("type") { | ||
| 422 | case "Anilist": | ||
| 423 | err = user.AnilistClient.CoupleByPin(body["code"][0]) | ||
| 424 | } | ||
| 425 | if err != nil { | ||
| 426 | data := make(map[string]interface{}) | ||
| 427 | data["user"] = user | ||
| 428 | data["name"] = ps.ByName("type") | ||
| 429 | data["error"] = err.Error() | ||
| 430 | c.renderer.RenderAPICouplePage(w, data) | ||
| 431 | return | ||
| 432 | } | ||
| 433 | http.Redirect(w, r, fmt.Sprintf("/user/%d", user.ID), 302) | ||
| 434 | } | ||
| 435 | |||
| 389 | func (c *Charakterin) GetUserFromRequest(r *http.Request) (*User, error) { | 436 | func (c *Charakterin) GetUserFromRequest(r *http.Request) (*User, error) { |
| 390 | cookie, err := r.Cookie("session") | 437 | cookie, err := r.Cookie("session") |
| 391 | if err != nil { | 438 | if err != nil { |
| @@ -404,14 +451,22 @@ func (c *Charakterin) GetUserFromRequest(r *http.Request) (*User, error) { | |||
| 404 | } | 451 | } |
| 405 | 452 | ||
| 406 | user := &User{ | 453 | user := &User{ |
| 407 | id, | 454 | ID: id, |
| 408 | name, | 455 | Name: name, |
| 409 | email, | 456 | EMail: email, |
| 410 | password, | 457 | Password: password, |
| 411 | displayName, | 458 | DisplayName: displayName, |
| 412 | lastActivity, | 459 | LastActivity: lastActivity, |
| 413 | isActive, | 460 | IsActive: isActive, |
| 414 | r.Header.Get("User-Agent"), | 461 | Agent: r.Header.Get("User-Agent"), |
| 462 | } | ||
| 463 | |||
| 464 | if c.anilistClientID != "" && c.anilistClientSecret != "" { | ||
| 465 | user.AnilistClient = goanilist.NewClient( | ||
| 466 | c.Database, | ||
| 467 | id, | ||
| 468 | c.anilistClientID, | ||
| 469 | c.anilistClientSecret) | ||
| 415 | } | 470 | } |
| 416 | 471 | ||
| 417 | return user, nil | 472 | return user, nil |
| @@ -424,6 +479,13 @@ func (c *Charakterin) GetUserByID(id int) (*User, error) { | |||
| 424 | if err != nil { | 479 | if err != nil { |
| 425 | return nil, err | 480 | return nil, err |
| 426 | } | 481 | } |
| 482 | if c.anilistClientID != "" && c.anilistClientSecret != "" { | ||
| 483 | user.AnilistClient = goanilist.NewClient( | ||
| 484 | c.Database, | ||
| 485 | id, | ||
| 486 | c.anilistClientID, | ||
| 487 | c.anilistClientSecret) | ||
| 488 | } | ||
| 427 | return user, nil | 489 | return user, nil |
| 428 | } | 490 | } |
| 429 | 491 | ||
| @@ -3,6 +3,8 @@ package charakterin | |||
| 3 | import ( | 3 | import ( |
| 4 | "database/sql" | 4 | "database/sql" |
| 5 | "time" | 5 | "time" |
| 6 | |||
| 7 | "fagott.pw/goanilist" | ||
| 6 | ) | 8 | ) |
| 7 | 9 | ||
| 8 | // Ein User ist ein ganz toller Benutzer. | 10 | // Ein User ist ein ganz toller Benutzer. |
| @@ -15,6 +17,9 @@ type User struct { | |||
| 15 | LastActivity *time.Time | 17 | LastActivity *time.Time |
| 16 | IsActive bool | 18 | IsActive bool |
| 17 | Agent string | 19 | Agent string |
| 20 | |||
| 21 | AnilistClient *goanilist.Client | ||
| 22 | externalServices []ExternalService | ||
| 18 | } | 23 | } |
| 19 | 24 | ||
| 20 | // GetName gibt den Anzeigenamen oder wenn dieser nicht gesetzt ist den Benutzernamen zurück. | 25 | // GetName gibt den Anzeigenamen oder wenn dieser nicht gesetzt ist den Benutzernamen zurück. |
| @@ -24,3 +29,43 @@ func (u *User) GetName() string { | |||
| 24 | } | 29 | } |
| 25 | return u.Name | 30 | return u.Name |
| 26 | } | 31 | } |
| 32 | |||
| 33 | func (u *User) HasExternalServices() bool { | ||
| 34 | return u.AnilistClient.IsCoupled | ||
| 35 | } | ||
| 36 | |||
| 37 | func (u *User) ExternalServices() []ExternalService { | ||
| 38 | if u.externalServices != nil { | ||
| 39 | return u.externalServices | ||
| 40 | } | ||
| 41 | ss := []ExternalService{} | ||
| 42 | if u.AnilistClient != nil { | ||
| 43 | s := ExternalService{ | ||
| 44 | Name: "Anilist", | ||
| 45 | IsEnabled: u.AnilistClient.IsCoupled, | ||
| 46 | AuthType: "copy-paste", | ||
| 47 | AuthorizeURL: u.AnilistClient.AuthorizeURL(), | ||
| 48 | CoupleURL: "/settings/api/Anilist/couple", | ||
| 49 | } | ||
| 50 | if u.AnilistClient.IsCoupled { | ||
| 51 | user, err := u.AnilistClient.User() | ||
| 52 | if err != nil { | ||
| 53 | s.UserName = err.Error() | ||
| 54 | } else { | ||
| 55 | s.UserName = user.DisplayName | ||
| 56 | } | ||
| 57 | } | ||
| 58 | ss = append(ss, s) | ||
| 59 | } | ||
| 60 | u.externalServices = ss | ||
| 61 | return ss | ||
| 62 | } | ||
| 63 | |||
| 64 | type ExternalService struct { | ||
| 65 | Name string | ||
| 66 | IsEnabled bool | ||
| 67 | AuthType string | ||
| 68 | AuthorizeURL string | ||
| 69 | CoupleURL string | ||
| 70 | UserName string | ||
| 71 | } | ||
