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 | } | ||