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

Commit

Permalink
Merge pull request #49 from saitamau-maximum/feat/#40_add_channels
Browse files Browse the repository at this point in the history
チャンネル機能実装 / サーバー
  • Loading branch information
sor4chi authored Dec 29, 2023
2 parents a029cec + d8b05f8 commit 78c99a3
Show file tree
Hide file tree
Showing 29 changed files with 1,296 additions and 92 deletions.
32 changes: 32 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## GET /api/channels

ログインしているユーザの属するChannel一覧を返す

```json
{
"channels": [
{
"id": 1,
"name": "test",
},
]
}
```

## GET /api/channels/:id

Channelの詳細を返す

```json
{
"channel": {
"name": "test",
"users": [
{
"name": "test",
"image_url": "test",
},
]
}
}
```
154 changes: 154 additions & 0 deletions server/adapter/handler/channel_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package handler

import (
"log"
"net/http"
"strconv"

"github.com/labstack/echo/v4"
"github.com/saitamau-maximum/meline/adapter/request"
"github.com/saitamau-maximum/meline/usecase"
)

type ChannelHandler struct {
channelInteractor usecase.IChannelInteractor
}

func NewChannelHandler(channelGroup *echo.Group, channelInteractor usecase.IChannelInteractor) {
channelHandler := &ChannelHandler{
channelInteractor: channelInteractor,
}

channelGroup.GET("", channelHandler.GetAllChannels)
channelGroup.GET("/:id", channelHandler.GetChannelByID)
channelGroup.GET("/", channelHandler.GetAllChannels)
channelGroup.POST("/:id/join", channelHandler.JoinChannel)
channelGroup.POST("", channelHandler.CreateChannel)
channelGroup.PUT("/:id", channelHandler.UpdateChannel)
channelGroup.DELETE("/:id", channelHandler.DeleteChannel)
channelGroup.DELETE("/:id/leave", channelHandler.LeaveChannel)
}

func (h *ChannelHandler) GetAllChannels(c echo.Context) error {
userId := c.Get("user_id").(uint64)
channelsResponse, err := h.channelInteractor.GetAllChannels(c.Request().Context(), userId)
if err != nil {
log.Println(err)
return c.JSON(http.StatusInternalServerError, err)
}

return c.JSON(http.StatusOK, channelsResponse)
}

func (h *ChannelHandler) GetChannelByID(c echo.Context) error {
id := c.Param("id")

channelId, err := strconv.ParseUint(id, 10, 64)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

channelResponse, err := h.channelInteractor.GetChannelByID(c.Request().Context(), channelId)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

return c.JSON(http.StatusOK, channelResponse)
}

func (h *ChannelHandler) GetChannelsByName(c echo.Context) error {
name := c.Param("name")

channelsResponse, err := h.channelInteractor.GetChannelsByName(c.Request().Context(), name)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

return c.JSON(http.StatusOK, channelsResponse)
}

func (h *ChannelHandler) CreateChannel(c echo.Context) error {
userId := c.Get("user_id").(uint64)

req := request.CreateChannelRequest{}

if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

if err := h.channelInteractor.CreateChannel(c.Request().Context(), req.Name, userId); err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

return c.NoContent(http.StatusOK)
}

func (h *ChannelHandler) UpdateChannel(c echo.Context) error {
id := c.Param("id")

channelId, err := strconv.ParseUint(id, 10, 64)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

req := request.UpdateChannelRequest{}

if err := c.Bind(&req); err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

if err := h.channelInteractor.UpdateChannel(c.Request().Context(), channelId, req.Name); err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

return c.NoContent(http.StatusOK)
}

func (h *ChannelHandler) DeleteChannel(c echo.Context) error {
id := c.Param("id")

channelId, err := strconv.ParseUint(id, 10, 64)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

if err := h.channelInteractor.DeleteChannel(c.Request().Context(), channelId); err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

return c.NoContent(http.StatusOK)
}

func (h *ChannelHandler) JoinChannel(c echo.Context) error {
id := c.Param("id")

channelId, err := strconv.ParseUint(id, 10, 64)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

userId := c.Get("user_id").(uint64)

if err := h.channelInteractor.JoinChannel(c.Request().Context(), channelId, userId); err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

return c.NoContent(http.StatusOK)
}

func (h *ChannelHandler) LeaveChannel(c echo.Context) error {
id := c.Param("id")

channelId, err := strconv.ParseUint(id, 10, 64)
if err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

userId := c.Get("user_id").(uint64)

if err := h.channelInteractor.LeaveChannel(c.Request().Context(), channelId, userId); err != nil {
return c.JSON(http.StatusInternalServerError, err)
}

return c.NoContent(http.StatusOK)
}
58 changes: 58 additions & 0 deletions server/adapter/presenter/channel_presenter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package presenter

import (
"github.com/saitamau-maximum/meline/domain/entity"
"github.com/saitamau-maximum/meline/usecase/presenter"
)

type ChannelPresenter struct{}

func NewChannelPresenter() presenter.IChannelPresenter {
return &ChannelPresenter{}
}

func (p *ChannelPresenter) GenerateGetAllChannelsResponse(channels []*entity.Channel) *presenter.GetAllChannelsResponse {
channelsResponse := &presenter.GetAllChannelsResponse{
Channels: []*presenter.Channel{},
}
for _, channel := range channels {
channelsResponse.Channels = append(channelsResponse.Channels, &presenter.Channel{
ID: channel.ID,
Name: channel.Name,
})
}

return channelsResponse
}

