diff --git a/audon-fe/src/views/LoginView.vue b/audon-fe/src/views/LoginView.vue index 96854bf..0d47611 100644 --- a/audon-fe/src/views/LoginView.vue +++ b/audon-fe/src/views/LoginView.vue @@ -15,6 +15,7 @@ export default { data() { return { server: "", + serverErr: "", }; }, validations() { @@ -31,7 +32,11 @@ export default { computed: { serverErrors() { const errors = this.v$.server.$errors; - return _.map(errors, (e) => e.$message); + const messages = _.map(errors, (e) => e.$message); + if (this.serverErr !== "") { + messages.push(this.serverErr); + } + return messages; }, }, methods: { @@ -40,12 +45,25 @@ export default { if (!isFormCorrect) { return; } - const response = await axios.postForm("/api/login", { server: this.server }); - if (response.status === 201) { - // this.$router.push(response.data) - location.assign(response.data) + try { + const response = await axios.postForm("/api/login", { + server: this.server, + }); + if (response.status === 201) { + // this.$router.push(response.data) + location.assign(response.data); + this.serverErr = ""; + } + } catch (error) { + if (error.response && error.response.status === 404) { + this.serverErr = "サーバーが見つかりません" + } } }, + onInput () { + this.v$.server.$touch(); + this.serverErr = ""; + } }, }; @@ -60,8 +78,7 @@ export default { placeholder="mastodon.example" class="mb-2" :error-messages="serverErrors" - @input="v$.server.$touch" - @blur="v$.server.$touch" + @update:model-value="onInput" clearable /> 0 { + room.ScheduledAt = now + } + // If CoHosts are already registered, retrieve their AudonID for i, cohost := range room.CoHost { cohostUser, err := findUserByRemote(c.Request().Context(), cohost.RemoteID, cohost.RemoteURL) if err == nil { - room.CoHost[i].AudonID = cohostUser.AudonID + room.CoHost[i] = cohostUser } } - roomToken, err := getHostToken(room.RoomID, host.AudonID) - if err != nil { - c.Logger().Error(err) + room.CreatedAt = now + + coll := mainDB.Collection(COLLECTION_ROOM) + if _, insertErr := coll.InsertOne(c.Request().Context(), room); insertErr != nil { + c.Logger().Error(insertErr) return echo.NewHTTPError(http.StatusInternalServerError) } - return c.JSON(http.StatusCreated, roomToken) + return c.String(http.StatusCreated, room.RoomID) } -func getHostToken(room, identity string) (string, error) { +func getHostToken(room *Room) (string, error) { at := auth.NewAccessToken(mainConfig.Livekit.APIKey, mainConfig.Livekit.APISecret) grant := &auth.VideoGrant{ - Room: room, - RoomJoin: true, - RoomRecord: true, + Room: room.RoomID, + RoomJoin: true, } - at.AddGrant(grant). - SetIdentity(identity). - SetValidFor(24 * time.Hour) + at.AddGrant(grant).SetIdentity(room.Host.AudonID).SetValidFor(10 * time.Minute) return at.ToJWT() } diff --git a/schema.go b/schema.go index f619b86..0ca37fd 100644 --- a/schema.go +++ b/schema.go @@ -19,21 +19,20 @@ type ( AudonUser struct { AudonID string `bson:"audon_id" json:"audon_id" validate:"alphanum"` - RemoteID string `bson:"remote_id" json:"remote_id" validate:"alphanum"` + RemoteID string `bson:"remote_id" json:"remote_id" validate:"printascii"` RemoteURL string `bson:"remote_url" json:"remote_url" validate:"url"` CreatedAt time.Time `bson:"created_at" json:"created_at"` } Room struct { - RoomID string `bson:"room_id" json:"room_id" validate:"required,alphanum"` - Title string `bson:"title" json:"title" validate:"required,alphanumunicode"` - Description string `bson:"description" json:"description" validate:"alphanumunicode"` + RoomID string `bson:"room_id" json:"room_id" validate:"required,printascii"` + Title string `bson:"title" json:"title" validate:"required,printascii|multibyte"` + Description string `bson:"description" json:"description" validate:"printascii|multibyte"` Host *AudonUser `bson:"host" json:"host"` CoHost []*AudonUser `bson:"cohost" json:"cohost"` - FollowingOnly bool `bson:"following_only" json:"following_only" validate:"required"` - FollowerOnly bool `bson:"follower_only" json:"follower_only" validate:"required"` - InviteOnly bool `bson:"invite_only" json:"invite_only" validate:"required"` - InviteToken string `bson:"invite_token" json:"invite_token" validate:"alphanum"` + FollowingOnly bool `bson:"following_only" json:"following_only"` + FollowerOnly bool `bson:"follower_only" json:"follower_only"` + MutualOnly bool `bson:"mutual_only" json:"mutual_only"` ScheduledAt time.Time `bson:"scheduled_at" json:"scheduled_at"` CreatedAt time.Time `bson:"created_at" json:"created_at"` } @@ -47,12 +46,15 @@ const ( func createIndexes(ctx context.Context) error { userColl := mainDB.Collection(COLLECTION_USER) userIndexes, err := userColl.Indexes().ListSpecifications(ctx) + if err != nil { + return err + } if len(userIndexes) < 3 { _, err := userColl.Indexes().CreateMany(ctx, []mongo.IndexModel{ { Keys: bson.D{{Key: "audon_id", Value: 1}}, - Options: options.Index().SetName("audon_id_1").SetUnique(true), + Options: options.Index().SetUnique(true), }, { Keys: bson.D{ @@ -66,7 +68,28 @@ func createIndexes(ctx context.Context) error { } } - return err + roomColl := mainDB.Collection(COLLECTION_ROOM) + roomIndexes, err := roomColl.Indexes().ListSpecifications(ctx) + if err != nil { + return err + } + + if len(roomIndexes) < 3 { + _, err := roomColl.Indexes().CreateMany(ctx, []mongo.IndexModel{ + { + Keys: bson.D{{Key: "room_id", Value: 1}}, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{{Key: "host.audon_id", Value: 1}}, + }, + }) + if err != nil { + return err + } + } + + return nil } func findUserByRemote(ctx context.Context, remoteID, remoteURL string) (*AudonUser, error) { diff --git a/server.go b/server.go index 9d7fa40..3c6988a 100644 --- a/server.go +++ b/server.go @@ -56,15 +56,17 @@ func main() { os.Exit(1) } - dbContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) + backContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - dbClient, err := mongo.Connect(dbContext, options.Client().ApplyURI(mainConfig.MongoURL.String())) + + // Setup database client + dbClient, err := mongo.Connect(backContext, options.Client().ApplyURI(mainConfig.MongoURL.String())) if err != nil { log.Fatalln(err) os.Exit(2) } mainDB = dbClient.Database(mainConfig.Database.Name) - err = createIndexes(dbContext) + err = createIndexes(backContext) if err != nil { log.Fatalln(err) os.Exit(3) @@ -78,7 +80,23 @@ func main() { } e.Renderer = t e.Validator = &CustomValidator{validator: mainValidator} - e.Use(session.Middleware(sessions.NewCookieStore([]byte(mainConfig.SeesionSecret)))) + cookieStore := sessions.NewCookieStore([]byte(mainConfig.SeesionSecret)) + cookieStore.Options = &sessions.Options{ + Path: "/", + Domain: mainConfig.LocalDomain, + MaxAge: 86400 * 30, + HttpOnly: true, + SameSite: http.SameSiteStrictMode, + Secure: true, + } + if mainConfig.Environment == "development" { + cookieStore.Options.Domain = "" + cookieStore.Options.SameSite = http.SameSiteNoneMode + cookieStore.Options.Secure = false + cookieStore.Options.MaxAge = 3600 * 24 + cookieStore.Options.HttpOnly = false + } + e.Use(session.Middleware(cookieStore)) // e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{ // CookiePath: "/", // TokenLookup: "header:X-XSRF-TOKEN", @@ -164,14 +182,6 @@ func getSession(c echo.Context) (sess *sessions.Session, err error) { return nil, err } - sess.Options = &sessions.Options{ - Path: "/", - MaxAge: 0, - HttpOnly: true, - SameSite: http.SameSiteStrictMode, - Secure: true, - } - return sess, nil }