1
0

schema.resolvers.go 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550
  1. package graph
  2. // This file will be automatically regenerated based on the schema, any resolver
  3. // implementations
  4. // will be copied through when generating and any unknown code will be moved to the end.
  5. // Code generated by github.com/99designs/gqlgen version v0.17.87
  6. import (
  7. "context"
  8. "errors"
  9. "fmt"
  10. "time"
  11. "gogs.dmsc.dev/arp/auth"
  12. "gogs.dmsc.dev/arp/graph/model"
  13. "gogs.dmsc.dev/arp/logging"
  14. "gogs.dmsc.dev/arp/models"
  15. )
  16. // Login is the resolver for the login field.
  17. func (r *mutationResolver) Login(ctx context.Context, email string, password string) (*model.AuthPayload, error) {
  18. var user models.User
  19. if err := r.DB.Preload("Roles.Permissions").Where("email = ?", email).First(&user).Error; err != nil {
  20. return nil, errors.New("invalid credentials")
  21. }
  22. // Check password
  23. if !auth.CheckPassword(password, user.Password) {
  24. return nil, errors.New("invalid credentials")
  25. }
  26. token, err := auth.GenerateToken(user)
  27. if err != nil {
  28. return nil, fmt.Errorf("failed to generate token: %w", err)
  29. }
  30. return &model.AuthPayload{
  31. Token: token,
  32. User: convertUser(user),
  33. }, nil
  34. }
  35. // CreateUser is the resolver for the createUser field.
  36. func (r *mutationResolver) CreateUser(ctx context.Context, input model.NewUser) (*model.User, error) {
  37. // Auth check
  38. if !auth.IsAuthenticated(ctx) {
  39. return nil, errors.New("unauthorized: authentication required")
  40. }
  41. roles := make([]models.Role, len(input.Roles))
  42. for i, roleIDStr := range input.Roles {
  43. roleID, err := toID(roleIDStr)
  44. if err != nil {
  45. return nil, fmt.Errorf("invalid role ID: %w", err)
  46. }
  47. var role models.Role
  48. if err := r.DB.First(&role, roleID).Error; err != nil {
  49. return nil, fmt.Errorf("role not found: %w", err)
  50. }
  51. roles[i] = role
  52. }
  53. // Hash the password before storing
  54. hashedPassword, err := auth.HashPassword(input.Password)
  55. if err != nil {
  56. return nil, fmt.Errorf("failed to hash password: %w", err)
  57. }
  58. user := models.User{
  59. Email: input.Email,
  60. Password: hashedPassword,
  61. Roles: roles,
  62. }
  63. if err := r.DB.Create(&user).Error; err != nil {
  64. return nil, fmt.Errorf("failed to create user: %w", err)
  65. }
  66. logging.LogMutation(ctx, "CREATE", "USER", user.Email)
  67. return convertUser(user), nil
  68. }
  69. // UpdateUser is the resolver for the updateUser field.
  70. func (r *mutationResolver) UpdateUser(ctx context.Context, id string, input model.UpdateUserInput) (*model.User, error) {
  71. // Auth check
  72. if !auth.IsAuthenticated(ctx) {
  73. return nil, errors.New("unauthorized: authentication required")
  74. }
  75. if !auth.HasPermission(ctx, "user:update") {
  76. return nil, errors.New("unauthorized: missing user:update permission")
  77. }
  78. userID, err := toID(id)
  79. if err != nil {
  80. return nil, fmt.Errorf("invalid user ID: %w", err)
  81. }
  82. var existing models.User
  83. if err := r.DB.First(&existing, userID).Error; err != nil {
  84. return nil, fmt.Errorf("user not found: %w", err)
  85. }
  86. if input.Email != nil {
  87. existing.Email = *input.Email
  88. }
  89. if input.Password != nil {
  90. // Hash the new password
  91. hashedPassword, err := auth.HashPassword(*input.Password)
  92. if err != nil {
  93. return nil, fmt.Errorf("failed to hash password: %w", err)
  94. }
  95. existing.Password = hashedPassword
  96. }
  97. if len(input.Roles) > 0 {
  98. roles := make([]models.Role, len(input.Roles))
  99. for i, roleIDStr := range input.Roles {
  100. roleID, err := toID(roleIDStr)
  101. if err != nil {
  102. return nil, fmt.Errorf("invalid role ID: %w", err)
  103. }
  104. var role models.Role
  105. if err := r.DB.First(&role, roleID).Error; err != nil {
  106. return nil, fmt.Errorf("role not found: %w", err)
  107. }
  108. roles[i] = role
  109. }
  110. existing.Roles = roles
  111. }
  112. if err := r.DB.Save(&existing).Error; err != nil {
  113. return nil, fmt.Errorf("failed to update user: %w", err)
  114. }
  115. logging.LogMutation(ctx, "UPDATE", "USER", existing.Email)
  116. return convertUser(existing), nil
  117. }
  118. // DeleteUser is the resolver for the deleteUser field.
  119. func (r *mutationResolver) DeleteUser(ctx context.Context, id string) (bool, error) {
  120. // Auth check
  121. if !auth.IsAuthenticated(ctx) {
  122. return false, errors.New("unauthorized: authentication required")
  123. }
  124. if !auth.HasPermission(ctx, "user:delete") {
  125. return false, errors.New("unauthorized: missing user:delete permission")
  126. }
  127. userID, err := toID(id)
  128. if err != nil {
  129. return false, fmt.Errorf("invalid user ID: %w", err)
  130. }
  131. result := r.DB.Delete(&models.User{}, userID)
  132. if result.Error != nil {
  133. return false, fmt.Errorf("failed to delete user: %w", result.Error)
  134. }
  135. logging.LogMutation(ctx, "DELETE", "USER", id)
  136. return result.RowsAffected > 0, nil
  137. }
  138. // CreateNote is the resolver for the createNote field.
  139. func (r *mutationResolver) CreateNote(ctx context.Context, input model.NewNote) (*model.Note, error) {
  140. // Auth check
  141. if !auth.IsAuthenticated(ctx) {
  142. return nil, errors.New("unauthorized: authentication required")
  143. }
  144. userID, err := toID(input.UserID)
  145. if err != nil {
  146. return nil, fmt.Errorf("invalid user ID: %w", err)
  147. }
  148. serviceID, err := toID(input.ServiceID)
  149. if err != nil {
  150. return nil, fmt.Errorf("invalid service ID: %w", err)
  151. }
  152. note := models.Note{
  153. Title: input.Title,
  154. Content: input.Content,
  155. UserID: userID,
  156. ServiceID: serviceID,
  157. }
  158. if err := r.DB.Create(&note).Error; err != nil {
  159. return nil, fmt.Errorf("failed to create note: %w", err)
  160. }
  161. logging.LogMutation(ctx, "CREATE", "NOTE", note.Title)
  162. return convertNote(note), nil
  163. }
  164. // UpdateNote is the resolver for the updateNote field.
  165. func (r *mutationResolver) UpdateNote(ctx context.Context, id string, input model.UpdateNoteInput) (*model.Note, error) {
  166. // Auth check
  167. if !auth.IsAuthenticated(ctx) {
  168. return nil, errors.New("unauthorized: authentication required")
  169. }
  170. if !auth.HasPermission(ctx, "note:update") {
  171. return nil, errors.New("unauthorized: missing note:update permission")
  172. }
  173. noteID, err := toID(id)
  174. if err != nil {
  175. return nil, fmt.Errorf("invalid note ID: %w", err)
  176. }
  177. var existing models.Note
  178. if err := r.DB.First(&existing, noteID).Error; err != nil {
  179. return nil, fmt.Errorf("note not found: %w", err)
  180. }
  181. if input.Title != nil {
  182. existing.Title = *input.Title
  183. }
  184. if input.Content != nil {
  185. existing.Content = *input.Content
  186. }
  187. if input.UserID != nil {
  188. userID, err := toID(*input.UserID)
  189. if err != nil {
  190. return nil, fmt.Errorf("invalid user ID: %w", err)
  191. }
  192. existing.UserID = userID
  193. }
  194. if input.ServiceID != nil {
  195. serviceID, err := toID(*input.ServiceID)
  196. if err != nil {
  197. return nil, fmt.Errorf("invalid service ID: %w", err)
  198. }
  199. existing.ServiceID = serviceID
  200. }
  201. if err := r.DB.Save(&existing).Error; err != nil {
  202. return nil, fmt.Errorf("failed to update note: %w", err)
  203. }
  204. logging.LogMutation(ctx, "UPDATE", "NOTE", existing.Title)
  205. return convertNote(existing), nil
  206. }
  207. // DeleteNote is the resolver for the deleteNote field.
  208. func (r *mutationResolver) DeleteNote(ctx context.Context, id string) (bool, error) {
  209. // Auth check
  210. if !auth.IsAuthenticated(ctx) {
  211. return false, errors.New("unauthorized: authentication required")
  212. }
  213. if !auth.HasPermission(ctx, "note:delete") {
  214. return false, errors.New("unauthorized: missing note:delete permission")
  215. }
  216. noteID, err := toID(id)
  217. if err != nil {
  218. return false, fmt.Errorf("invalid note ID: %w", err)
  219. }
  220. result := r.DB.Delete(&models.Note{}, noteID)
  221. if result.Error != nil {
  222. return false, fmt.Errorf("failed to delete note: %w", result.Error)
  223. }
  224. logging.LogMutation(ctx, "DELETE", "NOTE", id)
  225. return result.RowsAffected > 0, nil
  226. }
  227. // CreateRole is the resolver for the createRole field.
  228. func (r *mutationResolver) CreateRole(ctx context.Context, input model.NewRole) (*model.Role, error) {
  229. // Auth check
  230. if !auth.IsAuthenticated(ctx) {
  231. return nil, errors.New("unauthorized: authentication required")
  232. }
  233. permissions := make([]models.Permission, len(input.Permissions))
  234. for i, permIDStr := range input.Permissions {
  235. permID, err := toID(permIDStr)
  236. if err != nil {
  237. return nil, fmt.Errorf("invalid permission ID: %w", err)
  238. }
  239. var perm models.Permission
  240. if err := r.DB.First(&perm, permID).Error; err != nil {
  241. return nil, fmt.Errorf("permission not found: %w", err)
  242. }
  243. permissions[i] = perm
  244. }
  245. role := models.Role{
  246. Name: input.Name,
  247. Description: input.Description,
  248. Permissions: permissions,
  249. }
  250. if err := r.DB.Create(&role).Error; err != nil {
  251. return nil, fmt.Errorf("failed to create role: %w", err)
  252. }
  253. logging.LogMutation(ctx, "CREATE", "ROLE", role.Name)
  254. return convertRole(role), nil
  255. }
  256. // UpdateRole is the resolver for the updateRole field.
  257. func (r *mutationResolver) UpdateRole(ctx context.Context, id string, input model.UpdateRoleInput) (*model.Role, error) {
  258. // Auth check
  259. if !auth.IsAuthenticated(ctx) {
  260. return nil, errors.New("unauthorized: authentication required")
  261. }
  262. if !auth.HasPermission(ctx, "role:update") {
  263. return nil, errors.New("unauthorized: missing role:update permission")
  264. }
  265. roleID, err := toID(id)
  266. if err != nil {
  267. return nil, fmt.Errorf("invalid role ID: %w", err)
  268. }
  269. var existing models.Role
  270. if err := r.DB.First(&existing, roleID).Error; err != nil {
  271. return nil, fmt.Errorf("role not found: %w", err)
  272. }
  273. if input.Name != nil {
  274. existing.Name = *input.Name
  275. }
  276. if input.Description != nil {
  277. existing.Description = *input.Description
  278. }
  279. if len(input.Permissions) > 0 {
  280. permissions := make([]models.Permission, len(input.Permissions))
  281. for i, permIDStr := range input.Permissions {
  282. permID, err := toID(permIDStr)
  283. if err != nil {
  284. return nil, fmt.Errorf("invalid permission ID: %w", err)
  285. }
  286. var perm models.Permission
  287. if err := r.DB.First(&perm, permID).Error; err != nil {
  288. return nil, fmt.Errorf("permission not found: %w", err)
  289. }
  290. permissions[i] = perm
  291. }
  292. existing.Permissions = permissions
  293. }
  294. if err := r.DB.Save(&existing).Error; err != nil {
  295. return nil, fmt.Errorf("failed to update role: %w", err)
  296. }
  297. logging.LogMutation(ctx, "UPDATE", "ROLE", existing.Name)
  298. return convertRole(existing), nil
  299. }
  300. // DeleteRole is the resolver for the deleteRole field.
  301. func (r *mutationResolver) DeleteRole(ctx context.Context, id string) (bool, error) {
  302. // Auth check
  303. if !auth.IsAuthenticated(ctx) {
  304. return false, errors.New("unauthorized: authentication required")
  305. }
  306. if !auth.HasPermission(ctx, "role:delete") {
  307. return false, errors.New("unauthorized: missing role:delete permission")
  308. }
  309. roleID, err := toID(id)
  310. if err != nil {
  311. return false, fmt.Errorf("invalid role ID: %w", err)
  312. }
  313. result := r.DB.Delete(&models.Role{}, roleID)
  314. if result.Error != nil {
  315. return false, fmt.Errorf("failed to delete role: %w", result.Error)
  316. }
  317. logging.LogMutation(ctx, "DELETE", "ROLE", id)
  318. return result.RowsAffected > 0, nil
  319. }
  320. // CreatePermission is the resolver for the createPermission field.
  321. func (r *mutationResolver) CreatePermission(ctx context.Context, input model.NewPermission) (*model.Permission, error) {
  322. // Auth check
  323. if !auth.IsAuthenticated(ctx) {
  324. return nil, errors.New("unauthorized: authentication required")
  325. }
  326. permission := models.Permission{
  327. Code: input.Code,
  328. Description: input.Description,
  329. }
  330. if err := r.DB.Create(&permission).Error; err != nil {
  331. return nil, fmt.Errorf("failed to create permission: %w", err)
  332. }
  333. logging.LogMutation(ctx, "CREATE", "PERMISSION", permission.Code)
  334. return convertPermission(permission), nil
  335. }
  336. // UpdatePermission is the resolver for the updatePermission field.
  337. func (r *mutationResolver) UpdatePermission(ctx context.Context, id string, input model.UpdatePermissionInput) (*model.Permission, error) {
  338. // Auth check
  339. if !auth.IsAuthenticated(ctx) {
  340. return nil, errors.New("unauthorized: authentication required")
  341. }
  342. if !auth.HasPermission(ctx, "permission:update") {
  343. return nil, errors.New("unauthorized: missing permission:update permission")
  344. }
  345. permID, err := toID(id)
  346. if err != nil {
  347. return nil, fmt.Errorf("invalid permission ID: %w", err)
  348. }
  349. var existing models.Permission
  350. if err := r.DB.First(&existing, permID).Error; err != nil {
  351. return nil, fmt.Errorf("permission not found: %w", err)
  352. }
  353. if input.Code != nil {
  354. existing.Code = *input.Code
  355. }
  356. if input.Description != nil {
  357. existing.Description = *input.Description
  358. }
  359. if err := r.DB.Save(&existing).Error; err != nil {
  360. return nil, fmt.Errorf("failed to update permission: %w", err)
  361. }
  362. logging.LogMutation(ctx, "UPDATE", "PERMISSION", existing.Code)
  363. return convertPermission(existing), nil
  364. }
  365. // DeletePermission is the resolver for the deletePermission field.
  366. func (r *mutationResolver) DeletePermission(ctx context.Context, id string) (bool, error) {
  367. // Auth check
  368. if !auth.IsAuthenticated(ctx) {
  369. return false, errors.New("unauthorized: authentication required")
  370. }
  371. if !auth.HasPermission(ctx, "permission:delete") {
  372. return false, errors.New("unauthorized: missing permission:delete permission")
  373. }
  374. permID, err := toID(id)
  375. if err != nil {
  376. return false, fmt.Errorf("invalid permission ID: %w", err)
  377. }
  378. result := r.DB.Delete(&models.Permission{}, permID)
  379. if result.Error != nil {
  380. return false, fmt.Errorf("failed to delete permission: %w", result.Error)
  381. }
  382. logging.LogMutation(ctx, "DELETE", "PERMISSION", id)
  383. return result.RowsAffected > 0, nil
  384. }
  385. // CreateService is the resolver for the createService field.
  386. func (r *mutationResolver) CreateService(ctx context.Context, input model.NewService) (*model.Service, error) {
  387. // Auth check
  388. if !auth.IsAuthenticated(ctx) {
  389. return nil, errors.New("unauthorized: authentication required")
  390. }
  391. createdByID, err := toID(input.CreatedByID)
  392. if err != nil {
  393. return nil, fmt.Errorf("invalid created by ID: %w", err)
  394. }
  395. service := models.Service{
  396. Name: input.Name,
  397. CreatedByID: createdByID,
  398. }
  399. if input.Description != nil {
  400. service.Description = *input.Description
  401. }
  402. // Add participants
  403. for _, participantIDStr := range input.Participants {
  404. participantID, err := toID(participantIDStr)
  405. if err != nil {
  406. return nil, fmt.Errorf("invalid participant ID: %w", err)
  407. }
  408. var user models.User
  409. if err := r.DB.First(&user, participantID).Error; err != nil {
  410. return nil, fmt.Errorf("participant not found: %w", err)
  411. }
  412. service.Participants = append(service.Participants, user)
  413. }
  414. if err := r.DB.Create(&service).Error; err != nil {
  415. return nil, fmt.Errorf("failed to create service: %w", err)
  416. }
  417. // Reload with associations
  418. r.DB.Preload("CreatedBy").Preload("Participants").Preload("Tasks").First(&service, service.ID)
  419. logging.LogMutation(ctx, "CREATE", "SERVICE", service.Name)
  420. return convertService(service), nil
  421. }
  422. // UpdateService is the resolver for the updateService field.
  423. func (r *mutationResolver) UpdateService(ctx context.Context, id string, input model.UpdateServiceInput) (*model.Service, error) {
  424. // Auth check
  425. if !auth.IsAuthenticated(ctx) {
  426. return nil, errors.New("unauthorized: authentication required")
  427. }
  428. if !auth.HasPermission(ctx, "service:update") {
  429. return nil, errors.New("unauthorized: missing service:update permission")
  430. }
  431. serviceID, err := toID(id)
  432. if err != nil {
  433. return nil, fmt.Errorf("invalid service ID: %w", err)
  434. }
  435. var existing models.Service
  436. if err := r.DB.Preload("Participants").First(&existing, serviceID).Error; err != nil {
  437. return nil, fmt.Errorf("service not found: %w", err)
  438. }
  439. if input.Name != nil {
  440. existing.Name = *input.Name
  441. }
  442. if input.Description != nil {
  443. existing.Description = *input.Description
  444. }
  445. if len(input.Participants) > 0 {
  446. participants := []models.User{}
  447. for _, participantIDStr := range input.Participants {
  448. participantID, err := toID(participantIDStr)
  449. if err != nil {
  450. return nil, fmt.Errorf("invalid participant ID: %w", err)
  451. }
  452. var user models.User
  453. if err := r.DB.First(&user, participantID).Error; err != nil {
  454. return nil, fmt.Errorf("participant not found: %w", err)
  455. }
  456. participants = append(participants, user)
  457. }
  458. existing.Participants = participants
  459. }
  460. if err := r.DB.Save(&existing).Error; err != nil {
  461. return nil, fmt.Errorf("failed to update service: %w", err)
  462. }
  463. // Reload with associations for response
  464. r.DB.Preload("CreatedBy").Preload("Participants").Preload("Tasks").First(&existing, existing.ID)
  465. logging.LogMutation(ctx, "UPDATE", "SERVICE", existing.Name)
  466. return convertService(existing), nil
  467. }
  468. // DeleteService is the resolver for the deleteService field.
  469. func (r *mutationResolver) DeleteService(ctx context.Context, id string) (bool, error) {
  470. // Auth check
  471. if !auth.IsAuthenticated(ctx) {
  472. return false, errors.New("unauthorized: authentication required")
  473. }
  474. if !auth.HasPermission(ctx, "service:delete") {
  475. return false, errors.New("unauthorized: missing service:delete permission")
  476. }
  477. serviceID, err := toID(id)
  478. if err != nil {
  479. return false, fmt.Errorf("invalid service ID: %w", err)
  480. }
  481. result := r.DB.Delete(&models.Service{}, serviceID)
  482. if result.Error != nil {
  483. return false, fmt.Errorf("failed to delete service: %w", result.Error)
  484. }
  485. logging.LogMutation(ctx, "DELETE", "SERVICE", id)
  486. return result.RowsAffected > 0, nil
  487. }
  488. // CreateTask is the resolver for the createTask field.
  489. func (r *mutationResolver) CreateTask(ctx context.Context, input model.NewTask) (*model.Task, error) {
  490. // Auth check
  491. if !auth.IsAuthenticated(ctx) {
  492. return nil, errors.New("unauthorized: authentication required")
  493. }
  494. createdByID, err := toID(input.CreatedByID)
  495. if err != nil {
  496. return nil, fmt.Errorf("invalid created by ID: %w", err)
  497. }
  498. task := models.Task{
  499. Title: input.Title,
  500. Content: input.Content,
  501. CreatedByID: createdByID,
  502. Priority: input.Priority,
  503. }
  504. if input.AssigneeID != nil {
  505. assigneeID, err := toID(*input.AssigneeID)
  506. if err != nil {
  507. return nil, fmt.Errorf("invalid assignee ID: %w", err)
  508. }
  509. task.AssigneeID = &assigneeID
  510. }
  511. if input.StatusID != nil {
  512. statusID, err := toID(*input.StatusID)
  513. if err != nil {
  514. return nil, fmt.Errorf("invalid status ID: %w", err)
  515. }
  516. task.StatusID = statusID
  517. }
  518. if input.DueDate != nil {
  519. parsedTime, parseErr := time.Parse(time.RFC3339, *input.DueDate)
  520. if parseErr != nil {
  521. return nil, fmt.Errorf("invalid due date format: %w", parseErr)
  522. }
  523. task.DueDate = &parsedTime
  524. }
  525. if err := r.DB.Create(&task).Error; err != nil {
  526. return nil, fmt.Errorf("failed to create task: %w", err)
  527. }
  528. // Reload with associations
  529. r.DB.Preload("CreatedBy").Preload("Assignee").Preload("Status").First(&task, task.ID)
  530. // Publish task created event to assignee
  531. graphqlTask := convertTask(task)
  532. r.PublishTaskEvent(graphqlTask, task.AssigneeID, "created")
  533. logging.LogMutation(ctx, "CREATE", "TASK", task.Title)
  534. return graphqlTask, nil
  535. }
  536. // UpdateTask is the resolver for the updateTask field.
  537. func (r *mutationResolver) UpdateTask(ctx context.Context, id string, input model.UpdateTaskInput) (*model.Task, error) {
  538. // Auth check
  539. if !auth.IsAuthenticated(ctx) {
  540. return nil, errors.New("unauthorized: authentication required")
  541. }
  542. if !auth.HasPermission(ctx, "task:update") {
  543. return nil, errors.New("unauthorized: missing task:update permission")
  544. }
  545. // Get current user for UpdatedBy
  546. currentUser, err := auth.CurrentUser(ctx)
  547. if err != nil {
  548. return nil, fmt.Errorf("failed to get current user: %w", err)
  549. }
  550. taskID, err := toID(id)
  551. if err != nil {
  552. return nil, fmt.Errorf("invalid task ID: %w", err)
  553. }
  554. var existing models.Task
  555. if err := r.DB.Preload("CreatedBy").Preload("Assignee").First(&existing, taskID).Error; err != nil {
  556. return nil, fmt.Errorf("task not found: %w", err)
  557. }
  558. if input.Title != nil {
  559. existing.Title = *input.Title
  560. }
  561. if input.Content != nil {
  562. existing.Content = *input.Content
  563. }
  564. if input.AssigneeID != nil {
  565. if *input.AssigneeID == "" {
  566. existing.AssigneeID = nil
  567. } else {
  568. assigneeID, err := toID(*input.AssigneeID)
  569. if err != nil {
  570. return nil, fmt.Errorf("invalid assignee ID: %w", err)
  571. }
  572. existing.AssigneeID = &assigneeID
  573. }
  574. }
  575. if input.StatusID != nil {
  576. if *input.StatusID == "" {
  577. existing.StatusID = 0
  578. } else {
  579. statusID, err := toID(*input.StatusID)
  580. if err != nil {
  581. return nil, fmt.Errorf("invalid status ID: %w", err)
  582. }
  583. existing.StatusID = statusID
  584. }
  585. }
  586. if input.DueDate != nil {
  587. if *input.DueDate == "" {
  588. existing.DueDate = nil
  589. } else {
  590. parsedTime, parseErr := time.Parse(time.RFC3339, *input.DueDate)
  591. if parseErr != nil {
  592. return nil, fmt.Errorf("invalid due date format: %w", parseErr)
  593. }
  594. existing.DueDate = &parsedTime
  595. }
  596. }
  597. if input.Priority != nil {
  598. existing.Priority = *input.Priority
  599. }
  600. // Set UpdatedByID to current user
  601. existing.UpdatedByID = currentUser.ID
  602. if err := r.DB.Save(&existing).Error; err != nil {
  603. return nil, fmt.Errorf("failed to update task: %w", err)
  604. }
  605. // Reload with associations for response
  606. r.DB.Preload("CreatedBy").Preload("UpdatedBy").Preload("Assignee").Preload("Status").First(&existing, existing.ID)
  607. // Publish task updated event to assignee
  608. graphqlTask := convertTask(existing)
  609. r.PublishTaskEvent(graphqlTask, existing.AssigneeID, "updated")
  610. logging.LogMutation(ctx, "UPDATE", "TASK", existing.Title)
  611. return graphqlTask, nil
  612. }
  613. // DeleteTask is the resolver for the deleteTask field.
  614. func (r *mutationResolver) DeleteTask(ctx context.Context, id string) (bool, error) {
  615. // Auth check
  616. if !auth.IsAuthenticated(ctx) {
  617. return false, errors.New("unauthorized: authentication required")
  618. }
  619. if !auth.HasPermission(ctx, "task:delete") {
  620. return false, errors.New("unauthorized: missing task:delete permission")
  621. }
  622. taskID, err := toID(id)
  623. if err != nil {
  624. return false, fmt.Errorf("invalid task ID: %w", err)
  625. }
  626. result := r.DB.Delete(&models.Task{}, taskID)
  627. if result.Error != nil {
  628. return false, fmt.Errorf("failed to delete task: %w", result.Error)
  629. }
  630. logging.LogMutation(ctx, "DELETE", "TASK", id)
  631. return result.RowsAffected > 0, nil
  632. }
  633. // CreateTaskStatus is the resolver for the createTaskStatus field.
  634. func (r *mutationResolver) CreateTaskStatus(ctx context.Context, input model.NewTaskStatus) (*model.TaskStatus, error) {
  635. // Auth check
  636. if !auth.IsAuthenticated(ctx) {
  637. return nil, errors.New("unauthorized: authentication required")
  638. }
  639. taskStatus := models.TaskStatus{
  640. Code: input.Code,
  641. Label: input.Label,
  642. }
  643. if err := r.DB.Create(&taskStatus).Error; err != nil {
  644. return nil, fmt.Errorf("failed to create task status: %w", err)
  645. }
  646. logging.LogMutation(ctx, "CREATE", "TASKSTATUS", taskStatus.Code)
  647. return convertTaskStatus(taskStatus), nil
  648. }
  649. // UpdateTaskStatus is the resolver for the updateTaskStatus field.
  650. func (r *mutationResolver) UpdateTaskStatus(ctx context.Context, id string, input model.UpdateTaskStatusInput) (*model.TaskStatus, error) {
  651. // Auth check
  652. if !auth.IsAuthenticated(ctx) {
  653. return nil, errors.New("unauthorized: authentication required")
  654. }
  655. if !auth.HasPermission(ctx, "taskstatus:update") {
  656. return nil, errors.New("unauthorized: missing taskstatus:update permission")
  657. }
  658. statusID, err := toID(id)
  659. if err != nil {
  660. return nil, fmt.Errorf("invalid task status ID: %w", err)
  661. }
  662. var existing models.TaskStatus
  663. if err := r.DB.First(&existing, statusID).Error; err != nil {
  664. return nil, fmt.Errorf("task status not found: %w", err)
  665. }
  666. if input.Code != nil {
  667. existing.Code = *input.Code
  668. }
  669. if input.Label != nil {
  670. existing.Label = *input.Label
  671. }
  672. if err := r.DB.Save(&existing).Error; err != nil {
  673. return nil, fmt.Errorf("failed to update task status: %w", err)
  674. }
  675. // Reload with tasks for response
  676. r.DB.Preload("Tasks").First(&existing, existing.ID)
  677. logging.LogMutation(ctx, "UPDATE", "TASKSTATUS", existing.Code)
  678. return convertTaskStatus(existing), nil
  679. }
  680. // DeleteTaskStatus is the resolver for the deleteTaskStatus field.
  681. func (r *mutationResolver) DeleteTaskStatus(ctx context.Context, id string) (bool, error) {
  682. // Auth check
  683. if !auth.IsAuthenticated(ctx) {
  684. return false, errors.New("unauthorized: authentication required")
  685. }
  686. if !auth.HasPermission(ctx, "taskstatus:delete") {
  687. return false, errors.New("unauthorized: missing taskstatus:delete permission")
  688. }
  689. statusID, err := toID(id)
  690. if err != nil {
  691. return false, fmt.Errorf("invalid task status ID: %w", err)
  692. }
  693. result := r.DB.Delete(&models.TaskStatus{}, statusID)
  694. if result.Error != nil {
  695. return false, fmt.Errorf("failed to delete task status: %w", result.Error)
  696. }
  697. logging.LogMutation(ctx, "DELETE", "TASKSTATUS", id)
  698. return result.RowsAffected > 0, nil
  699. }
  700. // CreateChannel is the resolver for the createChannel field.
  701. func (r *mutationResolver) CreateChannel(ctx context.Context, input model.NewChannel) (*model.Channel, error) {
  702. // Auth check
  703. if !auth.IsAuthenticated(ctx) {
  704. return nil, errors.New("unauthorized: authentication required")
  705. }
  706. channel := models.Channel{}
  707. for _, participantIDStr := range input.Participants {
  708. participantID, err := toID(participantIDStr)
  709. if err != nil {
  710. return nil, fmt.Errorf("invalid participant ID: %w", err)
  711. }
  712. var user models.User
  713. if err := r.DB.First(&user, participantID).Error; err != nil {
  714. return nil, fmt.Errorf("participant not found: %w", err)
  715. }
  716. channel.Participants = append(channel.Participants, user)
  717. }
  718. if err := r.DB.Create(&channel).Error; err != nil {
  719. return nil, fmt.Errorf("failed to create channel: %w", err)
  720. }
  721. // Reload with participants
  722. r.DB.Preload("Participants").First(&channel, channel.ID)
  723. logging.LogMutation(ctx, "CREATE", "CHANNEL", fmt.Sprintf("id=%d", channel.ID))
  724. return convertChannel(channel), nil
  725. }
  726. // UpdateChannel is the resolver for the updateChannel field.
  727. func (r *mutationResolver) UpdateChannel(ctx context.Context, id string, input model.UpdateChannelInput) (*model.Channel, error) {
  728. // Auth check
  729. if !auth.IsAuthenticated(ctx) {
  730. return nil, errors.New("unauthorized: authentication required")
  731. }
  732. if !auth.HasPermission(ctx, "channel:update") {
  733. return nil, errors.New("unauthorized: missing channel:update permission")
  734. }
  735. channelID, err := toID(id)
  736. if err != nil {
  737. return nil, fmt.Errorf("invalid channel ID: %w", err)
  738. }
  739. var existing models.Channel
  740. if err := r.DB.Preload("Participants").First(&existing, channelID).Error; err != nil {
  741. return nil, fmt.Errorf("channel not found: %w", err)
  742. }
  743. participants := []models.User{}
  744. for _, participantIDStr := range input.Participants {
  745. participantID, err := toID(participantIDStr)
  746. if err != nil {
  747. return nil, fmt.Errorf("invalid participant ID: %w", err)
  748. }
  749. var user models.User
  750. if err := r.DB.First(&user, participantID).Error; err != nil {
  751. return nil, fmt.Errorf("participant not found: %w", err)
  752. }
  753. participants = append(participants, user)
  754. }
  755. existing.Participants = participants
  756. if err := r.DB.Save(&existing).Error; err != nil {
  757. return nil, fmt.Errorf("failed to update channel: %w", err)
  758. }
  759. logging.LogMutation(ctx, "UPDATE", "CHANNEL", id)
  760. return convertChannel(existing), nil
  761. }
  762. // DeleteChannel is the resolver for the deleteChannel field.
  763. func (r *mutationResolver) DeleteChannel(ctx context.Context, id string) (bool, error) {
  764. // Auth check
  765. if !auth.IsAuthenticated(ctx) {
  766. return false, errors.New("unauthorized: authentication required")
  767. }
  768. if !auth.HasPermission(ctx, "channel:delete") {
  769. return false, errors.New("unauthorized: missing channel:delete permission")
  770. }
  771. channelID, err := toID(id)
  772. if err != nil {
  773. return false, fmt.Errorf("invalid channel ID: %w", err)
  774. }
  775. result := r.DB.Delete(&models.Channel{}, channelID)
  776. if result.Error != nil {
  777. return false, fmt.Errorf("failed to delete channel: %w", result.Error)
  778. }
  779. logging.LogMutation(ctx, "DELETE", "CHANNEL", id)
  780. return result.RowsAffected > 0, nil
  781. }
  782. // CreateMessage is the resolver for the createMessage field.
  783. func (r *mutationResolver) CreateMessage(ctx context.Context, input model.NewMessage) (*model.Message, error) {
  784. // Auth check
  785. if !auth.IsAuthenticated(ctx) {
  786. return nil, errors.New("unauthorized: authentication required")
  787. }
  788. conversationID, err := toID(input.ConversationID)
  789. if err != nil {
  790. return nil, fmt.Errorf("invalid conversation ID: %w", err)
  791. }
  792. senderID, err := toID(input.SenderID)
  793. if err != nil {
  794. return nil, fmt.Errorf("invalid sender ID: %w", err)
  795. }
  796. message := models.Message{
  797. ConversationID: conversationID,
  798. SenderID: senderID,
  799. Content: input.Content,
  800. }
  801. if err := r.DB.Create(&message).Error; err != nil {
  802. return nil, fmt.Errorf("failed to create message: %w", err)
  803. }
  804. // Reload with associations
  805. r.DB.Preload("Sender").First(&message, message.ID)
  806. // Get channel participants for publishing the message event
  807. var channel models.Channel
  808. if err := r.DB.Preload("Participants").First(&channel, conversationID).Error; err == nil {
  809. // Build list of participant IDs (excluding the sender to prevent notification loops)
  810. participantIDs := make([]uint, 0, len(channel.Participants))
  811. for _, participant := range channel.Participants {
  812. if participant.ID != senderID {
  813. participantIDs = append(participantIDs, participant.ID)
  814. }
  815. }
  816. // Publish message event to channel participants
  817. graphqlMessage := convertMessage(message)
  818. r.PublishMessageEvent(graphqlMessage, conversationID, participantIDs)
  819. }
  820. logging.LogMutation(ctx, "CREATE", "MESSAGE", fmt.Sprintf("id=%d", message.ID))
  821. return convertMessage(message), nil
  822. }
  823. // UpdateMessage is the resolver for the updateMessage field.
  824. func (r *mutationResolver) UpdateMessage(ctx context.Context, id string, input model.UpdateMessageInput) (*model.Message, error) {
  825. // Auth check
  826. if !auth.IsAuthenticated(ctx) {
  827. return nil, errors.New("unauthorized: authentication required")
  828. }
  829. if !auth.HasPermission(ctx, "message:update") {
  830. return nil, errors.New("unauthorized: missing message:update permission")
  831. }
  832. messageID, err := toID(id)
  833. if err != nil {
  834. return nil, fmt.Errorf("invalid message ID: %w", err)
  835. }
  836. var existing models.Message
  837. if err := r.DB.Preload("Sender").First(&existing, messageID).Error; err != nil {
  838. return nil, fmt.Errorf("message not found: %w", err)
  839. }
  840. if input.ConversationID != nil {
  841. conversationID, err := toID(*input.ConversationID)
  842. if err != nil {
  843. return nil, fmt.Errorf("invalid conversation ID: %w", err)
  844. }
  845. existing.ConversationID = conversationID
  846. }
  847. if input.SenderID != nil {
  848. senderID, err := toID(*input.SenderID)
  849. if err != nil {
  850. return nil, fmt.Errorf("invalid sender ID: %w", err)
  851. }
  852. existing.SenderID = senderID
  853. }
  854. if input.Content != nil {
  855. existing.Content = *input.Content
  856. }
  857. if err := r.DB.Save(&existing).Error; err != nil {
  858. return nil, fmt.Errorf("failed to update message: %w", err)
  859. }
  860. logging.LogMutation(ctx, "UPDATE", "MESSAGE", id)
  861. return convertMessage(existing), nil
  862. }
  863. // DeleteMessage is the resolver for the deleteMessage field.
  864. func (r *mutationResolver) DeleteMessage(ctx context.Context, id string) (bool, error) {
  865. // Auth check
  866. if !auth.IsAuthenticated(ctx) {
  867. return false, errors.New("unauthorized: authentication required")
  868. }
  869. if !auth.HasPermission(ctx, "message:delete") {
  870. return false, errors.New("unauthorized: missing message:delete permission")
  871. }
  872. messageID, err := toID(id)
  873. if err != nil {
  874. return false, fmt.Errorf("invalid message ID: %w", err)
  875. }
  876. result := r.DB.Delete(&models.Message{}, messageID)
  877. if result.Error != nil {
  878. return false, fmt.Errorf("failed to delete message: %w", result.Error)
  879. }
  880. logging.LogMutation(ctx, "DELETE", "MESSAGE", id)
  881. return result.RowsAffected > 0, nil
  882. }
  883. // Users is the resolver for the users field.
  884. func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) {
  885. // Auth check
  886. if !auth.IsAuthenticated(ctx) {
  887. return nil, errors.New("unauthorized: authentication required")
  888. }
  889. var users []models.User
  890. if err := r.DB.Find(&users).Error; err != nil {
  891. return nil, fmt.Errorf("failed to fetch users: %w", err)
  892. }
  893. logging.LogQuery(ctx, "USERS", "all")
  894. return convertUsers(users), nil
  895. }
  896. // User is the resolver for the user field.
  897. func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error) {
  898. // Auth check
  899. if !auth.IsAuthenticated(ctx) {
  900. return nil, errors.New("unauthorized: authentication required")
  901. }
  902. userID, err := toID(id)
  903. if err != nil {
  904. return nil, fmt.Errorf("invalid user ID: %w", err)
  905. }
  906. var user models.User
  907. if err := r.DB.Preload("Roles.Permissions").First(&user, userID).Error; err != nil {
  908. return nil, fmt.Errorf("user not found: %w", err)
  909. }
  910. logging.LogQuery(ctx, "USER", id)
  911. return convertUser(user), nil
  912. }
  913. // Notes is the resolver for the notes field.
  914. func (r *queryResolver) Notes(ctx context.Context) ([]*model.Note, error) {
  915. // Auth check
  916. if !auth.IsAuthenticated(ctx) {
  917. return nil, errors.New("unauthorized: authentication required")
  918. }
  919. var notes []models.Note
  920. if err := r.DB.Preload("User").Preload("Service").Find(&notes).Error; err != nil {
  921. return nil, fmt.Errorf("failed to fetch notes: %w", err)
  922. }
  923. logging.LogQuery(ctx, "NOTES", "all")
  924. return convertNotes(notes), nil
  925. }
  926. // Note is the resolver for the note field.
  927. func (r *queryResolver) Note(ctx context.Context, id string) (*model.Note, error) {
  928. // Auth check
  929. if !auth.IsAuthenticated(ctx) {
  930. return nil, errors.New("unauthorized: authentication required")
  931. }
  932. noteID, err := toID(id)
  933. if err != nil {
  934. return nil, fmt.Errorf("invalid note ID: %w", err)
  935. }
  936. var note models.Note
  937. if err := r.DB.Preload("User").Preload("Service").First(&note, noteID).Error; err != nil {
  938. return nil, fmt.Errorf("note not found: %w", err)
  939. }
  940. logging.LogQuery(ctx, "NOTE", id)
  941. return convertNote(note), nil
  942. }
  943. // Roles is the resolver for the roles field.
  944. func (r *queryResolver) Roles(ctx context.Context) ([]*model.Role, error) {
  945. // Auth check
  946. if !auth.IsAuthenticated(ctx) {
  947. return nil, errors.New("unauthorized: authentication required")
  948. }
  949. var roles []models.Role
  950. if err := r.DB.Preload("Permissions").Find(&roles).Error; err != nil {
  951. return nil, fmt.Errorf("failed to fetch roles: %w", err)
  952. }
  953. logging.LogQuery(ctx, "ROLES", "all")
  954. return convertRoles(roles), nil
  955. }
  956. // Role is the resolver for the role field.
  957. func (r *queryResolver) Role(ctx context.Context, id string) (*model.Role, error) {
  958. // Auth check
  959. if !auth.IsAuthenticated(ctx) {
  960. return nil, errors.New("unauthorized: authentication required")
  961. }
  962. roleID, err := toID(id)
  963. if err != nil {
  964. return nil, fmt.Errorf("invalid role ID: %w", err)
  965. }
  966. var role models.Role
  967. if err := r.DB.Preload("Permissions").First(&role, roleID).Error; err != nil {
  968. return nil, fmt.Errorf("role not found: %w", err)
  969. }
  970. logging.LogQuery(ctx, "ROLE", id)
  971. return convertRole(role), nil
  972. }
  973. // Permissions is the resolver for the permissions field.
  974. func (r *queryResolver) Permissions(ctx context.Context) ([]*model.Permission, error) {
  975. // Auth check
  976. if !auth.IsAuthenticated(ctx) {
  977. return nil, errors.New("unauthorized: authentication required")
  978. }
  979. var perms []models.Permission
  980. if err := r.DB.Find(&perms).Error; err != nil {
  981. return nil, fmt.Errorf("failed to fetch permissions: %w", err)
  982. }
  983. logging.LogQuery(ctx, "PERMISSIONS", "all")
  984. return convertPermissions(perms), nil
  985. }
  986. // Permission is the resolver for the permission field.
  987. func (r *queryResolver) Permission(ctx context.Context, id string) (*model.Permission, error) {
  988. // Auth check
  989. if !auth.IsAuthenticated(ctx) {
  990. return nil, errors.New("unauthorized: authentication required")
  991. }
  992. permID, err := toID(id)
  993. if err != nil {
  994. return nil, fmt.Errorf("invalid permission ID: %w", err)
  995. }
  996. var perm models.Permission
  997. if err := r.DB.First(&perm, permID).Error; err != nil {
  998. return nil, fmt.Errorf("permission not found: %w", err)
  999. }
  1000. logging.LogQuery(ctx, "PERMISSION", id)
  1001. return convertPermission(perm), nil
  1002. }
  1003. // Services is the resolver for the services field.
  1004. func (r *queryResolver) Services(ctx context.Context) ([]*model.Service, error) {
  1005. // Auth check
  1006. if !auth.IsAuthenticated(ctx) {
  1007. return nil, errors.New("unauthorized: authentication required")
  1008. }
  1009. var services []models.Service
  1010. if err := r.DB.Preload("CreatedBy").Preload("Participants").Preload("Tasks").Find(&services).Error; err != nil {
  1011. return nil, fmt.Errorf("failed to fetch services: %w", err)
  1012. }
  1013. logging.LogQuery(ctx, "SERVICES", "all")
  1014. return convertServices(services), nil
  1015. }
  1016. // Service is the resolver for the service field.
  1017. func (r *queryResolver) Service(ctx context.Context, id string) (*model.Service, error) {
  1018. // Auth check
  1019. if !auth.IsAuthenticated(ctx) {
  1020. return nil, errors.New("unauthorized: authentication required")
  1021. }
  1022. serviceID, err := toID(id)
  1023. if err != nil {
  1024. return nil, fmt.Errorf("invalid service ID: %w", err)
  1025. }
  1026. var service models.Service
  1027. if err := r.DB.Preload("CreatedBy").Preload("Participants").Preload("Tasks").First(&service, serviceID).Error; err != nil {
  1028. return nil, fmt.Errorf("service not found: %w", err)
  1029. }
  1030. logging.LogQuery(ctx, "SERVICE", id)
  1031. return convertService(service), nil
  1032. }
  1033. // Tasks is the resolver for the tasks field.
  1034. func (r *queryResolver) Tasks(ctx context.Context) ([]*model.Task, error) {
  1035. // Auth check
  1036. if !auth.IsAuthenticated(ctx) {
  1037. return nil, errors.New("unauthorized: authentication required")
  1038. }
  1039. var tasks []models.Task
  1040. if err := r.DB.Preload("CreatedBy").Preload("UpdatedBy").Preload("Assignee").Preload("Status").Find(&tasks).Error; err != nil {
  1041. return nil, fmt.Errorf("failed to fetch tasks: %w", err)
  1042. }
  1043. logging.LogQuery(ctx, "TASKS", "all")
  1044. return convertTasks(tasks), nil
  1045. }
  1046. // Task is the resolver for the task field.
  1047. func (r *queryResolver) Task(ctx context.Context, id string) (*model.Task, error) {
  1048. // Auth check
  1049. if !auth.IsAuthenticated(ctx) {
  1050. return nil, errors.New("unauthorized: authentication required")
  1051. }
  1052. taskID, err := toID(id)
  1053. if err != nil {
  1054. return nil, fmt.Errorf("invalid task ID: %w", err)
  1055. }
  1056. var task models.Task
  1057. if err := r.DB.Preload("CreatedBy").Preload("UpdatedBy").Preload("Assignee").Preload("Status").First(&task, taskID).Error; err != nil {
  1058. return nil, fmt.Errorf("task not found: %w", err)
  1059. }
  1060. logging.LogQuery(ctx, "TASK", id)
  1061. return convertTask(task), nil
  1062. }
  1063. // TaskStatuses is the resolver for the taskStatuses field.
  1064. func (r *queryResolver) TaskStatuses(ctx context.Context) ([]*model.TaskStatus, error) {
  1065. // Auth check
  1066. if !auth.IsAuthenticated(ctx) {
  1067. return nil, errors.New("unauthorized: authentication required")
  1068. }
  1069. var statuses []models.TaskStatus
  1070. if err := r.DB.Preload("Tasks").Find(&statuses).Error; err != nil {
  1071. return nil, fmt.Errorf("failed to fetch task statuses: %w", err)
  1072. }
  1073. logging.LogQuery(ctx, "TASKSTATUSES", "all")
  1074. return convertTaskStatuses(statuses), nil
  1075. }
  1076. // TaskStatus
  1077. func (r *queryResolver) TaskStatus(ctx context.Context, id string) (*model.TaskStatus, error) {
  1078. // Auth check
  1079. if !auth.IsAuthenticated(ctx) {
  1080. return nil, errors.New("unauthorized: authentication required")
  1081. }
  1082. statusID, err := toID(id)
  1083. if err != nil {
  1084. return nil, fmt.Errorf("invalid task status ID: %w", err)
  1085. }
  1086. var status models.TaskStatus
  1087. if err := r.DB.Preload("Tasks").First(&status, statusID).Error; err != nil {
  1088. return nil, fmt.Errorf("task status not found: %w", err)
  1089. }
  1090. logging.LogQuery(ctx, "TASKSTATUS", id)
  1091. return convertTaskStatus(status), nil
  1092. }
  1093. // Channels is the resolver for the channels field.
  1094. func (r *queryResolver) Channels(ctx context.Context) ([]*model.Channel, error) {
  1095. // Auth check
  1096. if !auth.IsAuthenticated(ctx) {
  1097. return nil, errors.New("unauthorized: authentication required")
  1098. }
  1099. var channels []models.Channel
  1100. if err := r.DB.Preload("Participants").Find(&channels).Error; err != nil {
  1101. return nil, fmt.Errorf("failed to fetch channels: %w", err)
  1102. }
  1103. logging.LogQuery(ctx, "CHANNELS", "all")
  1104. return convertChannels(channels), nil
  1105. }
  1106. // Channel is the resolver for the channel field.
  1107. func (r *queryResolver) Channel(ctx context.Context, id string) (*model.Channel, error) {
  1108. // Auth check
  1109. if !auth.IsAuthenticated(ctx) {
  1110. return nil, errors.New("unauthorized: authentication required")
  1111. }
  1112. channelID, err := toID(id)
  1113. if err != nil {
  1114. return nil, fmt.Errorf("invalid channel ID: %w", err)
  1115. }
  1116. var channel models.Channel
  1117. if err := r.DB.Preload("Participants").First(&channel, channelID).Error; err != nil {
  1118. return nil, fmt.Errorf("channel not found: %w", err)
  1119. }
  1120. logging.LogQuery(ctx, "CHANNEL", id)
  1121. return convertChannel(channel), nil
  1122. }
  1123. // Messages is the resolver for the messages field.
  1124. func (r *queryResolver) Messages(ctx context.Context) ([]*model.Message, error) {
  1125. // Auth check
  1126. if !auth.IsAuthenticated(ctx) {
  1127. return nil, errors.New("unauthorized: authentication required")
  1128. }
  1129. var messages []models.Message
  1130. if err := r.DB.Preload("Sender").Find(&messages).Error; err != nil {
  1131. return nil, fmt.Errorf("failed to fetch messages: %w", err)
  1132. }
  1133. logging.LogQuery(ctx, "MESSAGES", "all")
  1134. return convertMessages(messages), nil
  1135. }
  1136. // Message is the resolver for the message field.
  1137. func (r *queryResolver) Message(ctx context.Context, id string) (*model.Message, error) {
  1138. // Auth check
  1139. if !auth.IsAuthenticated(ctx) {
  1140. return nil, errors.New("unauthorized: authentication required")
  1141. }
  1142. messageID, err := toID(id)
  1143. if err != nil {
  1144. return nil, fmt.Errorf("invalid message ID: %w", err)
  1145. }
  1146. var message models.Message
  1147. if err := r.DB.Preload("Sender").First(&message, messageID).Error; err != nil {
  1148. return nil, fmt.Errorf("message not found: %w", err)
  1149. }
  1150. logging.LogQuery(ctx, "MESSAGE", id)
  1151. return convertMessage(message), nil
  1152. }
  1153. // TaskCreated is the resolver for the taskCreated field.
  1154. // Users only receive events for tasks where they are the assignee.
  1155. func (r *subscriptionResolver) TaskCreated(ctx context.Context) (<-chan *model.Task, error) {
  1156. // Get current user
  1157. user, err := auth.CurrentUser(ctx)
  1158. if err != nil {
  1159. return nil, errors.New("unauthorized: authentication required")
  1160. }
  1161. // Subscribe to task events
  1162. eventChan := r.SubscribeToTasks(user.ID)
  1163. // Create output channel
  1164. outputChan := make(chan *model.Task, 10)
  1165. // Start goroutine to filter and forward events
  1166. go func() {
  1167. defer close(outputChan)
  1168. for {
  1169. select {
  1170. case <-ctx.Done():
  1171. return
  1172. case event, ok := <-eventChan:
  1173. if !ok {
  1174. return
  1175. }
  1176. // Only forward "created" events
  1177. if event.EventType == "created" && event.Task != nil {
  1178. select {
  1179. case outputChan <- event.Task:
  1180. default:
  1181. // Channel full, skip
  1182. }
  1183. }
  1184. }
  1185. }
  1186. }()
  1187. return outputChan, nil
  1188. }
  1189. // TaskUpdated is the resolver for the taskUpdated field.
  1190. // Users only receive events for tasks where they are the assignee.
  1191. func (r *subscriptionResolver) TaskUpdated(ctx context.Context) (<-chan *model.Task, error) {
  1192. // Get current user
  1193. user, err := auth.CurrentUser(ctx)
  1194. if err != nil {
  1195. return nil, errors.New("unauthorized: authentication required")
  1196. }
  1197. // Subscribe to task events
  1198. eventChan := r.SubscribeToTasks(user.ID)
  1199. // Create output channel
  1200. outputChan := make(chan *model.Task, 10)
  1201. // Start goroutine to filter and forward events
  1202. go func() {
  1203. defer close(outputChan)
  1204. for {
  1205. select {
  1206. case <-ctx.Done():
  1207. return
  1208. case event, ok := <-eventChan:
  1209. if !ok {
  1210. return
  1211. }
  1212. // Only forward "updated" events
  1213. if event.EventType == "updated" && event.Task != nil {
  1214. select {
  1215. case outputChan <- event.Task:
  1216. default:
  1217. // Channel full, skip
  1218. }
  1219. }
  1220. }
  1221. }
  1222. }()
  1223. return outputChan, nil
  1224. }
  1225. // TaskDeleted is the resolver for the taskDeleted field.
  1226. // Users only receive events for tasks where they are the assignee.
  1227. func (r *subscriptionResolver) TaskDeleted(ctx context.Context) (<-chan *model.Task, error) {
  1228. // Get current user
  1229. user, err := auth.CurrentUser(ctx)
  1230. if err != nil {
  1231. return nil, errors.New("unauthorized: authentication required")
  1232. }
  1233. // Subscribe to task events
  1234. eventChan := r.SubscribeToTasks(user.ID)
  1235. // Create output channel
  1236. outputChan := make(chan *model.Task, 10)
  1237. // Start goroutine to filter and forward events
  1238. go func() {
  1239. defer close(outputChan)
  1240. for {
  1241. select {
  1242. case <-ctx.Done():
  1243. return
  1244. case event, ok := <-eventChan:
  1245. if !ok {
  1246. return
  1247. }
  1248. // Only forward "deleted" events
  1249. if event.EventType == "deleted" && event.Task != nil {
  1250. select {
  1251. case outputChan <- event.Task:
  1252. default:
  1253. // Channel full, skip
  1254. }
  1255. }
  1256. }
  1257. }
  1258. }()
  1259. return outputChan, nil
  1260. }
  1261. // MessageAdded is the resolver for the messageAdded field.
  1262. // Users only receive events for messages in channels where they are participants.
  1263. func (r *subscriptionResolver) MessageAdded(ctx context.Context) (<-chan *model.Message, error) {
  1264. // Get current user
  1265. user, err := auth.CurrentUser(ctx)
  1266. if err != nil {
  1267. return nil, errors.New("unauthorized: authentication required")
  1268. }
  1269. // Subscribe to message events
  1270. eventChan := r.SubscribeToMessages(user.ID)
  1271. // Create output channel
  1272. outputChan := make(chan *model.Message, 10)
  1273. // Start goroutine to filter and forward events
  1274. go func() {
  1275. defer close(outputChan)
  1276. for {
  1277. select {
  1278. case <-ctx.Done():
  1279. return
  1280. case event, ok := <-eventChan:
  1281. if !ok {
  1282. return
  1283. }
  1284. // Check if user is in the participant list
  1285. isParticipant := false
  1286. for _, participantID := range event.ParticipantIDs {
  1287. if participantID == user.ID {
  1288. isParticipant = true
  1289. break
  1290. }
  1291. }
  1292. if isParticipant && event.Message != nil {
  1293. select {
  1294. case outputChan <- event.Message:
  1295. default:
  1296. // Channel full, skip
  1297. }
  1298. }
  1299. }
  1300. }
  1301. }()
  1302. return outputChan, nil
  1303. }
  1304. // Mutation returns MutationResolver implementation.
  1305. func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }
  1306. // Query returns QueryResolver implementation.
  1307. func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }
  1308. // Subscription returns SubscriptionResolver implementation.
  1309. func (r *Resolver) Subscription() SubscriptionResolver { return &subscriptionResolver{r} }
  1310. type mutationResolver struct{ *Resolver }
  1311. type queryResolver struct{ *Resolver }
  1312. type subscriptionResolver struct{ *Resolver }