Skip to content

Commit

Permalink
Merge pull request #345 from NIHGOV/gh-152-org-owner-card
Browse files Browse the repository at this point in the history
GH-152: Add an Org Owner Card for members
  • Loading branch information
petersonjdNIH authored Sep 2, 2023
2 parents cc87493 + 536959c commit eb459cb
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 53 deletions.
32 changes: 32 additions & 0 deletions business/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,38 @@ export class Organization {
return this.getMembers(memberOptions);
}

async getOwnersCardData() {
const [linkedOrgAdmins, unlinkedOrgAdmins] = await Promise.all([
this.getLinkedMembers({ role: OrganizationMembershipRoleQuery.Admin }),
this.getUnlinkedMembers({ role: OrganizationMembershipRoleQuery.Admin }),
]);

// clean up admin data for the front end
const organizationAdmins = Array.prototype
.concat(linkedOrgAdmins, unlinkedOrgAdmins)
.reduce((acc, admin) => {
const { member, link } = admin;

// linked and unlinked admins return slightly different data structures
const login = member ? member.login : admin.login;
const avatar_url = member ? member.avatar_url : admin.avatar_url;
// fallback to corporateUsername if corporateMailAddress is not available
const mailAddress = link ? link.corporateMailAddress || link.corporateUsername : undefined;
const primaryName = link ? link.corporateDisplayName || link.corporateUsername : login;

acc.push({
login,
mailAddress,
avatar_url,
primaryName,
});

return acc;
}, []);

return organizationAdmins;
}

