@@ -15,59 +15,7 @@
1515{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
1616
1717
18−module Data.Query (
19− Schema,
20− createTables,
21− getPosts,
22− -- getUser,
23− getUsers,
24− getAllUsers,
25− getLastPosts,
26− getPostsForUser,
27− Limit,
28− publishPost,
29− getChannelPosts,
30− updateChannel,
31− createNewChannel,
32− getAllChannels,
33− getAnonymousChannelPosts,
34− deleteNamedChannel,
35− HasUsers(..),
36− wrapIntoUsers,
37− ResponseWithUsers(..),
38− getTags,
39− getDialogs,
40− getMessagesInUserChat,
41− getMessagesInGroupChat,
42− sendMessage,
43− createGroupChat,
44− updateGroupChat,
45− leaveGroupChat,
46− getGroupChatForUser,
47− getFaculty,
48− updateFaculty,
49− getFacultyFromQuery,
50− getUserWithEmail,
51− createToken,
52− validateToken,
53− invalidateToken,
54− tryVerifyToken,
55− getVerifiedToken,
56− UserCreation(..),
57− createUser,
58− tryActivateToken,
59− deactivateToken,
60− searchUsers,
61− searchTags,
62− updateUser,
63− UserUpdateRow(..),
64− killAllTokens,
65− channelCountForUser,
66− pruneAuth,
67− searchChannels,
68− isValidFaculty,
69− groupChatIsValidForUser
70− ) where
18+module Data.Query where
7119
7220import Squeal.PostgreSQL
7321import Data.User
@@ -110,6 +58,9 @@ import qualified Data.Vector as V
11058import Server.Auth.Token
11159import Server.Error
11260import Data.Text.Validator
61+import Control.Monad.Except
62+import Control.Monad.IO.Class
63+import Crypto.Hash.SHA512 (hash)
11364
11465-- MARK: Documentation
11566
@@ -122,14 +73,17 @@ instance (ToSample r) => ToSample (ResponseWithUsers r) where
12273type TableEndo schema params from grouping = TableExpression schema params from grouping ->
12374 TableExpression schema params from grouping
12475
76+-- |Функция, возвращаяющая запрос на посты, прменяя к нему данный ндоморфизм.
12577postsQ :: TableEndo Schema params _ 'Ungrouped -> Query Schema params _
12678postsQ te = selectStar $ te (from $ table #posts)
12779
80+-- |Функция, возвращающая посты
12881postViewT :: TableEndo Schema params _ 'Ungrouped -> TableExpression Schema params _ 'Ungrouped
12982postViewT te = from $ subquery (postsQ te `As` #posts) &
13083 innerJoin (table #postElements)
13184 (#posts ! #postRowId .== #postElements ! #rowElementId)
13285
86+-- |Функция, возвращающая запрос на поста, примення два промежуточных эндоморфизма к таблице.
13387getPostQ
13488 :: TableEndo Schema params _ 'Ungrouped
13589 -- ^ PostRowResponse endo
@@ -172,6 +126,7 @@ getPostQ oTe te = select (
172126-- let rows = M.fromList $ map (tupleBy $ quoteRowId . head) . groupBy ((==) `on` quoteRowId) . sortBy (compare `on` quoteRowId) $ rows'
173127-- return $ M.lookup qId rows >>= rowsToQuote rows
174128
129+-- |Запрос, возвращающий пользователя по адресу почты.
175130getUserWithEmailQ :: Query Schema (TuplePG (Only UserEmail)) (RowPG (User FacultyUrl))
176131getUserWithEmailQ = select (
177132 #userRowId `as` #userId :*
@@ -184,6 +139,7 @@ getUserWithEmailQ = select (
184139 where_ (#userRowEmail .== param @1) &
185140 where_ (notNull #userRowIsValidated))
186141
142+-- |Запрос, возвращающий подтвержденных пользователей.
187143verifiedUserIdsQ :: [UserId] -> Maybe (Query Schema '[] (RowPG (Only UserId)))
188144verifiedUserIdsQ uIds = case idsToColumn uIds of
189145 Just idQ -> Just $ select (#users ! #userRowId `as` #fromOnly) $ from (subquery (idQ `As` #ids) &
@@ -191,6 +147,7 @@ verifiedUserIdsQ uIds = case idsToColumn uIds of
191147 (#ids ! #id .== #users ! #userRowId))
192148 Nothing -> Nothing
193149
150+-- |Запрос, возвращающий пользователей с данными идентификаторами.
194151getUsersQ :: [UserId] -> Maybe (Query Schema '[] (RowPG UserRow))
195152getUsersQ uIds = case idsToColumn uIds of
196153 Just idQ -> Just $ select (
@@ -216,6 +173,7 @@ getUsersQ uIds = case idsToColumn uIds of
216173 where_ (notNull $ #users ! #userRowIsValidated))
217174 Nothing -> Nothing
218175
176+-- |Запорс, возвращающий всех пользователей.
219177getAllUsersQ :: Query Schema '[] (RowPG UserRow)
220178getAllUsersQ = select (
221179 #users ! #userRowId :*
@@ -237,6 +195,7 @@ getAllUsersQ = select (
237195 (#users ! #userRowFacultyUrl .== #faculties ! #facultyUrl))&
238196 where_ (notNull $ #users ! #userRowIsValidated))
239197
198+-- |Запрос, возвращающий все посты по идентификатору.
240199getPostsByIdQ :: [PostId] -> Maybe (Query Schema '[] (RowPG PostRowResponse))
241200getPostsByIdQ pIds = case idsToColumn pIds of
242201 Just idQ -> Just $ selectDotStar #posts $ from (subquery (idQ `As` #ids) &
@@ -245,14 +204,17 @@ getPostsByIdQ pIds = case idsToColumn pIds of
245204 (#ids ! #id .== #posts ! #postRowId))
246205 Nothing -> Nothing
247206
207+-- |Ограничение
248208type Limit = Word64
249209
210+-- |SQL оператор IS NOT FALSE
250211isNotFalse
251212 :: Expression schema from grouping params ('Null ty)
252213 -- ^ possibly @NULL@
253214 -> Condition schema from grouping params
254215isNotFalse x = UnsafeExpression $ renderExpression x <+> "IS NOT FALSE"
255216
217+-- |Запрос, возвращающий последние посты.
256218getLastPostsQ
257219 :: TableEndo _ _ _ _
258220 -> Limit
@@ -267,12 +229,14 @@ getLastPostsQ te lim dir = getPostQ
267229 where
268230 ((.^), order) = directionToOperator dir
269231
232+-- |Запрос, возвращающий последние посты для данного пользователя.
270233getLastNPostsForUserQ
271234 :: Limit
272235 -> P.PaginationDirection
273236 -> Query Schema (TuplePG (Maybe PostId, UserId)) (RowPG PostRowResponse)
274237getLastNPostsForUserQ = getLastPostsQ $ where_ (#posts ! #postRowAuthorId .== param @2)
275238
239+-- |Запрос на создание поста.
276240createPostRowQ :: Manipulation Schema (TuplePG (UserId, Vector Text)) (RowPG (Only PostId))
277241createPostRowQ = insertRow #posts
278242 (Default `as` #postRowId :*
@@ -282,6 +246,7 @@ createPostRowQ = insertRow #posts
282246 OnConflictDoRaise
283247 (Returning $ #postRowId `as` #fromOnly)
284248
249+-- |Запрос на создание элементов постов.
285250createPostElementRowsQ :: Manipulation Schema (TuplePG (PostElementRow Post)) '[]
286251createPostElementRowsQ = insertRow_ #postElements
287252 (Set (param @1) `as` #rowElementId :*
@@ -292,11 +257,13 @@ createPostElementRowsQ = insertRow_ #postElements
292257 Set (param @6) `as` #rowElementQuote :*
293258 Set (param @7) `as` #rowElementAttachment)
294259
260+-- |Запрос, возвращающий канал для данного пользователя.
295261getChannelForUserQ :: Query Schema (TuplePG (UserId, NamedChannelId)) (RowPG NamedChannelFull)
296262getChannelForUserQ = selectStar $
297263 from (table #channels) &
298264 where_ (#namedChannelFullOwner .== param @1 .&& #namedChannelFullId .== param @2)
299265
266+-- |Запрос, обновляющий данные о пользователе.
300267updateUserQ :: Manipulation Schema (TuplePG (UserUpdateRow)) (RowPG (Only UserId))
301268updateUserQ = update #users (
302269 Same `as` #userRowId :*
@@ -309,12 +276,14 @@ updateUserQ = update #users (
309276 (#userRowId .== param @1)
310277 (Returning $ #userRowId `as` #fromOnly)
311278
279+-- |Запрос, возвращающий каналы пользователя.
312280getAllChannelsForUserQ :: Query Schema (TuplePG (Only UserId)) (RowPG NamedChannelFull)
313281getAllChannelsForUserQ = selectStar $
314282 from (table #channels) &
315283 where_ (#namedChannelFullOwner .== param @1) &
316284 orderBy [#namedChannelFullId & Desc]
317285
286+-- |Запрос, осуществляющий поиск по каналам данного пользователя.
318287searchChannelsForUserQ :: Query Schema (TuplePG (UserId, Text)) (RowPG NamedChannelFull)
319288searchChannelsForUserQ = selectStar $
320289 from (table #channels) &
@@ -331,6 +300,7 @@ searchChannelsForUserQ = selectStar $
331300 vector1 = tsVector' #namedChannelFullName
332301 query = tsQuery' (param @2)
333302
303+-- |Запрос, обновляющий факультет.
334304updateFacultyQ :: Manipulation Schema (TuplePG Faculty) '[]
335305updateFacultyQ = insertRow #faculties
336306 (
@@ -345,10 +315,12 @@ updateFacultyQ = insertRow #faculties
345315 (OnConflictDoNothing)
346316 (Returning Nil)
347317
318+-- |Запрос, возвращающий факультет.
348319getFacultyQ :: Query Schema (TuplePG (Only Text)) (RowPG Faculty)
349320getFacultyQ = selectStar (from (table #faculties) &
350321 where_ (#facultyUrl .== param @1))
351322
323+-- |Запрос на создание нового именованного канала.
352324createNamedChannelQ :: Manipulation Schema (TuplePG NamedChannelCreation) (RowPG (Only NamedChannelId))
353325createNamedChannelQ = insertRow #channels
354326 (
@@ -361,14 +333,17 @@ createNamedChannelQ = insertRow #channels
361333 OnConflictDoRaise
362334 (Returning $ #namedChannelFullId `as` #fromOnly)
363335
336+-- |Запрос, возвращающий количество каналов у данного пользователя.
364337countChannelsQ :: Query Schema (TuplePG (Only UserId)) (RowPG (Only Int64))
365338countChannelsQ = select (countStar `as` #fromOnly) (from (table #channels) &
366339 where_ (#namedChannelFullOwner .== param @1) &
367340 groupBy #namedChannelFullOwner)
368341
342+-- |Запрос, удаляющий канал у данного пользователя.
369343deleteNamedChannelQ :: Manipulation Schema (TuplePG (Only NamedChannelId)) '[]
370344deleteNamedChannelQ = deleteFrom_ #channels (#namedChannelFullId .== param @1)
371345
346+-- |Запрос, обновляющий именованный канал.
372347updateNamedChannelQ :: Manipulation Schema (TuplePG NamedChannelFull) '[]
373348updateNamedChannelQ = update_ #channels
374349 (
@@ -380,6 +355,7 @@ updateNamedChannelQ = update_ #channels
380355 )
381356 (#namedChannelFullOwner .== param @2 .&& #namedChannelFullId .== param @1)
382357
358+-- |Запрос на каналы пользователя.
383359getChannelPostsQ
384360 :: Limit
385361 -> P.PaginationDirection
@@ -398,10 +374,12 @@ getChannelPostsQ lim dir uIds tags = getLastPostsQ
398374 Just uIdsQ -> (`in_` uIdsQ)
399375 Nothing -> const $ false
400376
377+-- |Запрос на все хэштеги.
401378getTagsQ :: Query Schema params (RowPG (Only String))
402379getTagsQ = selectDistinct (unsafeFunction "unnest" #postRowTags `as` #fromOnly) $
403380 from (table #posts)
404381
382+-- |Запорс на создание сообщения.
405383createMessageQ :: Manipulation
406384 Schema
407385 (TuplePG (UserId, Maybe GroupChatId, Maybe UserId, Jsonb (PostElement (MessageCreation))))
@@ -418,6 +396,7 @@ createMessageQ = insertRow #messages
418396 OnConflictDoRaise
419397 (Returning $ #messageStorageId `as` #fromOnly)
420398
399+-- |Запрос на создание фантомного сообщения.
421400createPhantomMessageQ :: Manipulation Schema (TuplePG (Only GroupChatId)) '[]
422401createPhantomMessageQ = insertRow_ #messages
423402 (
@@ -429,6 +408,7 @@ createPhantomMessageQ = insertRow_ #messages
429408 Set currentTimestamp `as` #messageStorageTime
430409 )
431410
411+-- |Запрос на создание групповой беседы.
432412createGroupChatQ :: Manipulation Schema (TuplePG GroupChatCreation) (RowPG (Only GroupChatId))
433413createGroupChatQ = insertRow #groupChats
434414 (
@@ -439,6 +419,7 @@ createGroupChatQ = insertRow #groupChats
439419 OnConflictDoRaise
440420 (Returning $ #groupChatId `as` #fromOnly)
441421
422+-- |Запрос на обновление групповой беседы.
442423updateGroupChatQ :: Manipulation Schema (TuplePG GroupChat) '[]
443424updateGroupChatQ = update_ #groupChats
444425 (
@@ -448,23 +429,27 @@ updateGroupChatQ = update_ #groupChats
448429 )
449430 (#groupChatId .== param @1)
450431
432+-- |Тип строки, воозвращаемой в промежуточном запросе на все диалоги.
451433type ChatsQueryResponse = '[
452434 "messageId" ::: 'NotNull (PG UserId),
453435 "messageGroupId" ::: 'Null (PG UserId),
454436 "messageUserId" ::: 'Null (PG UserId)
455437 ]
456438
439+-- |Тип оператора сравнения.
457440type ConditionOp schema from grouping params nullity0 nullity1 (ty :: PGType)
458441 = Expression schema from grouping params (nullity0 ty)
459442 -> Expression schema from grouping params (nullity1 ty)
460443 -> Condition schema from grouping params
461444
445+-- |Тип параметров на запрос диалогов.
462446type ChatQueryParams = TuplePG
463447 ( UserId
464448 , Maybe String -- Just UserId as String
465449 , Maybe MessageId
466450 )
467451
452+-- |Запрос на все диалоги.
468453getChatsQ
469454 :: Limit
470455 -> P.PaginationDirection
@@ -525,6 +510,7 @@ getChatsQ lim dir = select (
525510 where_ (isNotNull #messageStorageDestinationGroupId) &
526511 groupBy #messageStorageDestinationGroupId
527512
513+-- |Запрос на сообщения.
528514getMessagesQ
529515 :: Limit
530516 -> P.PaginationDirection
@@ -544,6 +530,7 @@ getMessagesQ lim dir = selectStar (from (table #messages) &
544530 where
545531 ((.^), order) = directionToOperator dir
546532
533+-- |Запрос на сообщения в групповой беседе.
547534getGroupMessagesQ
548535 :: Limit
549536 -> P.PaginationDirection
@@ -562,12 +549,14 @@ getGroupMessagesQ lim dir = selectStar (from (table #messages) &
562549 ((.^), order) = directionToOperator dir
563550
564551-- String -- user id as String
552+-- |Запрос на групповую беседу для данного пользователя.
565553getGroupChatForUserQ :: Query Schema (TuplePG (String, GroupChatId)) (RowPG GroupChat)
566554getGroupChatForUserQ = selectStar $
567555 (from (table #groupChats)) &
568556 where_ (#groupChatId .== param @2) &
569557 where_ (#groupChatUsers .? param @1)
570558
559+-- |Запрос на поиск факультета.
571560getFacultySearchResultQ :: Query Schema (TuplePG (Only Text)) (RowPG Faculty)
572561getFacultySearchResultQ = selectStar (from (table #faculties) &
573562 where_ (vector @@ query) &
@@ -588,6 +577,7 @@ getFacultySearchResultQ = selectStar (from (table #faculties) &
588577 #facultyPath])
589578 query = tsQuery "russian" (param @1)
590579
580+-- |Запрос на поиск пользователя.
591581searchUsersQ :: Query Schema (TuplePG (Only Text)) (RowPG UserRow)
592582searchUsersQ = select (
593583 #users ! #userRowId :*
@@ -619,19 +609,21 @@ searchUsersQ = select (
619609 ])
620610 query = tsQuery' (param @1)
621611
612+-- |Запрос на теги по популярности.
622613tagsByFrquencyQ :: Query Schema params '["tag" ::: 'NotNull (PG Text), "count" ::: 'NotNull 'PGint8]
623614tagsByFrquencyQ = select
624615 (#fromOnly `as` #tag :* count #fromOnly `as` #count)
625616 (from (subquery $ getTagsQ `As` #tt) &
626617 groupBy #fromOnly)
627618
619+-- |Запрос на данной количество самых популярных тегов.
628620getNpopularTagsQ :: Limit -> Query Schema param (RowPG (Only Text))
629621getNpopularTagsQ lim = select (#tag `as` #fromOnly)
630622 (from (subquery $ tagsByFrquencyQ `As` #tt) &
631623 orderBy [#count & Desc] &
632624 limit lim)
633625
634−
626+-- |Запрос на поиск по тегам.
635627searchTagsQ :: Query Schema (TuplePG (Only Text)) (RowPG (Only Text))
636628searchTagsQ = select (#tag `as` #fromOnly) $
637629 from (subquery (tagsByFrquencyQ `As` #tt)) &
@@ -642,6 +634,7 @@ searchTagsQ = select (#tag `as` #fromOnly) $
642634 query = tsQuery' (param @1)
643635 vector = tsVector' #tag
644636
637+-- |PostgreSQL функция ts_rank_cd
645638tsRankCd
646639 :: Expression schema from grouping params ('NotNull 'PGtext)
647640 -> Expression schema from grouping params ('NotNull 'PGtext)
@@ -649,6 +642,7 @@ tsRankCd
649642tsRankCd vector query = UnsafeExpression $
650643 "ts_rank_cd" <> parenthesized (commaSeparated ["ARRAY[1,1,1,1]", renderExpression vector, renderExpression query, "2|4|8|16|32"])
651644
645+-- |PostgreSQL функция ts_vector
652646tsVector
653647 :: ByteString -- ^ Language
654648 -> Expression schema from grouping params ('NotNull 'PGtext)
@@ -656,12 +650,14 @@ tsVector
656650tsVector lang x = UnsafeExpression $
657651 "to_tsvector" <> parenthesized (commaSeparated [singleQuotedUtf8 lang, renderExpression x])
658652
653+-- |PostgreSQL функция ts_vector без языка.
659654tsVector'
660655 :: Expression schema from grouping params ('NotNull 'PGtext)
661656 -> Expression schema from grouping params ('NotNull 'PGtext)
662657tsVector' x = UnsafeExpression $
663658 "to_tsvector" <> parenthesized (renderExpression x)
664659
660+-- |PostgreSQL функция ts_query.
665661tsQuery
666662 :: ByteString -- ^ Language
667663 -> Expression schema from grouping params ('NotNull 'PGtext)
@@ -669,32 +665,38 @@ tsQuery
669665tsQuery lang x = UnsafeExpression $
670666 "to_tsquery" <> parenthesized (commaSeparated [singleQuotedUtf8 lang, renderExpression x])
671667
668+-- |PostgreSQL функция ts_query без языка.
672669tsQuery'
673670 :: Expression schema from grouping params ('NotNull 'PGtext)
674671 -> Expression schema from grouping params ('NotNull 'PGtext)
675672tsQuery' x = UnsafeExpression $
676673 "to_tsquery" <> parenthesized (renderExpression x)
677674
675+-- |PostgreSQL функция array_to_string
678676arrayToText
679677 :: Expression schema from grouping params ('NotNull ('PGvararray ('NotNull 'PGtext)))
680678 -> Expression schema from grouping params ('NotNull 'PGtext)
681679arrayToText x = UnsafeExpression $
682680 "array_to_string" <> parenthesized (commaSeparated [renderExpression x, "' '"])
683681
682+-- |PostgreSQL оператор @@
684683(@@)
685684 :: Expression schema from grouping params (nullity0 'PGtext)
686685 -> Expression schema from grouping params (nullity1 'PGtext)
687686 -> Expression schema from grouping params (nullity2 'PGbool)
688687(@@) = unsafeBinaryOp "@@"
689688
689+-- |Пробел.
690690space :: Expression schema from grouping params ('NotNull 'PGtext)
691691space = UnsafeExpression "' '"
692692
693+-- |Функция, переводящая список варажений текста в одно выражение текста через пробел.
693694textArrayToText
694695 :: [Expression schema from grouping params ('NotNull 'PGtext)]
695696 -> Expression schema from grouping params ('NotNull 'PGtext)
696697textArrayToText = fold . L.intersperse space
697698
699+-- |Запрос, создающий пользователя.
698700createUserQ :: Manipulation Schema (TuplePG UserCreation) (RowPG (Only UserId))
699701createUserQ = insertRow #users (
700702 Default `as` #userRowId :*
@@ -707,12 +709,13 @@ createUserQ = insertRow #users (
707709 OnConflictDoRaise
708710 (Returning (#userRowId `as` #fromOnly))
709711
712+-- |Запрос, удалющий пользователей, которые не подтвердили свой профиль.
710713removeUnverifiedUserQ :: Manipulation Schema (TuplePG (Only UserEmail)) '[]
711714removeUnverifiedUserQ = deleteFrom_ #users
712715 (#userRowEmail .== param @1 .&&
713716 (not_ . notNull $ #userRowIsValidated))
714717
715−
718+-- |Запрос, создающий токен.
716719createTokenQ :: Manipulation Schema (TuplePG Token) '[]
717720createTokenQ = insertRow_ #tokens (
718721 Set (param @1) `as` #tokenUserId :*
@@ -725,6 +728,7 @@ createTokenQ = insertRow_ #tokens (
725728 Set (param @8) `as` #tokenDeactivationCode
726729 )
727730
731+-- |Запрос, обновляющий токен.
728732updateTokenQ :: Manipulation Schema (TuplePG Token) '[]
729733updateTokenQ = update_ #tokens (
730734 Same `as` #tokenUserId :*
@@ -737,10 +741,12 @@ updateTokenQ = update_ #tokens (
737741 Set (param @8) `as` #tokenDeactivationCode)
738742 (#tokenUserId .== param @1 .&& #tokenValue .== param @2)
739743
744+-- |Запрос, удалющий токен.
740745deleteTokenQ :: Manipulation Schema (TuplePG (UserId, ByteString)) '[]
741746deleteTokenQ = deleteFrom_ #tokens
742747 (#tokenUserId .== param @1 .&& #tokenValue .== param @2)
743748
749+-- |Запрос, подтверждающий профиль пользователя.
744750validateUserQ :: Manipulation Schema (TuplePG (Only UserId)) '[]
745751validateUserQ = update_ #users (
746752 Same `as` #userRowId :*
@@ -752,22 +758,26 @@ validateUserQ = update_ #users (
752758 Set true `as` #userRowIsValidated)
753759 (#userRowId .== param @1)
754760
761+-- |Запрос, возвращающий токен.
755762getTokenQ :: Query Schema (TuplePG (UserId, ByteString)) (RowPG Token)
756763getTokenQ = selectStar (from (table #tokens) &
757764 where_ (#tokenUserId .== param @1 .&&
758765 #tokenValue .== param @2))
759766
767+-- |Запрос, возвращающий токен по хэшу кода активации.
760768getTokenActivationQ :: Query Schema (TuplePG (UserId, ByteString)) (RowPG Token)
761769getTokenActivationQ = selectStar (from (table #tokens) &
762770 where_ (#tokenUserId .== param @1 .&&
763771 #tokenActivationCode .== param @2))
764772
773+-- |Запрос, даективирующий токен.
765774deactivateTokenQ :: Manipulation Schema (TuplePG (UserId, ByteString)) (RowPG (Only Text))
766775deactivateTokenQ = deleteFrom #tokens
767776 (#tokenUserId .== param @1 .&&
768777 #tokenDeactivationCode .== param @2)
769778 (Returning (#tokenUserAgent `as` #fromOnly))
770779
780+-- |Запрос, возвращающий подтвержденный токен.
771781getVerifiedTokenQ :: Query Schema (TuplePG (UserId, ByteString)) (RowPG Token)
772782getVerifiedTokenQ = selectStar (from (table #tokens) &
773783 where_ (#tokenUserId .== param @1 .&&
@@ -775,14 +785,17 @@ getVerifiedTokenQ = selectStar (from (table #tokens) &
775785 isNull #tokenVerificationCode .&&
776786 currentTimestamp .< #tokenExpiryDate))
777787
788+-- |Запрос, даективирующий все токены для данного пользователя.
778789killAllTokensQ :: Manipulation Schema (TuplePG (Only UserId)) '[]
779790killAllTokensQ = deleteFrom_ #tokens
780791 (#tokenUserId .== param @1)
781792
793+-- |Запрос, удаляющий недействительные токены.
782794pruneDeadTokensQ :: Manipulation Schema '[] '[]
783795pruneDeadTokensQ = deleteFrom_ #tokens
784796 (#tokenExpiryDate .< currentTimestamp)
785797
798+-- |Запрос, удаляющий неактивированных пользователей.
786799pruneGhostUsersQ :: Manipulation Schema '[] '[]
787800pruneGhostUsersQ = deleteFrom_ #users
788801 ((not_ . in_ #userRowId $ select (#tokens ! #tokenUserId `as` #id) (from $ table #tokens)) .&&
@@ -798,11 +811,17 @@ instance HasValidatableText UserCreation where
798811 userCreationUserFaculty,
799812 userCreationUserEmail]
800813
814+-- |Объект для создания пользователя.
801815data UserCreation = UserCreation {
816+ -- |Имя.
802817 userCreationFirstName :: Text,
818+ -- |Отчество.
803819 userCreationMiddleName :: Text,
820+ -- |Фамилия.
804821 userCreationLastName :: Text,
822+ -- |Факультет.
805823 userCreationUserFaculty :: FacultyUrl,
824+ -- |Адрес почты.
806825 userCreationUserEmail :: Text
807826} deriving (GHC.Generic, SOP.Generic, SOP.HasDatatypeInfo)
808827
@@ -819,42 +838,62 @@ instance FromJSON UserCreation where
819838 parseJSON = withObject "user creation" $ \e ->
820839 UserCreation <$> e .: "firstName" <*> e .: "middleName" <*> e .: "lastName" <*> e .: "faculty" <*> e .: "email"
821840
841+-- |Объект для обновления пользователя.
822842data UserUpdateRow = UserUpdateRow {
843+ -- |Идентификатор пользователя.
823844 userUpdateRowId :: UserId,
845+ -- |Имя.
824846 userUpdateRowFirstName :: Text,
847+ -- |Отчество.
825848 userUpdateRowMiddleName :: Text,
849+ -- |Фамилия.
826850 userUpdateRowLastName :: Text,
851+ -- |Факультет.
827852 userUpdateRowUserFaculty :: FacultyUrl
828853} deriving (GHC.Generic, SOP.Generic, SOP.HasDatatypeInfo)
829854
830−
855+-- |Объект для создания канала.
831856data NamedChannelCreation = NamedChannelCreation {
857+ -- |Владелец канала.
832858 namedChannelCreationOwner :: UserId,
859+ -- |Название канала.
833860 namedChannelCreationName :: Text,
861+ -- |Теги в канале.
834862 namedChannelCreationTags :: Vector Text,
863+ -- |Люди в канале.
835864 namedChannelCreationPeopleIds :: Vector UserId
836865} deriving (GHC.Generic, SOP.Generic, SOP.HasDatatypeInfo)
837866
867+-- |Функция, добавлющая в структуру пользователя.
838868addUserToChannelCreate :: UserId -> NamedChannelCreationRequest -> NamedChannelCreation
839869addUserToChannelCreate uId (NamedChannelCreationRequest cName cTags cPeople) = NamedChannelCreation uId cName cTags cPeople
840870
871+-- |Полный объект канала.
841872data NamedChannelFull = NamedChannelFull {
873+ -- |Идентификатор.
842874 namedChannelFullId :: NamedChannelId,
875+ -- |Владелец.
843876 namedChannelFullOwner :: UserId,
877+ -- |Название.
844878 namedChannelFullName :: Text,
879+ -- |Теги.
845880 namedChannelFullTags :: Vector Text,
881+ -- |пользователи.
846882 namedChannelFullPeopleIds :: Vector UserId
847883} deriving GHC.Generic
848884
849885instance SOP.Generic NamedChannelFull
850886instance SOP.HasDatatypeInfo NamedChannelFull
851887
888+-- |Добавляет в структуру пользователя.
852889addUserToChannelUpdate :: UserId -> NamedChannel UserId -> NamedChannelFull
853890addUserToChannelUpdate uId (NamedChannel cId cName cTags cPeople) = NamedChannelFull cId uId cName cTags cPeople
854891
892+-- |Убирает пользователя из структуры.
855893removeUserFromChannel :: NamedChannelFull -> NamedChannel UserId
856894removeUserFromChannel (NamedChannelFull cId _ cName cTags cPeople) = NamedChannel cId cName cTags cPeople
857895
896+-- |Возвращаает канал для данного человека.
858897getChannelForUser :: UserId -> NamedChannelId -> StaticPQ NamedChannelFull
859898getChannelForUser uId cId = do
860899 channel <- runQueryParams getChannelForUserQ (uId, cId) >>= firstRow
@@ -862,7 +901,7 @@ getChannelForUser uId cId = do
862901 (Just c) -> return c
863902 Nothing -> lift $ S.throwError S.err404
864903
865−-- TODO: Reject bad requests. Should be binary.
904+-- |Проверяет, существует ли пользователь.
866905verifyUsers :: [UserId] -> StaticPQ ()
867906verifyUsers uIds =
868907 case verifiedUserIdsQ uIds of
@@ -871,6 +910,7 @@ verifyUsers uIds =
871910 when (length us /= length uIds) $ lift $ S.throwError impossibleContent
872911 Nothing -> return ()
873912
913+-- |Удаляет групповую беседу.
874914deleteGroupChat :: GroupChatId -> StaticPQ ()
875915deleteGroupChat gId = do
876916 _ <- manipulateParams deleteGroupChatQ (Only gId)
@@ -885,6 +925,7 @@ deleteGroupChat gId = do
885925 (#messageStorageDestinationGroupId .== param @1)
886926
887927-- NOTE: Not transactional
928+-- |Создает пользователя.
888929createUser :: UserCreation -> StaticPQ UserId
889930createUser creation = do
890931 _ <- manipulateParams removeUnverifiedUserQ (Only $ userCreationUserEmail creation)
@@ -894,6 +935,7 @@ createUser creation = do
894935-- MARK: FrontEnd functions
895936
896937-- Nothing <=> no user
938+-- |Возвращаает посты от данного пользователя.
897939getPostsForUser
898940 :: Maybe PostId
899941 -> Limit
@@ -904,6 +946,7 @@ getPostsForUser pId lim dir uId = do
904946 postRows <- runQueryParams (getLastNPostsForUserQ lim dir) (pId, uId) >>= getRows
905947 wrapIntoResponse (fromMaybe [] . rowsToPosts $ postRows)
906948
949+-- |Возвращаает посты по идентификатором.
907950getPosts :: [PostId] -> StaticPQ (Maybe (ResponseWithUsers [Post]))
908951getPosts pId =
909952 case getPostsByIdQ pId of
@@ -912,6 +955,7 @@ getPosts pId =
912955 rowsToPosts postRows `liftMaybe` wrapIntoResponse
913956 Nothing -> return Nothing
914957
958+-- |Возвращает последние посты.
915959getLastPosts
916960 :: Maybe PostId
917961 -> Limit
@@ -921,15 +965,19 @@ getLastPosts pId lim dir = do
921965 postRows <- runQueryParams (getLastPostsQ id lim dir) (Only pId) >>= getRows
922966 rowsToPosts postRows `liftMaybe` wrapIntoResponse
923967
968+-- |Возвращает пользователя по адресу почты.
924969getUserWithEmail :: UserEmail -> StaticPQ (Maybe (User FacultyUrl))
925970getUserWithEmail email = runQueryParams getUserWithEmailQ (Only email) >>= firstRow
926971
972+-- |возвращает пользователей по идентификаторам.
927973getUsers :: [UserId] -> StaticPQ (Maybe [User Faculty])
928974getUsers ids = getUsersQ ids `liftMaybe` (fmap (Just . map rowToUser) . (runQuery >=> getRows))
929975
976+-- |Возвращает всех пользователей.
930977getAllUsers :: StaticPQ [User Faculty]
931978getAllUsers = fmap rowToUser <$> (runQuery getAllUsersQ >>= getRows)
932979
980+-- |Публичует пост.
933981publishPost :: UserId -> PostCreation -> StaticPQ PostId
934982publishPost uId pc = commitedTransactionallyUpdate $ do
935983 pId' <- manipulateParams createPostRowQ (uId, postCreationTags pc) >>= firstRow
@@ -939,6 +987,7 @@ publishPost uId pc = commitedTransactionallyUpdate $ do
939987 return pId
940988 _ -> lift $ S.throwError S.err404
941989
990+-- |Создает канал.
942991createNewChannel :: UserId -> NamedChannelCreationRequest -> StaticPQ (Maybe NamedChannelId)
943992createNewChannel uId req = commitedTransactionallyUpdate $ do
944993 let uIds = toList $ namedChannelCreationRequestPeopleIds req
@@ -946,9 +995,11 @@ createNewChannel uId req = commitedTransactionallyUpdate $ do
946995 cId <- manipulateParams createNamedChannelQ (addUserToChannelCreate uId (req {namedChannelCreationRequestPeopleIds = fromList uIds})) >>= firstRow
947996 return $ fmap fromOnly cId
948997
998+-- |Возвращает канал для данного пользователя.
949999channelCountForUser :: UserId -> StaticPQ Int64
9501000channelCountForUser uId = (fromMaybe 0 . fmap fromOnly) <$> (runQueryParams countChannelsQ (Only uId) >>= firstRow)
9511001
1002+-- |Обновляет канал.
9521003updateChannel :: UserId -> NamedChannel UserId -> StaticPQ ()
9531004updateChannel uId req = do
9541005 let uIds = namedChannelPeopleIds req
@@ -957,17 +1008,21 @@ updateChannel uId req = do
9571008 _ <- commitedTransactionallyUpdate $ manipulateParams updateNamedChannelQ $ addUserToChannelUpdate uId (req {namedChannelPeopleIds = uIds})
9581009 return ()
9591010
1011+-- |Возвращает факультет.
9601012getFaculty :: Text -> StaticPQ Faculty
9611013getFaculty t = runQueryParams getFacultyQ (Only t) >>= firstRow >>= fromMaybe404
9621014
1015+-- |Проверяет, является ли данный факультет валидным.
9631016isValidFaculty :: FacultyUrl -> StaticPQ Bool
9641017isValidFaculty url = do
9651018 (faculty :: Maybe Faculty) <- runQueryParams getFacultyQ (Only url) >>= firstRow
9661019 return $ isJust faculty
9671020
1021+-- |Обновляет факультет.
9681022updateFaculty :: Faculty -> StaticPQ ()
9691023updateFaculty fac = void $ manipulateParams updateFacultyQ fac
9701024
1025+-- |Возвращает посты в канале.
9711026getChannelPosts
9721027 :: UserId
9731028 -> Maybe PostId
@@ -986,6 +1041,7 @@ getChannelPosts uId pId lim dir cId = do
9861041 >>= getRows
9871042 fmap (fromMaybe $ ResponseWithUsers mempty mempty) $ rowsToPosts postRows `liftMaybe` wrapIntoResponse
9881043
1044+-- |Возвращает почты в анонимном кнаале.
9891045getAnonymousChannelPosts
9901046 :: Maybe PostId
9911047 -> Limit
@@ -996,19 +1052,23 @@ getAnonymousChannelPosts pId lim dir (AnonymousChannel tags people) = do
9961052 postRows <- runQueryParams (getChannelPostsQ lim dir people tags) (Only pId) >>= getRows
9971053 fmap (fromMaybe $ ResponseWithUsers mempty mempty) $ rowsToPosts postRows `liftMaybe` wrapIntoResponse
9981054
1055+-- |Возвращает все каналы.
9991056getAllChannels :: UserId -> StaticPQ [NamedChannel UserId]
10001057getAllChannels uId = fmap (map removeUserFromChannel) $
10011058 runQueryParams getAllChannelsForUserQ (Only uId) >>= getRows
10021059
1060+-- |Удаляет именованный канал.
10031061deleteNamedChannel :: UserId -> NamedChannelId -> StaticPQ ()
10041062deleteNamedChannel uId cId = do
10051063 _ <- getChannelForUser uId cId
10061064 _ <- commitedTransactionallyUpdate $ manipulateParams deleteNamedChannelQ (Only cId)
10071065 return ()
10081066
1067+-- |Возвращает теги.
10091068getTags :: Limit -> StaticPQ [String]
10101069getTags lim = map fromOnly <$> (runQuery (getNpopularTagsQ lim) >>= getRows)
10111070
1071+-- |Возвращает диалоги.
10121072getDialogs
10131073 :: UserId
10141074 -> Maybe MessageId
@@ -1019,6 +1079,7 @@ getDialogs uId mId lim dir = do
10191079 resp <- runQueryParams (getChatsQ lim dir) (uId, Just $ show uId, mId) >>= getRows
10201080 (>>= fromMaybe500) $ (responseToDialogs uId resp `liftMaybe` wrapIntoResponse)
10211081
1082+-- |Возвращает сообщения в диалоге.
10221083getMessagesInUserChat
10231084 :: UserId
10241085 -> UserId
@@ -1030,6 +1091,7 @@ getMessagesInUserChat selfId uId mId lim dir = do
10301091 resp <- runQueryParams (getMessagesQ lim dir) (selfId, uId, mId) >>= getRows
10311092 fromMaybe500 . sequence . map restoreMessage $ resp
10321093
1094+-- |Возвращает сообщения в групповой беседе.
10331095getMessagesInGroupChat
10341096 :: UserId
10351097 -> GroupChatId
@@ -1042,6 +1104,7 @@ getMessagesInGroupChat selfId gId mId lim dir = do
10421104 resp <- runQueryParams (getGroupMessagesQ lim dir) (gId, mId) >>= getRows
10431105 return . catMaybes . map restoreMessage $ resp
10441106
1107+-- |Отправляет сообщение.
10451108sendMessage :: UserId -> MessageCreation -> StaticPQ MessageId
10461109sendMessage selfId (MessageCreation (Just gId) uId@Nothing body) = do
10471110 _ <- getGroupChatForUser selfId gId
@@ -1055,6 +1118,7 @@ sendMessage selfId (MessageCreation gId@Nothing (Just uId) body) = do
10551118 return mId
10561119sendMessage _ _ = lift $ S.throwError S.err400
10571120
1121+-- |Создает групповую беседу.
10581122createGroupChat :: UserId -> GroupChatCreation -> StaticPQ GroupChatId
10591123createGroupChat uId (GroupChatCreation (Jsonb chatUsers) name) = do
10601124 verifyUsers . M.keys $ chatUsers
@@ -1065,6 +1129,7 @@ createGroupChat uId (GroupChatCreation (Jsonb chatUsers) name) = do
10651129 _ <- manipulateParams createPhantomMessageQ (Only chatId)
10661130 return chatId
10671131
1132+-- |Обновляет групповую беседу.
10681133updateGroupChat :: UserId -> GroupChat -> StaticPQ ()
10691134updateGroupChat uId (GroupChat gId (Jsonb perms) name) = do
10701135 verifyUsers . M.keys $ perms
@@ -1075,6 +1140,7 @@ updateGroupChat uId (GroupChat gId (Jsonb perms) name) = do
10751140 let newPerms = M.insert uId userPerm perms
10761141 void $ manipulateParams updateGroupChatQ (GroupChat gId (Jsonb newPerms) name)
10771142
1143+-- |Удаляет пользователя из беседы.
10781144leaveGroupChat :: UserId -> GroupChatId -> StaticPQ ()
10791145leaveGroupChat uId gId = commitedTransactionallyUpdate $ do
10801146 gChat@(GroupChat _ (Jsonb perms) _) <- getGroupChatForUser uId gId
@@ -1083,6 +1149,7 @@ leaveGroupChat uId gId = commitedTransactionallyUpdate $ do
10831149 then deleteGroupChat gId
10841150 else void $ manipulateParams updateGroupChatQ gChat{groupChatUsers = Jsonb newPerms}
10851151
1152+-- |Возвращает беседу для пользователя.
10861153getGroupChatForUser :: UserId -> GroupChatId -> StaticPQ GroupChat
10871154getGroupChatForUser uId gId = do
10881155 chat <- runQueryParams getGroupChatForUserQ (show uId, gId) >>= firstRow
@@ -1090,15 +1157,18 @@ getGroupChatForUser uId gId = do
10901157 (Just c) -> return c
10911158 Nothing -> lift $ S.throwError S.err404
10921159
1160+-- |Проверяет, является ли данная беседа валидной для данного пользователя.
10931161groupChatIsValidForUser :: UserId -> GroupChatId -> StaticPQ Bool
10941162groupChatIsValidForUser uId gId = do
10951163 (chat :: Maybe GroupChat) <- runQueryParams getGroupChatForUserQ (show uId, gId) >>= firstRow
10961164 return $ isJust chat
10971165
1166+-- |Возвращает каналы по поисковой строке.
10981167getFacultyFromQuery :: T.Text -> StaticPQ [Faculty]
10991168getFacultyFromQuery query =
11001169 runQueryParams getFacultySearchResultQ (Only . queryFromTextAbbr $ query) >>= getRows
11011170
1171+-- |Ищет пользователей по строке.
11021172searchUsers :: T.Text -> StaticPQ [User Faculty]
11031173searchUsers query = do
11041174 unless (validateText query) $ lift $ throwError lengthExceeded
@@ -1106,37 +1176,45 @@ searchUsers query = do
11061176 then return []
11071177 else map rowToUser <$> (runQueryParams searchUsersQ (Only . queryFromText $ query) >>= getRows)
11081178
1179+-- |Ищет теги по запосу.
11091180searchTags :: T.Text -> StaticPQ [Text]
11101181searchTags "" = return []
11111182searchTags query = map fromOnly <$>
11121183 (runQueryParams searchTagsQ
11131184 (Only . (<> ":*") . T.strip $ query) >>= getRows)
11141185
1186+-- |Создает токен.
11151187createToken :: Token -> StaticPQ ()
11161188createToken token = void $ manipulateParams createTokenQ token
11171189
1190+-- |Деактивирует все токены для пользователя.
11181191killAllTokens :: UserId -> StaticPQ ()
11191192killAllTokens = void . manipulateParams killAllTokensQ . Only
11201193
1194+-- |Удаляет устаревшую информацию про авторизацию.
11211195pruneAuth :: StaticPQ ()
11221196pruneAuth = do
11231197 _ <- commitedTransactionallyUpdate . manipulate $ pruneDeadTokensQ
11241198 _ <- commitedTransactionallyUpdate . manipulate $ pruneGhostUsersQ
11251199 return ()
11261200
1201+-- |Осуществляет поиск по каналам.
11271202searchChannels :: UserId -> Text -> StaticPQ [NamedChannel UserId]
11281203searchChannels uId query = fmap (map removeUserFromChannel) $
11291204 runQueryParams searchChannelsForUserQ (uId, queryFromText query) >>= getRows
11301205
11311206-- NOTE: Not transactional
1207+-- |Проверяет, является ли токен валидным.
11321208validateToken :: Token -> StaticPQ ()
11331209validateToken token = do
11341210 void $ manipulateParams updateTokenQ token{tokenVerificationCode = Nothing, tokenActivationCode = Nothing}
11351211 void $ manipulateParams validateUserQ $ Only $ tokenUserId token
11361212
1213+-- |Даективирует токен.
11371214invalidateToken :: UserId -> ByteString -> StaticPQ ()
11381215invalidateToken uId bs = void . manipulateParams deleteTokenQ $ (uId, bs)
11391216
1217+-- |Пытается активировать токен с помощью кода.
11401218tryVerifyToken :: UserId -> ByteString -> Int -> StaticPQ (Maybe Token)
11411219tryVerifyToken uId tokenData code = commitedTransactionallyUpdate $ do
11421220 token' <- runQueryParams getTokenQ (uId, hash tokenData) >>= firstRow
@@ -1154,6 +1232,7 @@ tryVerifyToken uId tokenData code = commitedTransactionallyUpdate $ do
11541232 _ <- manipulateParams updateTokenQ newToken
11551233 return Nothing
11561234
1235+-- |Пытается активировать с помощью ключа активации.
11571236tryActivateToken :: UserId -> ByteString -> StaticPQ (Maybe Token)
11581237tryActivateToken uId activationData = do
11591238 let hData = hash activationData
@@ -1165,17 +1244,21 @@ tryActivateToken uId activationData = do
11651244 then commitedTransactionallyUpdate (validateToken token) >> (return $ Just token)
11661245 else return Nothing
11671246
1247+-- |Деактивирует токен.
11681248deactivateToken :: UserId -> ByteString -> StaticPQ (Maybe Text)
11691249deactivateToken uId dData = fmap fromOnly <$> (manipulateParams deactivateTokenQ (uId, hash dData) >>= firstRow)
11701250
1251+-- |Возвращает активированный токен.
11711252getVerifiedToken :: UserId -> ByteString -> StaticPQ (Maybe Token)
11721253getVerifiedToken uId tokenData = runQueryParams getVerifiedTokenQ (uId, hash tokenData) >>= firstRow
11731254
1255+-- |Обновляет пользователя.
11741256updateUser :: (UserUpdateRow) -> StaticPQ (Maybe UserId)
11751257updateUser user = fmap fromOnly <$> (manipulateParams updateUserQ (normalizeUser user) >>= firstRow)
11761258
11771259-- MARK: Utils
11781260
1261+-- |Нормализует поля пользователя.
11791262normalizeUser :: UserUpdateRow -> UserUpdateRow
11801263normalizeUser UserUpdateRow{..} = UserUpdateRow {
11811264 userUpdateRowId = userUpdateRowId,
@@ -1185,23 +1268,39 @@ normalizeUser UserUpdateRow{..} = UserUpdateRow {
11851268 userUpdateRowUserFaculty = T.toLower . T.strip $ userUpdateRowUserFaculty
11861269}
11871270
1271+-- |Объект пользователя для ответов с базы данных.
11881272data UserRow = UserRow {
1273+ -- |Идентификатор пользователя.
11891274 userRowId :: UserId,
1275+ -- |Имя.
11901276 userRowFirstName :: Text,
1277+ -- |Отчество.
11911278 userRowMiddleName :: Text,
1279+ -- |Фамилия.
11921280 userRowLastName :: Text,
1281+ -- |Факультет.
11931282 userRowFacultyUrl :: FacultyUrl,
1283+ -- |Почта.
11941284 userRowEmail :: Text,
1285+ -- |Был ли профиль подтвержден через почту.
11951286 userRowIsValidated :: Bool,
1287+ -- |Название факультета.
11961288 userRowFacultyName :: T.Text,
1289+ -- |Адрес сайта факультета.
11971290 userRowFacultyURL :: FacultyUrl,
1291+ -- |Вспомогательная информация о факультете.
11981292 userRowFacultyPath :: T.Text,
1293+ -- |Кампус.
11991294 userRowFacultyCampusName :: T.Text,
1295+ -- |Код Кампуса.
12001296 userRowFacultyCampusCode :: T.Text,
1297+ -- |Теги департамента.
12011298 userRowFacultyTags :: V.Vector T.Text,
1299+ -- |АДрес департамента.
12021300 userRowFacultyAddress :: T.Text
12031301} deriving (GHC.Generic, SOP.Generic, SOP.HasDatatypeInfo)
12041302
1303+-- |Функция, переводящая ответ с базы данных в пользователя.
12051304rowToUser :: UserRow -> User Faculty
12061305rowToUser UserRow{..} = User {
12071306 userId = userRowId,
@@ -1220,6 +1319,7 @@ rowToUser UserRow{..} = User {
12201319 userEmail = userRowEmail
12211320 }
12221321
1322+-- |Переводит строку в запрос с учетом аббревиатур.
12231323queryFromTextAbbr :: Text -> Text
12241324queryFromTextAbbr = T.unwords . L.intersperse "&" . map processTerm . filter (not . T.null) . T.split (not . isAlphaNum)
12251325 where
@@ -1230,12 +1330,14 @@ queryFromTextAbbr = T.unwords . L.intersperse "&" . map processTerm . filter (no
12301330 else mempty
12311331 ) <> ")"
12321332
1333+-- |Переводит строку в запорс.
12331334queryFromText :: Text -> Text
12341335queryFromText = T.unwords . L.intersperse "&" . map processTerm . filter (not . T.null) . T.split (not . isPrint)
12351336 where
12361337 processTerm :: Text -> Text
12371338 processTerm t = t <> ":*"
12381339
1340+-- |Перевод направление в оператор.
12391341directionToOperator
12401342 :: P.PaginationDirection
12411343 -> (ConditionOp schema0 from0 grouping0 params0 nullity0 nullity1 (ty :: PGType),
@@ -1248,6 +1350,7 @@ foldMaybe [] = Just []
12481350foldMaybe (Nothing : _) = Nothing
12491351foldMaybe (Just x : xs) = (x :) <$> foldMaybe xs
12501352
1353+-- |переводит элементы поста с базы данных в объект поста.
12511354rowsToPosts :: [PostRowResponse] -> Maybe [Post]
12521355rowsToPosts = foldMaybe . map rowsToPost . L.groupBy ((==) `on` postRowId)
12531356
@@ -1261,11 +1364,15 @@ idsToColumn :: [Int64] -> Maybe (Query schema params '["id" ::: 'NotNull 'PGint8
12611364idsToColumn [] = Nothing
12621365idsToColumn (i:ii) = Just $ values (unsafeIntToExpr i `as` #id) $ map ((`as` #id) . unsafeIntToExpr) ii
12631366
1367+-- |Небезопасное переведение числа в SQL выражение.
12641368unsafeIntToExpr :: Int64 -> Expression schema from grouping params ty
12651369unsafeIntToExpr = UnsafeExpression . pack . show
12661370
1371+-- |Ответ сервера с пользователями.
12671372data ResponseWithUsers r = ResponseWithUsers {
1373+ -- |Тело ответа.
12681374 response :: r,
1375+ -- |Пользователи.
12691376 users :: M.Map UserId (User Faculty)
12701377} deriving (Generic)
12711378
@@ -1296,6 +1403,7 @@ instance (Foldable t, HasUsers r) => HasUsers (t r) where
12961403instance HasUsers Post where
12971404 userSet = Set.singleton . postAuthorId
12981405
1406+-- |Оборачивает ответ в пользователей.
12991407wrapIntoUsers :: r -> Set.Set UserId -> StaticPQ (Maybe (ResponseWithUsers r))
13001408wrapIntoUsers r us
13011409 | Set.null us = return . Just $ ResponseWithUsers r M.empty