Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Share/Notifications/Queries.hs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ listNotificationHubEntryPayloads notificationUserId mayLimit mayCursor statusFil
LIMIT #{limit}
|]

hasUnreadNotifications :: UserId -> Transaction e Bool
hasUnreadNotifications :: (PG.QueryA m) => UserId -> m Bool
hasUnreadNotifications notificationUserId = do
queryExpect1Col
[sql|
Expand Down
6 changes: 3 additions & 3 deletions src/Share/Postgres/Authorization/Queries.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ module Share.Postgres.Authorization.Queries
)
where

import Share.Prelude
import Control.Lens
import Data.Set qualified as Set
import Share.IDs
import Share.Postgres qualified as PG
import Share.Postgres.IDs (CausalId)
import Share.Prelude
import Share.Web.Authorization.Types

-- | A user has access if they own the repo, or if they're a member of an org which owns it.
Expand All @@ -42,7 +42,7 @@ checkIsUserMaintainer requestingUserId codebaseOwnerUserId
)
|]

isSuperadmin :: UserId -> PG.Transaction e Bool
isSuperadmin :: (PG.QueryA m) => UserId -> m Bool
isSuperadmin uid = do
PG.queryExpect1Col
[PG.sql|
Expand Down Expand Up @@ -155,7 +155,7 @@ permissionsForProject mayUserId projectId = do
|]
<&> Set.fromList

permissionsForOrg :: Maybe UserId -> OrgId -> PG.Transaction e (Set RolePermission)
permissionsForOrg :: (PG.QueryA m) => Maybe UserId -> OrgId -> m (Set RolePermission)
permissionsForOrg mayUserId orgId = do
PG.queryListCol @RolePermission
[PG.sql|
Expand Down
10 changes: 5 additions & 5 deletions src/Share/Postgres/Queries.hs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ searchProjects caller userIdFilter (Query query) psk limit = do
pure (results <&> \(project PG.:. PG.Only handle) -> (project, handle))

-- | Returns the list of tours the user has completed.
getCompletedToursForUser :: UserId -> PG.Transaction e [TourId]
getCompletedToursForUser :: (PG.QueryA m) => UserId -> m [TourId]
getCompletedToursForUser uid = do
PG.queryListCol
[PG.sql|
Expand Down Expand Up @@ -973,13 +973,13 @@ isUnisonEmployee uid = do
|]

-- | Returns the handles of all orgs the provided user is a member of.
organizationMemberships :: UserId -> PG.Transaction e [UserHandle]
organizationMemberships :: (PG.QueryA m) => UserId -> m [OrgId]
organizationMemberships uid = do
PG.queryListCol
[PG.sql|
SELECT org_user.handle FROM users AS org_user
JOIN org_members ON organization_user_id = org_user.id
WHERE member_user_id = #{uid}
SELECT om.org_id
FROM org_members om
WHERE om.member_user_id = #{uid}
|]

releaseByProjectReleaseShortHand :: ProjectReleaseShortHand -> PG.Transaction e (Maybe (Release CausalId UserId))
Expand Down
4 changes: 2 additions & 2 deletions src/Share/Postgres/Users/Queries.hs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ searchUsersByNameOrHandlePrefix (Query prefix) usk (Limit limit) = do
Just orgId -> UnifiedOrg orgId
Nothing -> UnifiedUser userId

joinOrgIdsToUserIdsOf :: Traversal s t UserId (UserId, Maybe OrgId) -> s -> PG.Transaction e t
joinOrgIdsToUserIdsOf :: (PG.QueryA m) => Traversal s t UserId (UserId, Maybe OrgId) -> s -> m t
joinOrgIdsToUserIdsOf trav s = do
s
& asListOf trav %%~ \userIds -> do
Expand Down Expand Up @@ -342,7 +342,7 @@ allUsers = do
SELECT id FROM users
|]

userSubscriptionTier :: UserId -> PG.Transaction e PlanTier
userSubscriptionTier :: (PG.QueryA m) => UserId -> m PlanTier
userSubscriptionTier userId =
fromMaybe Free <$> do
PG.query1Col
Expand Down
2 changes: 1 addition & 1 deletion src/Share/Web/Share/DisplayInfo/Queries.hs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module Share.Web.Share.DisplayInfo.Queries (userLikeDisplayInfoOf, unifiedDisplayInfoForUserOf) where

import Share.Prelude
import Control.Lens
import Share.IDs
import Share.Postgres (Transaction)
import Share.Postgres.Users.Queries qualified as UserQ
import Share.Postgres.Users.Queries qualified as UsersQ
import Share.Prelude
import Share.Web.Share.DisplayInfo.Types
import Share.Web.Share.Orgs.Queries qualified as OrgsQ

