@@ -686,8 +686,7 @@ userNotifyFeature serverEnv@ServerEnv{serverBaseURI, serverCron}
686
686
users <- queryGetUserDb
687
687
688
688
revisionsAndUploads <- collectRevisionsAndUploads trimLastTime now
689
- revisionUploadNotifications <- foldM (genRevUploadList notifyPrefs) Map. empty revisionsAndUploads
690
- let revisionUploadEmails = foldMap (describeRevision users trimLastTime now) <$> revisionUploadNotifications
689
+ revisionUploadNotifications <- concatMapM (genRevUploadList notifyPrefs trimLastTime now) revisionsAndUploads
691
690
692
691
groupActions <- collectAdminActions trimLastTime now
693
692
groupActionNotifications <- foldM (genGroupUploadList notifyPrefs) Map. empty groupActions
@@ -709,13 +708,15 @@ userNotifyFeature serverEnv@ServerEnv{serverBaseURI, serverCron}
709
708
emails <-
710
709
getNotificationEmails serverEnv userDetailsFeature users
711
710
( foldr1 (Map. unionWith (<>) )
712
- [ revisionUploadEmails
713
- , groupActionEmails
711
+ [ groupActionEmails
714
712
, docReportEmails
715
713
, tagProposalEmails
716
714
]
717
715
, dependencyEmails
718
- )
716
+ ) $
717
+ concat
718
+ [ revisionUploadNotifications
719
+ ]
719
720
mapM_ sendNotifyEmailAndDelay emails
720
721
721
722
updateState notifyState (SetNotifyTime now)
@@ -762,25 +763,39 @@ userNotifyFeature serverEnv@ServerEnv{serverBaseURI, serverCron}
762
763
writeMemState tagProposalLog Map. empty
763
764
pure $ Map. toList logs
764
765
765
- genRevUploadList notifyPrefs mp pkg = do
766
+ genRevUploadList notifyPrefs earlier now pkg = do
766
767
pkgIndex <- queryGetPackageIndex
767
768
let actor = pkgLatestUploadUser pkg
768
769
isRevision = pkgNumRevisions pkg > 1
769
770
pkgName = packageName . pkgInfoId $ pkg
770
771
mbLatest = listToMaybe . take 1 . reverse $ PackageIndex. lookupPackageName pkgIndex pkgName
771
772
isLatestVersion = maybe False (\ x -> pkgInfoId pkg == pkgInfoId x) mbLatest
772
- addNotification uid m =
773
- if not (notifyOptOut npref) &&
774
- (isRevision &&
775
- ( notifyRevisionRange npref == NotifyAllVersions ||
776
- ((notifyRevisionRange npref == NotifyNewestVersion ) && isLatestVersion))
777
- ||
778
- not isRevision && notifyUpload npref)
779
- then Map. insertWith (++) uid [pkg] m
780
- else m
781
- where npref = fromMaybe defaultNotifyPrefs (Map. lookup uid notifyPrefs)
782
773
maintainers <- queryUserGroup $ maintainersGroup (packageName . pkgInfoId $ pkg)
783
- return $ foldr addNotification mp (toList (delete actor maintainers))
774
+ pure . flip mapMaybe (toList maintainers) $ \ uid ->
775
+ fmap (uid,) $ do
776
+ let NotifyPref {.. } = fromMaybe defaultNotifyPrefs (Map. lookup uid notifyPrefs)
777
+ guard $ uid /= actor
778
+ guard $ not notifyOptOut
779
+ if isRevision
780
+ then do
781
+ guard $
782
+ notifyRevisionRange == NotifyAllVersions ||
783
+ (notifyRevisionRange == NotifyNewestVersion && isLatestVersion)
784
+ Just
785
+ NotifyNewRevision
786
+ { notifyPackageId = pkgInfoId pkg
787
+ , notifyRevisions =
788
+ filter (\ (t, _) -> earlier < t && t <= now)
789
+ . map snd
790
+ . Vec. toList
791
+ $ pkgMetadataRevisions pkg
792
+ }
793
+ else do
794
+ guard notifyUpload
795
+ Just
796
+ NotifyNewVersion
797
+ { notifyPackageInfo = pkg
798
+ }
784
799
785
800
genGroupUploadList notifyPrefs mp ga =
786
801
let (actor,gdesc) = case ga of (_,uid,Admin_GroupAddUser _ gd,_) -> (uid, gd)
@@ -817,18 +832,6 @@ userNotifyFeature serverEnv@ServerEnv{serverBaseURI, serverCron}
817
832
Map. mapKeys (, pid) <$>
818
833
getUserNotificationsOnRelease (queryUserGroup . maintainersGroup) idx revIdx queryGetUserNotifyPref pid
819
834
820
- describeRevision users earlier now pkg
821
- | pkgNumRevisions pkg <= 1 =
822
- EmailContentParagraph $
823
- " Package upload, " <> renderPkgLink (pkgInfoId pkg) <> " , by " <>
824
- formatTimeUser users (pkgLatestUploadTime pkg) (pkgLatestUploadUser pkg)
825
- | otherwise =
826
- EmailContentParagraph (" Package metadata revision(s), " <> renderPkgLink (pkgInfoId pkg) <> " :" )
827
- <> EmailContentList (map (uncurry (formatTimeUser users) . snd ) recentRevs)
828
- where
829
- revs = reverse $ Vec. toList (pkgMetadataRevisions pkg)
830
- recentRevs = filter ((\ x -> x > earlier && x <= now) . fst . snd ) revs
831
-
832
835
describeGroupAction users (time, uid, act, reason) =
833
836
fmap
834
837
( \ message ->
@@ -906,6 +909,15 @@ userNotifyFeature serverEnv@ServerEnv{serverBaseURI, serverCron}
906
909
-- delay sending out emails, because ???
907
910
threadDelay 250000
908
911
912
+ data Notification
913
+ = NotifyNewVersion
914
+ { notifyPackageInfo :: PkgInfo
915
+ }
916
+ | NotifyNewRevision
917
+ { notifyPackageId :: PackageId
918
+ , notifyRevisions :: [UploadInfo ]
919
+ }
920
+
909
921
-- | Notifications in the same group are batched in the same email.
910
922
--
911
923
-- TODO: How often do multiple notifications come in at once? Maybe it's
@@ -921,14 +933,17 @@ getNotificationEmails
921
933
-> UserDetailsFeature
922
934
-> Users. Users
923
935
-> (Map UserId EmailContent , Map (UserId , PackageId ) EmailContent )
936
+ -> [(UserId , Notification )]
924
937
-> IO [Mail ]
925
938
getNotificationEmails
926
939
ServerEnv {serverBaseURI}
927
940
UserDetailsFeature {queryUserDetails}
928
941
allUsers
929
- (generalEmails, dependencyUpdateEmails) = do
930
- let userIds = Set. fromList . Map. keys $ generalEmails <> Map. mapKeys fst dependencyUpdateEmails
931
- userIdToDetails <- Map. mapMaybe id <$> fromSetM queryUserDetails userIds
942
+ (generalEmails, dependencyUpdateEmails)
943
+ notifications = do
944
+ let userIds = Set. fromList $ map fst notifications
945
+ let userIds' = Set. fromList . Map. keys $ generalEmails <> Map. mapKeys fst dependencyUpdateEmails
946
+ userIdToDetails <- Map. mapMaybe id <$> fromSetM queryUserDetails (userIds <> userIds')
932
947
933
948
pure $
934
949
let emails =
@@ -940,6 +955,8 @@ getNotificationEmails
940
955
. Map. mapKeys fst
941
956
. Map. mapWithKey (\ (_, pkg) emailContent -> (emailContent, DependencyNotification pkg))
942
957
$ dependencyUpdateEmails
958
+ , flip mapMaybe notifications $ \ (uid, notif) ->
959
+ fmap (uid,) $ renderNotification notif
943
960
]
944
961
in flip mapMaybe (Map. toList emails) $ \ ((uid, group), emailContent) ->
945
962
case uid `Map.lookup` userIdToDetails of
@@ -994,7 +1011,50 @@ getNotificationEmails
994
1011
]
995
1012
}
996
1013
1014
+ {- ---- Render notifications -----}
1015
+
1016
+ renderNotification :: Notification -> Maybe (EmailContent , NotificationGroup )
1017
+ renderNotification = \ case
1018
+ NotifyNewVersion {.. } ->
1019
+ generalNotification $
1020
+ renderNotifyNewVersion
1021
+ notifyPackageInfo
1022
+ NotifyNewRevision {.. } ->
1023
+ generalNotification $
1024
+ renderNotifyNewRevision
1025
+ notifyPackageId
1026
+ notifyRevisions
1027
+ where
1028
+ generalNotification emailContent = Just (emailContent, GeneralNotification )
1029
+
1030
+ renderNotifyNewVersion pkg =
1031
+ EmailContentParagraph $
1032
+ " Package upload, " <> renderPkgLink (pkgInfoId pkg) <> " , by " <>
1033
+ renderUserTime (pkgLatestUploadUser pkg) (pkgLatestUploadTime pkg)
1034
+
1035
+ renderNotifyNewRevision pkg revs =
1036
+ EmailContentParagraph (" Package metadata revision(s), " <> renderPkgLink pkg <> " :" )
1037
+ <> EmailContentList (map (uncurry $ flip renderUserTime) $ sortOn (Down . fst ) revs)
1038
+
1039
+ {- ---- Rendering helpers -----}
1040
+
1041
+ renderPkgLink pkg =
1042
+ EmailContentLink
1043
+ (T. pack $ display pkg)
1044
+ serverBaseURI
1045
+ { uriPath = " /package/" <> display (packageName pkg) <> " -" <> display (packageVersion pkg)
1046
+ }
1047
+
1048
+ renderUser = emailContentDisplay . Users. userIdToName allUsers
1049
+
1050
+ renderTime = emailContentStr . formatTime defaultTimeLocale " %c"
1051
+
1052
+ renderUserTime u t = renderUser u <> " [" <> renderTime t <> " ]"
1053
+
997
1054
{- ---- Utilities -----}
998
1055
999
1056
fromSetM :: Monad m => (k -> m v ) -> Set k -> m (Map k v )
1000
1057
fromSetM f = traverse id . Map. fromSet f
1058
+
1059
+ concatMapM :: Monad m => (a -> m [b ]) -> [a ] -> m [b ]
1060
+ concatMapM f = fmap concat . mapM f
0 commit comments