async getAuditLog(options?: IGetOrganizationAuditLogOptions): Promise<GitHubAuditLogEntry[]> {
options = options || {};
const operations = throwIfNotGitHubCapable(this._operations);
Expand Down
3 changes: 2 additions & 1 deletion routes/org/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import express, { Router } from 'express';
import asyncHandler from 'express-async-handler';
const router: Router = Router();

import { getProviders } from '../../transitional';
import { IAggregateUserSummary } from '../../business/user/aggregate';
import { TeamJoinApprovalEntity } from '../../entities/teamJoinApproval/teamJoinApproval';
Expand Down Expand Up @@ -97,6 +96,7 @@ router.get(
const organization = req.organization;
const username = req.individualContext.getGitHubIdentity().username;
const individualContext = req.individualContext;
const organizationAdmins = await organization.getOwnersCardData();
const results = {
orgUser: organization.memberFromEntity(await organization.getDetails()),
isMembershipPublic: await organization.checkPublicMembership(username),
Expand All @@ -105,6 +105,7 @@ router.get(
isSudoer: false, // if (results.isAdministrator && results.isAdministrator === true) { results.isSudoer = true;
teamsMaintainedHash: null,
pendingApprovals: null as TeamJoinApprovalEntity[],
organizationAdmins,
};
results.organizationOverview = await individualContext.aggregations.getAggregatedOrganizationOverview(
organization
Expand Down
28 changes: 2 additions & 26 deletions routes/org/join.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,36 +86,12 @@ async function showOrgJoinDetails(req: ReposAppRequest) {
// this implementation as close to the default org get route as possible
const { individualContext, organization } = req;

const [linkedOrgAdmins, unlinkedOrgAdmins, orgDetails, organizationOverview] = await Promise.all([
organization.getLinkedMembers({ role: OrganizationMembershipRoleQuery.Admin }),
organization.getUnlinkedMembers({ role: OrganizationMembershipRoleQuery.Admin }),
const [orgDetails, organizationOverview, organizationAdmins] = await Promise.all([
organization.getDetails(),
individualContext.aggregations.getAggregatedOrganizationOverview(organization),
organization.getOwnersCardData(),
]);

// clean up admin data for the front end
const organizationAdmins = Array.prototype
.concat(linkedOrgAdmins, unlinkedOrgAdmins)
.reduce((acc, admin) => {
const { member, link } = admin;

// linked and unlinked admins return slightly different data structures
const login = member ? member.login : admin.login;
const avatar_url = member ? member.avatar_url : admin.avatar_url;
// fallback to corporateUsername if corporateMailAddress is not available
const mailAddress = link ? link.corporateMailAddress || link.corporateUsername : undefined;
const primaryName = link ? link.corporateDisplayName || link.corporateUsername : login;

acc.push({
login,
mailAddress,
avatar_url,
primaryName,
});

return acc;
}, []);

const results = {
orgUser: organization.memberFromEntity(orgDetails),
orgDetails, //org details from GitHub
Expand Down
2 changes: 1 addition & 1 deletion routes/org/repos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ router.get(
currentManagementChain,
repo,
repository,
repoAdmins: await repository.getAdmins(),
repoAdmins: await repository.getAdmins(false, false),
// permissions: slicePermissionsForView(filterSystemTeams(teamsFilterType.systemTeamsExcluded, systemTeams, permissions)),
// systemPermissions: slicePermissionsForView(filterSystemTeams(teamsFilterType.systemTeamsOnly, systemTeams, permissions)),
// collaborators: sliceCollaboratorsForView(collaborators),
Expand Down
30 changes: 30 additions & 0 deletions views/nih/mixins.pug
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,33 @@ mixin repositoryAdminCards(admins, maxCards = 5)
a(href='/people?q=' + admin.login)= admin.login
- var title = admin.adminType == "Org Admin" ? organization.name + ' organization owner' : repo.name + 'direct repo owner'
.label.label-info(title=title, style='margin-left: 5px; cursor: default')= admin.adminType


//- Renders organization owner card
//- admins: user objects with login, avatar_url, primaryName
//- maxCards: Maximum number of cards to render
mixin orgAdminCards(organizationAdmins, maxCards = 5)
ul.list-unstyled
- var admins = organizationAdmins
- var cardsToShow = Math.min(admins.length, maxCards)
- for (var i = 0; i < cardsToShow; i++)
- var admin = admins[i]
li(style='vertical-align:top;width:370px')
ul.list-inline
if admin.avatar_url
li(style='vertical-align:top;margin-top:12px;padding-right:3px'): img(
alt=admin.login,
src=admin.avatar_url + '&s=96',
style='width:36px;height:36px;')
li
ul.list-unstyled(style='margin-right:16px')
li: h5(style='margin-bottom:.3em')
a(href='/people?q=' + admin.login)= admin.primaryName
.label.label-info(title=organization.name + ' organization owner', style='margin-left: 5px; cursor: default') Owner
ul.list-inline
if admin.primaryName != admin.login
li: p(style='font-size: .8em')
a(href='https://github.com/' + admin.login, target='_new', style='color: black; text-decoration:none')= admin.login
if admin.mailAddress
li: a(href='mailto:' + admin.mailAddress, title='Send email to ' + admin.mailAddress)
!= octicon('mail', 16)
3 changes: 3 additions & 0 deletions views/org/index.pug
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ block content
h2
| &infin;&nbsp;
small Public
hr
h3 Owners
+orgAdminCards(accountInfo.organizationAdmins, 5)

hr
p
Expand Down
25 changes: 1 addition & 24 deletions views/org/publicView.pug
Original file line number Diff line number Diff line change
Expand Up @@ -129,27 +129,4 @@ block content
!= octicon('alert', 17)
= 'Invitation Required'
p Access to this organization requires an invitation from one of the following administrators.
ul.list-unstyled
- var admins = organizationAdmins
- var adminCount = admins.length
- for (var i = 0; i < adminCount; i++)
- var admin = admins[i]
li(style='vertical-align:top;width:370px')
ul.list-inline
if admin.avatar_url
li(style='vertical-align:top;margin-top:12px;padding-right:3px'): img(
alt=admin.login,
src=admin.avatar_url + '&s=96',
style='width:36px;height:36px;')
li
ul.list-unstyled(style='margin-right:16px')
li: h5(style='margin-bottom:.3em')
a(href='/people?q=' + admin.login)= admin.primaryName
.label.label-info(title=organization.name + ' organization owner', style='margin-left: 5px; cursor: default') Owner
ul.list-inline
if admin.primaryName != admin.login
li: p(style='font-size: .8em')
a(href='https://github.com/' + admin.login, target='_new', style='color: black; text-decoration:none')= admin.login
if admin.mailAddress
li: a(href='mailto:' + admin.mailAddress, title='Send email to ' + admin.mailAddress)
!= octicon('mail', 16)
+orgAdminCards(organizationAdmins, 5)
2 changes: 1 addition & 1 deletion views/repos/repo.pug
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ block content

hr

h4 Repository Admins
if repoAdmins
h4 Repository Admins
+repositoryAdminCards(repoAdmins)
//- Disabling this function as it is high risk: uses GHEC enterprise admin PAT and makes repo public outside of Org owner involvement
//- if repoPermissions.allowAdministration && repo.private === true
Expand Down

0 comments on commit eb459cb

Please sign in to comment.