func (p *ChannelPresenter) GenerateGetChannelByIdResponse(channel *entity.Channel) *presenter.GetChannelByIdResponse {
users := make([]*presenter.User, len(channel.Users))
for _, user := range channel.Users {
users = append(users, &presenter.User{
ID: user.ID,
Name: user.Name,
ImageURL: user.ImageURL,
})
}

return &presenter.GetChannelByIdResponse{
Channel: &presenter.ChannelDetail{
Name: channel.Name,
Users: users,
},
}
}

func (p *ChannelPresenter) GenerateGetChannelsByNameResponse(channels []*entity.Channel) *presenter.GetChannelsByNameResponse {
channelsResponse := &presenter.GetChannelsByNameResponse{
Channels: []*presenter.Channel{},
}
for _, channel := range channels {
channelsResponse.Channels = append(channelsResponse.Channels, &presenter.Channel{
ID: channel.ID,
Name: channel.Name,
})
}

return channelsResponse
}
5 changes: 5 additions & 0 deletions server/adapter/request/create_channel_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package request

type CreateChannelRequest struct {
Name string `json:"name"`
}
5 changes: 5 additions & 0 deletions server/adapter/request/update_channel_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package request

type UpdateChannelRequest struct {
Name string `json:"name"`
}
2 changes: 2 additions & 0 deletions server/cmd/migrate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/saitamau-maximum/meline/config"
infra "github.com/saitamau-maximum/meline/infra/mysql"
"github.com/saitamau-maximum/meline/migrations"
model "github.com/saitamau-maximum/meline/models"
)

const (
Expand All @@ -36,6 +37,7 @@ func main() {
panic(err)
}
bunDB := bun.NewDB(db, mysqldialect.New())
bunDB.RegisterModel((*model.ChannelUsers)(nil), (*model.Channel)(nil), (*model.User)(nil))
bunDB.AddQueryHook(bundebug.NewQueryHook(
bundebug.WithEnabled(false),
bundebug.FromEnv(""),
Expand Down
6 changes: 6 additions & 0 deletions server/cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/saitamau-maximum/meline/config"
"github.com/saitamau-maximum/meline/infra/github"
"github.com/saitamau-maximum/meline/infra/mysql"
model "github.com/saitamau-maximum/meline/models"
"github.com/saitamau-maximum/meline/usecase"
)

Expand All @@ -35,21 +36,26 @@ func main() {
}

bunDB := bun.NewDB(db, mysqldialect.New())
bunDB.RegisterModel((*model.ChannelUsers)(nil), (*model.Channel)(nil), (*model.User)(nil))
defer bunDB.Close()

apiGroup := e.Group("/api")

oAuthConf := github.NewGithubOAuthConf()
oAuthRepository := github.NewOAuthRepository(oAuthConf)
userRepository := mysql.NewUserRepository(bunDB)
channelRepository := mysql.NewChannelRepository(bunDB)
channelUsersRepository := mysql.NewChannelUsersRepository(bunDB)
githubOAuthInteractor := usecase.NewGithubOAuthInteractor(oAuthRepository)
authInteractor := usecase.NewAuthInteractor()
channelInteractor := usecase.NewChannelInteractor(channelRepository, channelUsersRepository, userRepository, presenter.NewChannelPresenter())
userPresenter := presenter.NewUserPresenter()
userInteractor := usecase.NewUserInteractor(userRepository, userPresenter)
authGateway := gateway.NewAuthGateway(userInteractor)

handler.NewOAuthHandler(apiGroup.Group("/auth"), githubOAuthInteractor, authInteractor, userInteractor)
handler.NewUserHandler(apiGroup.Group("/user", authGateway.Auth), userInteractor)
handler.NewChannelHandler(apiGroup.Group("/channels", authGateway.Auth), channelInteractor)

apiGroup.GET("/", authGateway.Auth(func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
Expand Down
23 changes: 23 additions & 0 deletions server/domain/entity/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package entity

import (
"time"
)

type Channel struct {
ID uint64
Name string
Users []*User
CreatedAt time.Time
DeletedAt time.Time
}

func NewChannelEntity(id uint64, name string, Users []*User, createdAt, deletedAt time.Time) *Channel {
return &Channel{
ID: id,
Name: name,
Users: Users,
CreatedAt: createdAt,
DeletedAt: deletedAt,
}
}
23 changes: 23 additions & 0 deletions server/domain/entity/channel_users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package entity

import (
"time"
)

type ChannelUsers struct {
UserID uint64
User *User
ChannelID uint64
Channel *Channel
JoinedAt time.Time
}

func NewChannelUsersEntity(userID uint64, user *User, channelID uint64, channel *Channel, joinedAt time.Time) *ChannelUsers {
return &ChannelUsers{
UserID: userID,
User: user,
ChannelID: channelID,
Channel: channel,
JoinedAt: joinedAt,
}
}
6 changes: 3 additions & 3 deletions server/domain/entity/oauth_user_response.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package entity

type OAuthUserResponse struct {
OAuthUserID string `json:"user_id"`
Name string `json:"name"`
ImageURL string `json:"image_url"`
OAuthUserID string `json:"user_id"`
Name string `json:"name"`
ImageURL string `json:"image_url"`
}
Loading

0 comments on commit 78c99a3

Please sign in to comment.