Line data Source code
1 : // Package controller は スキル関連情報に関する、エンドポイントを提供します
2 : package controller
3 :
4 : import (
5 : "errors"
6 : "net/http"
7 : "strconv"
8 :
9 : "github.com/gin-gonic/gin"
10 : "github.com/go-playground/validator/v10"
11 :
12 : "resume/internal/adapter/http/dto/request"
13 : "resume/internal/adapter/http/handlerutil"
14 : "resume/internal/shared/apperr"
15 : "resume/internal/shared/ctx/auth"
16 : ucskill "resume/internal/usecase/skill"
17 : )
18 :
19 : // SkillHandler はスキル関連のエンドポイントを提供します
20 : type SkillHandler struct {
21 : uc ucskill.Usecase
22 : }
23 :
24 : // NewSkillHandler は スキルユースケースを注入した新しい SkillHandler を生成します
25 : func NewSkillHandler(
26 : uc ucskill.Usecase,
27 0 : ) *SkillHandler {
28 0 : return &SkillHandler{
29 0 : uc: uc,
30 0 : }
31 0 : }
32 :
33 : // ListSkill はユーザスキル一覧を取得します
34 0 : func (h *SkillHandler) ListSkill(c *gin.Context) {
35 0 : UserID, ok := auth.UserID(c)
36 0 : if !ok || UserID == 0 {
37 0 : handlerutil.WriteError(c, apperr.New(apperr.CodeUnauthorized, "unauthorized", nil))
38 0 : return
39 0 : }
40 0 : var req request.ListUserSkillRequest
41 0 : if err := c.ShouldBindQuery(&req); err != nil {
42 0 : var verrs validator.ValidationErrors
43 0 : if errors.As(err, &verrs) {
44 0 : env := handlerutil.BuildValidationEnvelope(c, verrs, "domain.userSkill")
45 0 : handlerutil.WriteValidationError(c, env)
46 0 : return
47 0 : }
48 0 : handlerutil.WriteError(c, err)
49 0 : return
50 : }
51 0 : req.Normalize()
52 0 : in := ucskill.ListUserSkillInput{
53 0 : UserID: UserID,
54 0 : Page: req.Page,
55 0 : PerPage: req.PerPage,
56 0 : Sort: req.Sort,
57 0 : SortOrder: req.Order,
58 0 : SkillCategoryID: req.SkillCategoryID,
59 0 : SKillLevelID: req.SkillLevelID,
60 0 : ExperienceID: req.ExperienceID,
61 0 : SkillNameNorm: req.SkillNameNorm,
62 0 : }
63 0 : out, err := h.uc.ListUserSkill(c.Request.Context(), in)
64 0 : if err != nil {
65 0 : c.JSON(http.StatusInternalServerError, gin.H{
66 0 : "error": "failed to fetch user skill",
67 0 : })
68 0 : }
69 0 : c.JSON(http.StatusOK, out)
70 : }
71 :
72 : // SuggestSkill は スキル候補をリストアップするためのエンドポイントを提供します
73 : func (h *SkillHandler) SuggestSkill(
74 : c *gin.Context,
75 0 : ) {
76 0 : _, ok := auth.From(c.Request.Context())
77 0 : if !ok {
78 0 : handlerutil.WriteError(
79 0 : c,
80 0 : apperr.New(apperr.CodeUnauthorized, "unauthorized", nil),
81 0 : )
82 0 : return
83 0 : }
84 0 : var req request.SuggestUserSkillRequest
85 0 : if err := c.ShouldBindJSON(&req); err != nil {
86 0 : var verrs validator.ValidationErrors
87 0 : if errors.As(err, &verrs) {
88 0 : env := handlerutil.BuildValidationEnvelope(c, verrs, "domain.userSkill")
89 0 : handlerutil.WriteValidationError(c, env)
90 0 : return
91 0 : }
92 0 : handlerutil.WriteError(c, err)
93 0 : return
94 : }
95 0 : req.Normalize()
96 0 : in := ucskill.SuggestUserSkillInput{
97 0 : SkillCategoryID: req.SkillCategoryID,
98 0 : Q: req.Q,
99 0 : Limit: req.Limit,
100 0 : WithDeleted: req.WithDeleted,
101 0 : }
102 0 : out, err := h.uc.SuggestUserSkill(c.Request.Context(), in)
103 0 : if err != nil {
104 0 : handlerutil.WriteError(c, err)
105 0 : return
106 0 : }
107 0 : c.JSON(http.StatusOK, out)
108 : }
109 :
110 : // AddSkill は スキルの追加に関するエンドポイントを提供します
111 : func (h *SkillHandler) AddSkill(
112 : c *gin.Context,
113 0 : ) {
114 0 : _, ok := auth.From(c.Request.Context())
115 0 : if !ok {
116 0 : handlerutil.WriteError(
117 0 : c,
118 0 : apperr.New(apperr.CodeUnauthorized, "unauthorized", nil),
119 0 : )
120 0 : return
121 0 : }
122 :
123 0 : var req request.AddSkillRequest
124 0 : if err := c.ShouldBindJSON(&req); err != nil {
125 0 : var verrs validator.ValidationErrors
126 0 : if errors.As(err, &verrs) {
127 0 : env := handlerutil.BuildValidationEnvelope(c, verrs, "domain.userSkill")
128 0 : handlerutil.WriteValidationError(c, env)
129 0 : return
130 0 : }
131 0 : handlerutil.WriteError(c, err)
132 0 : return
133 : }
134 0 : req.Normalize()
135 0 :
136 0 : userID, ok := auth.UserID(c)
137 0 : if !ok || userID == 0 {
138 0 : handlerutil.WriteError(
139 0 : c,
140 0 : apperr.New(apperr.CodeUnauthorized, "unauthorized", nil),
141 0 : )
142 0 : return
143 0 : }
144 :
145 0 : in := ucskill.CreateUserSkillInput{
146 0 : UserID: userID,
147 0 : SkillCategoryID: req.SkillCategoryID,
148 0 : SkillLevelID: req.SkillLevelID,
149 0 : ExperienceID: req.ExperienceID,
150 0 : SkillName: req.SkillName,
151 0 : Evidence: req.Evidence,
152 0 : }
153 0 :
154 0 : out, err := h.uc.CreateUserSkill(c.Request.Context(), in)
155 0 : if err != nil {
156 0 : handlerutil.WriteError(c, err)
157 0 : return
158 0 : }
159 :
160 0 : c.JSON(http.StatusCreated, out)
161 : }
162 :
163 : // EditSkill は スキルの更新に関するエンドポイントを提供します
164 0 : func (h *SkillHandler) EditSkill(c *gin.Context) {
165 0 : _, ok := auth.From(c.Request.Context())
166 0 : if !ok {
167 0 : handlerutil.WriteError(
168 0 : c,
169 0 : apperr.New(apperr.CodeUnauthorized, "unauthorized", nil),
170 0 : )
171 0 : return
172 0 : }
173 :
174 0 : var req request.EditUserSkillRequest
175 0 : if err := c.ShouldBindJSON(&req); err != nil {
176 0 : var verrs validator.ValidationErrors
177 0 : if errors.As(err, &verrs) {
178 0 : env := handlerutil.BuildValidationEnvelope(c, verrs, "domain.userSkill")
179 0 : handlerutil.WriteValidationError(c, env)
180 0 : return
181 0 : }
182 0 : handlerutil.WriteError(c, err)
183 0 : return
184 : }
185 0 : req.Normalize()
186 0 :
187 0 : userID, ok := auth.UserID(c)
188 0 : if !ok || userID == 0 {
189 0 : handlerutil.WriteError(
190 0 : c,
191 0 : apperr.New(apperr.CodeUnauthorized, "unauthorized", nil),
192 0 : )
193 0 : return
194 0 : }
195 :
196 0 : skillIDStr := c.Param("skill_id")
197 0 : skillID, err := strconv.ParseUint(skillIDStr, 10, 64)
198 0 : if err != nil {
199 0 : c.JSON(http.StatusBadRequest, gin.H{
200 0 : "error": "invalid skill_id",
201 0 : })
202 0 : return
203 0 : }
204 0 : in := ucskill.UpdateUserSkillInput{
205 0 : ID: skillID,
206 0 : UserID: userID,
207 0 : SkillCategoryID: req.SkillCategoryID,
208 0 : SkillLevelID: req.SkillLevelID,
209 0 : ExperienceID: req.ExperienceID,
210 0 : SkillName: req.SkillName,
211 0 : Evidence: req.Evidence,
212 0 : }
213 0 : out, err := h.uc.UpdateUserSkill(c.Request.Context(), in)
214 0 : if err != nil {
215 0 : handlerutil.WriteError(c, err)
216 0 : return
217 0 : }
218 0 : c.JSON(http.StatusOK, out)
219 : }
220 :
221 : // DeleteSkill はスキルを削除するハンドラです
222 0 : func (h *SkillHandler) DeleteSkill(c *gin.Context) {
223 0 : userID, ok := auth.UserID(c)
224 0 : if !ok || userID == 0 {
225 0 : handlerutil.WriteError(
226 0 : c,
227 0 : apperr.New(apperr.CodeUnauthorized, "unauthorized", nil),
228 0 : )
229 0 : }
230 :
231 0 : skillIDStr := c.Param("skill_id")
232 0 : skillID, err := strconv.ParseUint(skillIDStr, 10, 64)
233 0 : if err != nil {
234 0 : c.JSON(http.StatusBadRequest, gin.H{
235 0 : "error": "invalid skill_id",
236 0 : })
237 0 : return
238 0 : }
239 :
240 0 : in := ucskill.DeleteUserSkillInput{
241 0 : ID: skillID,
242 0 : UserID: userID,
243 0 : }
244 0 :
245 0 : out, err := h.uc.DeleteUserSkill(c.Request.Context(), in)
246 0 : if err != nil {
247 0 : handlerutil.WriteError(c, err)
248 0 : return
249 0 : }
250 0 : c.JSON(http.StatusOK, out)
251 : }
252 :
253 : // OrderSkill はスキルの並び順を更新するハンドラです
254 0 : func (h *SkillHandler) OrderSkill(c *gin.Context) {
255 0 : userID, ok := auth.UserID(c)
256 0 : if !ok || userID == 0 {
257 0 : handlerutil.WriteError(
258 0 : c,
259 0 : apperr.New(apperr.CodeUnauthorized, "unauthorized", nil),
260 0 : )
261 0 : return
262 0 : }
263 :
264 0 : var req request.OrderUserSkillRequest
265 0 : if err := c.ShouldBindJSON(&req); err != nil {
266 0 : var verrs validator.ValidationErrors
267 0 : if errors.As(err, &verrs) {
268 0 : env := handlerutil.BuildValidationEnvelope(c, verrs, "domain.userSkill")
269 0 : handlerutil.WriteValidationError(c, env)
270 0 : return
271 0 : }
272 0 : handlerutil.WriteError(c, err)
273 0 : return
274 : }
275 :
276 0 : in := ucskill.OrderUserSkillInput{
277 0 : UserID: userID,
278 0 : IDs: req.IDs,
279 0 : }
280 0 :
281 0 : err := h.uc.ReorderUserSkill(c.Request.Context(), in)
282 0 : if err != nil {
283 0 : handlerutil.WriteError(c, err)
284 0 : return
285 0 : }
286 :
287 : //c.JSON(http.StatusNoContent, nil)
288 0 : c.Status(http.StatusNoContent)
289 : }
290 :
291 : // ExistsSkill は指定されたユーザーがスキルを持っているかを確認するハンドラです
292 0 : func (h *SkillHandler) ExistsSkill(c *gin.Context) {
293 0 : userID, ok := auth.UserID(c)
294 0 : if !ok || userID == 0 {
295 0 : handlerutil.WriteError(
296 0 : c,
297 0 : apperr.New(apperr.CodeUnauthorized, "unauthorized", nil),
298 0 : )
299 0 : return
300 0 : }
301 0 : in := ucskill.HasUserSkillInput{
302 0 : UserID: userID,
303 0 : }
304 0 : out, err := h.uc.HasUserSkill(c.Request.Context(), in)
305 0 : if err != nil {
306 0 : handlerutil.WriteError(c, err)
307 0 : return
308 0 : }
309 0 : c.JSON(http.StatusOK, out)
310 : }
|