Expand Down
36 changes: 21 additions & 15 deletions src/Share/Web/Share/Impl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import Share.Notifications.Queries qualified as NotifQ
import Share.OAuth.Session
import Share.OAuth.Types (UserId)
import Share.Postgres qualified as PG
import Share.Postgres.Authorization.Queries qualified as AuthQ
import Share.Postgres.Authorization.Queries qualified as AuthZQ
import Share.Postgres.Causal.Queries qualified as CausalQ
import Share.Postgres.IDs (CausalHash)
Expand Down Expand Up @@ -57,6 +58,7 @@ import Share.Web.Share.Contributions.Impl qualified as Contributions
import Share.Web.Share.DefinitionSearch qualified as DefinitionSearch
import Share.Web.Share.DisplayInfo.Queries qualified as DisplayInfoQ
import Share.Web.Share.DisplayInfo.Types (OrgDisplayInfo (..), UserLike (..))
import Share.Web.Share.Orgs.Queries qualified as OrgsQ
import Share.Web.Share.Projects.Impl qualified as Projects
import Share.Web.Share.Types
import Share.Web.Share.Users.API qualified as Users
Expand Down Expand Up @@ -571,22 +573,26 @@ accountInfoEndpoint :: Session -> WebApp UserAccountInfo
accountInfoEndpoint Session {sessionUserId} = do
User {user_email, user_id} <- PGO.expectUserById sessionUserId
PG.runTransaction $ do
completedTours <- Q.getCompletedToursForUser user_id
organizationMemberships <- Q.organizationMemberships user_id
isSuperadmin <- AuthZQ.isSuperadmin user_id
displayInfo <- DisplayInfoQ.unifiedDisplayInfoForUserOf id user_id
planTier <- UserQ.userSubscriptionTier user_id
hasUnreadNotifications <- NotifQ.hasUnreadNotifications user_id
pure $
UserAccountInfo
{ primaryEmail = user_email,
completedTours,
organizationMemberships,
isSuperadmin,
displayInfo,
planTier,
hasUnreadNotifications
}
memberOfOrgs <- Q.organizationMemberships user_id
PG.pipelined $ do
orgDisplayInfos <- OrgsQ.orgDisplayInfoOf traversed memberOfOrgs
orgPermissions <- for memberOfOrgs \orgId -> do
AuthQ.permissionsForOrg (Just user_id) orgId
completedTours <- Q.getCompletedToursForUser user_id
isSuperadmin <- AuthZQ.isSuperadmin user_id
planTier <- UserQ.userSubscriptionTier user_id
hasUnreadNotifications <- NotifQ.hasUnreadNotifications user_id
pure $
UserAccountInfo
{ primaryEmail = user_email,
completedTours,
organizationMemberships = zipWith OrgMembershipInfo orgDisplayInfos orgPermissions,
isSuperadmin,
displayInfo,
planTier,
hasUnreadNotifications
}

completeToursEndpoint :: Session -> NonEmpty TourId -> WebApp NoContent
completeToursEndpoint Session {sessionUserId} flows = do
Expand Down
21 changes: 20 additions & 1 deletion src/Share/Web/Share/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -277,11 +277,30 @@ instance PG.DecodeValue PlanTier where
"Pro" -> Pro
_ -> Free

data OrgMembershipInfo = OrgMembershipInfo
{ org :: OrgDisplayInfo,
permissions :: Set RolePermission
}
deriving (Show, Eq, Ord)

instance ToJSON OrgMembershipInfo where
toJSON OrgMembershipInfo {..} =
Aeson.object
[ "org" .= org,
"permissions" .= permissions
]

instance FromJSON OrgMembershipInfo where
parseJSON = Aeson.withObject "OrgMembershipInfo" $ \o -> do
org <- o Aeson..: "org"
permissions <- o Aeson..: "permissions"
pure OrgMembershipInfo {org, permissions}

data UserAccountInfo = UserAccountInfo
{ primaryEmail :: Maybe Email,
-- List of tours which the user has completed.
completedTours :: [TourId],
organizationMemberships :: [UserHandle],
organizationMemberships :: [OrgMembershipInfo],
isSuperadmin :: Bool,
planTier :: PlanTier,
displayInfo :: UnifiedDisplayInfo,
Expand Down
28 changes: 27 additions & 1 deletion transcripts/share-apis/code-browse/account.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,33 @@
"kind": "user",
"name": "The Transcript User",
"organizationMemberships": [
"unison"
{
"org": {
"isCommercial": false,
"orgId": "ORG-<UUID>",
"user": {
"avatarUrl": "https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?f=y&d=retro",
"handle": "unison",
"name": "Unison Org",
"userId": "U-<UUID>"
}
},
"permissions": [
"project:view",
"project:contribute",
"project:maintain",
"project:create",
"org:view",
"org:edit",
"team:view",
"notification_hub_entry:view",
"notification_hub_entry:update",
"notification_subscription:view",
"notification_subscription:manage",
"notification_delivery_method:view",
"notification_delivery_method:manage"
]
}
],
"planTier": "Free",
"primaryEmail": "[email protected]",
Expand Down
Loading