diff --git a/docs/v3-api.yaml b/docs/v3-api.yaml index 12fbb3aeb..86fb5118e 100644 --- a/docs/v3-api.yaml +++ b/docs/v3-api.yaml @@ -1311,6 +1311,35 @@ paths: ユーザーが見つかりません。 operationId: getUserStats description: 指定したユーザーの統計情報を取得します。 + '/channels/{channelId}/audiences': + parameters: + - $ref: '#/components/parameters/channelIdInPath' + get: + summary: チャンネルの未読管理者のリストを取得 + tags: + - channel + - notification + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + description: 未読管理者UUIDの配列 + items: + type: string + format: uuid + '403': + description: |- + Forbidden + プライベートチャンネル・強制通知チャンネルの設定は取得できません。 + '404': + description: |- + Not Found + チャンネルが見つかりません。 + operationId: getChannelAudiences + description: 指定したチャンネルを未読管理しているユーザーのUUIDのリストを取得します。 '/channels/{channelId}/subscribers': parameters: - $ref: '#/components/parameters/channelIdInPath' diff --git a/router/v3/channels.go b/router/v3/channels.go index 976630d9d..85cbfe558 100644 --- a/router/v3/channels.go +++ b/router/v3/channels.go @@ -293,6 +293,27 @@ func (h *Handlers) GetChannelSubscribers(c echo.Context) error { return c.JSON(http.StatusOK, result) } +// GetChannelAudiences GET /channels/:channelID/audiences +func (h *Handlers) GetChannelAudiences(c echo.Context) error { + ch := getParamChannel(c) + + // プライベートチャンネル・強制通知チャンネルの設定は取得できない。 + if !ch.IsPublic || ch.IsForced { + return herror.Forbidden() + } + + audiences, err := h.Repo.GetChannelSubscriptions(repository.ChannelSubscriptionQuery{}.SetChannel(ch.ID).SetLevel(model.ChannelSubscribeLevelMark)) + if err != nil { + return herror.InternalServerError(err) + } + result := make([]uuid.UUID, 0) + for _, audience := range audiences { + result = append(result, audience.UserID) + } + + return c.JSON(http.StatusOK, result) +} + // PutChannelSubscribersRequest PUT /channels/:channelID/subscribers リクエストボディ type PutChannelSubscribersRequest struct { On set.UUID `json:"on"` diff --git a/router/v3/channels_test.go b/router/v3/channels_test.go index fa4e56d49..b6b28ccfa 100644 --- a/router/v3/channels_test.go +++ b/router/v3/channels_test.go @@ -831,9 +831,82 @@ func TestHandlers_GetChannelSubscribers(t *testing.T) { env := Setup(t, common1) user := env.CreateUser(t, rand) user2 := env.CreateUser(t, rand) + user3 := env.CreateUser(t, rand) channel := env.CreateChannel(t, rand) err := env.CM.ChangeChannelSubscriptions(channel.ID, map[uuid.UUID]model.ChannelSubscribeLevel{ - user.GetID(): model.ChannelSubscribeLevelMarkAndNotify, + user.GetID(): model.ChannelSubscribeLevelMarkAndNotify, + user2.GetID(): model.ChannelSubscribeLevelNone, + user3.GetID(): model.ChannelSubscribeLevelMark, + }, false, user.GetID()) + require.NoError(t, err) + forced := env.CreateChannel(t, rand) + require.NoError(t, env.CM.UpdateChannel(forced.ID, repository.UpdateChannelArgs{ForcedNotification: optional.From(true)})) + dm := env.CreateDMChannel(t, user.GetID(), user2.GetID()) + commonSession := env.S(t, user.GetID()) + + t.Run("not logged in", func(t *testing.T) { + t.Parallel() + e := env.R(t) + e.GET(path, channel.ID). + Expect(). + Status(http.StatusUnauthorized) + }) + + t.Run("not found", func(t *testing.T) { + t.Parallel() + e := env.R(t) + e.GET(path, uuid.Must(uuid.NewV4()).String()). + WithCookie(session.CookieName, commonSession). + Expect(). + Status(http.StatusNotFound) + }) + + t.Run("forbidden (forced)", func(t *testing.T) { + t.Parallel() + e := env.R(t) + e.GET(path, forced.ID.String()). + WithCookie(session.CookieName, commonSession). + Expect(). + Status(http.StatusForbidden) + }) + + t.Run("forbidden (dm)", func(t *testing.T) { + t.Parallel() + e := env.R(t) + e.GET(path, dm.ID.String()). + WithCookie(session.CookieName, commonSession). + Expect(). + Status(http.StatusForbidden) + }) + + t.Run("success", func(t *testing.T) { + t.Parallel() + e := env.R(t) + obj := e.GET(path, channel.ID.String()). + WithCookie(session.CookieName, commonSession). + Expect(). + Status(http.StatusOK). + JSON(). + Array() + + obj.Length().IsEqual(1) + obj.Value(0).String().IsEqual(user.GetID().String()) + }) +} + +func TestHandlers_GetChannelAudiences(t *testing.T) { + t.Parallel() + + path := "/api/v3/channels/{channelId}/audiences" + env := Setup(t, common1) + user := env.CreateUser(t, rand) + user2 := env.CreateUser(t, rand) + user3 := env.CreateUser(t, rand) + channel := env.CreateChannel(t, rand) + err := env.CM.ChangeChannelSubscriptions(channel.ID, map[uuid.UUID]model.ChannelSubscribeLevel{ + user.GetID(): model.ChannelSubscribeLevelMark, + user2.GetID(): model.ChannelSubscribeLevelNone, + user3.GetID(): model.ChannelSubscribeLevelMarkAndNotify, }, false, user.GetID()) require.NoError(t, err) forced := env.CreateChannel(t, rand) diff --git a/router/v3/router.go b/router/v3/router.go index 721d1b4b7..93e55b232 100644 --- a/router/v3/router.go +++ b/router/v3/router.go @@ -185,6 +185,7 @@ func (h *Handlers) Setup(e *echo.Group) { apiChannelsCID.PUT("/topic", h.EditChannelTopic, requires(permission.EditChannelTopic)) apiChannelsCID.GET("/viewers", h.GetChannelViewers, requires(permission.GetChannel)) apiChannelsCID.GET("/pins", h.GetChannelPins, requires(permission.GetMessage)) + apiChannelsCID.GET("/audiences", h.GetChannelAudiences, requires(permission.GetChannelSubscription)) apiChannelsCID.GET("/subscribers", h.GetChannelSubscribers, requires(permission.GetChannelSubscription)) apiChannelsCID.PUT("/subscribers", h.SetChannelSubscribers, requires(permission.EditChannelSubscription)) apiChannelsCID.PATCH("/subscribers", h.EditChannelSubscribers, requires(permission.EditChannelSubscription))