Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

API: Add Post API #256

Open
wants to merge 14 commits into
base: go
Choose a base branch
from
42 changes: 34 additions & 8 deletions arn/AnimeList.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,25 +103,39 @@ func (list *AnimeList) Find(animeID AnimeID) *AnimeListItem {

// Import adds an anime to the list if it hasn't been added yet
// and if it did exist it will update episode, rating and notes.
func (list *AnimeList) Import(item *AnimeListItem) {
func (list *AnimeList) Import(item *AnimeListItem) error {
existing := list.Find(item.AnimeID)
anime, err := GetAnime(item.AnimeID)

if err != nil {
return err
}

if anime.EpisodeCount < item.Episodes {
return errors.New("More episodes than possible, limit is: " + fmt.Sprint(anime.EpisodeCount))
}

// If it doesn't exist yet: Simply add it.
if existing == nil {
item.Created = DateTimeUTC()

list.Lock()
list.Items = append(list.Items, item)
list.Unlock()
return

existing = list.Find(item.AnimeID)
}

// Temporary save it before changing the status
// because status changes can modify the episode count.
// This will prevent loss of "episodes watched" data.
existingEpisodes := existing.Episodes

// Status
existing.Status = item.Status
existing.OnStatusChange()
// Status change in the case the user asks for it
if item.Status != "" {
existing.Status = item.Status
existing.OnStatusChange()
}

// Episodes
if item.Episodes > existingEpisodes {
Expand All @@ -133,12 +147,22 @@ func (list *AnimeList) Import(item *AnimeListItem) {
existing.OnEpisodesChange()

// Rating
if existing.Rating.Overall == 0 {
if item.Rating.Overall != 0 {
existing.Rating.Overall = item.Rating.Overall
existing.Rating.Clamp()
}
if item.Rating.Story != 0 {
existing.Rating.Story = item.Rating.Story
}
if item.Rating.Soundtrack != 0 {
existing.Rating.Soundtrack = item.Rating.Soundtrack
}
if item.Rating.Visuals != 0 {
existing.Rating.Soundtrack = item.Rating.Visuals
}

if existing.Notes == "" {
existing.Rating.Clamp()

if existing.Notes == "" || (existing.Notes != item.Notes && item.Notes != "") {
existing.Notes = item.Notes
}

Expand All @@ -148,6 +172,8 @@ func (list *AnimeList) Import(item *AnimeListItem) {

// Edited
existing.Edited = DateTimeUTC()

return nil
}

// User returns the user this anime list belongs to.
Expand Down
10 changes: 10 additions & 0 deletions arn/User.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/aerogo/aero"
"github.com/aerogo/http/client"
"github.com/akyoto/uuid"
"github.com/animenotifier/ffxiv"
"github.com/animenotifier/notify.moe/arn/autocorrect"
"github.com/animenotifier/notify.moe/arn/validate"
Expand Down Expand Up @@ -56,6 +57,7 @@ type User struct {
OS UserOS `json:"os" private:"true"`
Location *Location `json:"location" private:"true"`
FollowIDs []UserID `json:"follows"`
APIToken uuid.UUID `json:"apiToken" private:"true"`

hasPosts

Expand Down Expand Up @@ -137,6 +139,14 @@ func RegisterUser(user *User) {
}
}
}

// Create API Token
user.CreateAPIToken()
}

// (Re)create APIToken
func (user *User) CreateAPIToken() {
user.APIToken = uuid.New()
}

// SendNotification accepts a PushNotification and generates a new Notification object.
Expand Down
2 changes: 2 additions & 0 deletions arn/UserAPI.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/aerogo/api"
"github.com/aerogo/http/client"
"github.com/akyoto/color"
"github.com/akyoto/uuid"
"github.com/animenotifier/notify.moe/arn/autocorrect"
)

Expand Down Expand Up @@ -232,6 +233,7 @@ func (user *User) Filter() {
user.Location = &Location{}
user.Browser = UserBrowser{}
user.OS = UserOS{}
user.APIToken = uuid.UUID{}
}

// ShouldFilter tells whether data needs to be filtered in the given context.
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ require (
github.com/akyoto/hash v0.4.10
github.com/akyoto/imageserver v0.3.7
github.com/akyoto/stringutils v0.3.1
github.com/akyoto/uuid v1.1.3
github.com/akyoto/webpush-go v0.1.2
github.com/andybalholm/cascadia v1.2.0 // indirect
github.com/animenotifier/anilist v0.2.6
Expand All @@ -45,6 +46,7 @@ require (
github.com/go-chi/chi v4.1.2+incompatible // indirect
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/gomodule/oauth1 v0.0.0-20181215000758-9a59ed3b0a84
github.com/google/uuid v1.1.2 // indirect
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
github.com/itchyny/gojq v0.11.2
github.com/json-iterator/go v1.1.10
Expand All @@ -62,6 +64,7 @@ require (
github.com/smartystreets/assertions v1.2.0 // indirect
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf // indirect
github.com/tidwall/gjson v1.6.1
github.com/ungerik/go-gravatar v0.0.0-20120802094239-6ab22628222a
github.com/ventu-io/go-shortid v0.0.0-20171029131806-771a37caa5cf
github.com/xrash/smetrics v0.0.0-20200730060457-89a2a8a1fb0b
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201009210932-67992a1a5a35/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
Expand Down Expand Up @@ -451,6 +453,12 @@ github.com/tdewolff/test v1.0.0/go.mod h1:DiQUlutnqlEvdvhSn2LPGy4TFwRauAaYDsL+68
github.com/tdewolff/test v1.0.3/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA=
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0=
github.com/tidwall/gjson v1.6.1 h1:LRbvNuNuvAiISWg6gxLEFuCe72UKy5hDqhxW/8183ws=
github.com/tidwall/gjson v1.6.1/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0=
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/ungerik/go-gravatar v0.0.0-20120802094239-6ab22628222a h1:TZyMbJbyPL+4/ndyXns8aNDrmUJn5a6aV8lj3qEM7fM=
github.com/ungerik/go-gravatar v0.0.0-20120802094239-6ab22628222a/go.mod h1:cmQAsXze586z5DHYfoVO9jZBampncP3iuhVgujPqdxk=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
Expand Down
13 changes: 12 additions & 1 deletion pages/api/api.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package api

import (
"net/http"
"path"
"sort"

"github.com/aerogo/aero"
"github.com/akyoto/color"
"github.com/akyoto/uuid"
"github.com/animenotifier/notify.moe/arn"
"github.com/animenotifier/notify.moe/arn/autodocs"
"github.com/animenotifier/notify.moe/components"
Expand All @@ -14,6 +16,11 @@ import (
// Get api page.
func Get(ctx aero.Context) error {
types := []*autodocs.Type{}
user := arn.GetUserFromContext(ctx)

if user == nil {
return ctx.Error(http.StatusUnauthorized, "Not logged in")
}

for typeName := range arn.DB.Types() {
if typeName == "Session" {
Expand All @@ -33,5 +40,9 @@ func Get(ctx aero.Context) error {
return types[i].Name < types[j].Name
})

return ctx.HTML(components.API(types))
if (user.APIToken == uuid.UUID{}) {
user.CreateAPIToken()
}

return ctx.HTML(components.API(types, user))
}
5 changes: 3 additions & 2 deletions pages/api/api.pixy
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
component API(types []*autodocs.Type)
component API(types []*autodocs.Type, user *arn.User)
.api-docs
h1.mountable API
h2.mountable
InputText("APIToken", user.APIToken.String(), "API Token", "Your API token for notify.moe, keep it a secret!", 0)

h2.mountable Endpoints
ul
Expand Down
5 changes: 4 additions & 1 deletion pages/listimport/listimportanilist/anilist.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ func Finish(ctx aero.Context) error {
Edited: arn.DateTimeUTC(),
}

animeList.Import(item)
err := animeList.Import(item)
if err != nil {
return err
}
}

animeList.Save()
Expand Down
5 changes: 4 additions & 1 deletion pages/listimport/listimportkitsu/kitsu.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ func Finish(ctx aero.Context) error {
Edited: arn.DateTimeUTC(),
}

animeList.Import(item)
err := animeList.Import(item)
if err != nil {
return err
}
}

animeList.Save()
Expand Down
5 changes: 4 additions & 1 deletion pages/listimport/listimportmyanimelist/myanimelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ func Finish(ctx aero.Context) error {
Edited: arn.DateTimeUTC(),
}

animeList.Import(item)
err := animeList.Import(item)
if err != nil {
return err
}
}

animeList.Save()
Expand Down
4 changes: 4 additions & 0 deletions server/New.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/animenotifier/notify.moe/server/graphql"
"github.com/animenotifier/notify.moe/server/https"
"github.com/animenotifier/notify.moe/server/middleware"
"github.com/animenotifier/notify.moe/server/tokenapi"
"github.com/animenotifier/notify.moe/utils/htmlemail"
"github.com/animenotifier/notify.moe/utils/routetests"
)
Expand Down Expand Up @@ -74,6 +75,9 @@ func New() *aero.Application {
// GraphQL
graphql.Install(app)

// TokenAPI
tokenapi.Install(app)
AnnsAnns marked this conversation as resolved.
Show resolved Hide resolved

// Close the database node on shutdown
app.OnEnd(arn.Node.Close)

Expand Down
50 changes: 50 additions & 0 deletions server/tokenapi/AnimeList.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package tokenapi

import (
"errors"

"github.com/animenotifier/notify.moe/arn"
)

// AnimeUpdate parses animeListEntry.out of the JSON and then tries to integrate them into the database
func AnimeUpdate(request *TokenRequest) error {
animeListEntry := &arn.AnimeListItem{}
animeJSON := request.JSON.Get("anime")

animeListEntry.Status = animeJSON.Get("status").String()
animeListEntry.AnimeID = animeJSON.Get("id").String()
animeListEntry.Episodes = int(animeJSON.Get("episode").Int())
animeListEntry.Notes = animeJSON.Get("notes").String()
animeListEntry.RewatchCount = int(animeJSON.Get("rewatchCount").Int())
animeListEntry.Private = animeJSON.Get("isPrivate").Bool()

switch animeListEntry.Status {
case arn.AnimeListStatusWatching:
case arn.AnimeListStatusCompleted:
case arn.AnimeListStatusPlanned:
case arn.AnimeListStatusHold:
case arn.AnimeListStatusDropped:
break
default:
animeListEntry.Status = ""
}

if animeListEntry.AnimeID == "" {
return errors.New("No anime ID has been supplied")
}

rating := animeJSON.Get("ratings")
animeListEntry.Rating.Overall = rating.Get("overall").Float()
animeListEntry.Rating.Story = rating.Get("story").Float()
animeListEntry.Rating.Visuals = rating.Get("visuals").Float()
animeListEntry.Rating.Soundtrack = rating.Get("soundtrack").Float()

animeList := request.User.AnimeList()
err := animeList.Import(animeListEntry)

if err != nil {
return err
}

return nil
}
19 changes: 19 additions & 0 deletions server/tokenapi/DBUtils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package tokenapi

import (
"github.com/akyoto/uuid"
"github.com/animenotifier/notify.moe/arn"
)

// @TODO: Implement this in a better way, this might become a bottleneck in the future!
func GetUserFromToken(token uuid.UUID) *arn.User {
user := &arn.User{}

for user = range arn.StreamUsers() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could replace this O(n) loop with an O(1) lookup using a new collection in the DB ("TokenToUser") later on.

Otherwise this can become a huge bottleneck.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally wanted to implement this in a better way but I'm honestly too unfamiliar with nano so I didn't want to touch what I was unsure about.

if user.APIToken == token {
break
}
}

return user
}
18 changes: 18 additions & 0 deletions server/tokenapi/Install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package tokenapi

import (
"os"

"github.com/aerogo/aero"
"github.com/aerogo/log"
)

// Install installs all authentication routes in the application.
func Install(app *aero.Application) {
authLog := log.New()
authLog.AddWriter(os.Stdout)
authLog.AddWriter(log.File("logs/tokenapi.log"))

// Login
Main(app, authLog)
}
Loading