Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENG-6419] Share integration #2377

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Intl from 'ember-intl/services/intl';
import InstitutionModel from 'ember-osf-web/models/institution';
import SearchResultModel from 'ember-osf-web/models/search-result';
import { AttributionRoleIris } from 'ember-osf-web/models/index-card';
import { getOsfmapObjects, getSingleOsfmapValue, hasOsfmapValue } from 'ember-osf-web/packages/osfmap/jsonld';

interface ContributorsFieldArgs {
searchResult: SearchResultModel;
Expand All @@ -24,34 +25,51 @@ export default class InstitutionalObjectListContributorsField extends Component<
// Return two contributors affiliated with the institution given with highest permission levels
get topInstitutionAffiliatedContributors() {
const { searchResult, institution } = this.args;
const attributions: any[] = searchResult.resourceMetadata.qualifiedAttribution;
const {resourceMetadata} = searchResult;
const attributions: any[] = getOsfmapObjects(resourceMetadata, ['qualifiedAttribution']);
const contributors = getOsfmapObjects(resourceMetadata, ['creator']);
const institutionIris = institution.iris;

const affiliatedAttributions = attributions
.filter((attribution: any) => hasInstitutionAffiliation(attribution, institutionIris));
const adminAttributions = affiliatedAttributions
.filter(attribution => attribution.hadRole[0]['@id'] === AttributionRoleIris.Admin);
const writeAttributions = affiliatedAttributions
.filter(attribution => attribution.hadRole[0]['@id'] === AttributionRoleIris.Write);
const readAttributions = affiliatedAttributions
.filter(attribution => attribution.hadRole[0]['@id'] === AttributionRoleIris.Read);
.filter((attribution: any) => hasInstitutionAffiliation(contributors, attribution, institutionIris));
const adminAttributions = affiliatedAttributions.filter(
attribution => hasOsfmapValue(attribution, ['hadRole'], AttributionRoleIris.Admin),
);
const writeAttributions = affiliatedAttributions.filter(
attribution => hasOsfmapValue(attribution, ['hadRole'], AttributionRoleIris.Write),
);
const readAttributions = affiliatedAttributions.filter(
attribution => hasOsfmapValue(attribution, ['hadRole'], AttributionRoleIris.Read),
);

const prioritizedAttributions = adminAttributions.concat(writeAttributions, readAttributions);

return prioritizedAttributions.slice(0, 2).map((attribution: any) => {
const roleIri: AttributionRoleIris = attribution.hadRole[0]['@id'];
return prioritizedAttributions.slice(0, 2).map(attribution => {
const contributor = getContributorById(contributors, getSingleOsfmapValue(attribution, ['agent']));
const roleIri: AttributionRoleIris = getSingleOsfmapValue(attribution, ['hadRole']);
return {
name: attribution.agent[0].name[0]['@value'],
url: attribution.agent[0]['@id'],
name: getSingleOsfmapValue(contributor,['name']),
url: getSingleOsfmapValue(contributor, ['identifier']),
permissionLevel: this.intl.t(roleIriToTranslationKey[roleIri]),
};
});
}
}

function hasInstitutionAffiliation(contributor: any, institutionIris: string[]) {
return contributor.agent[0].affiliation.some(
function hasInstitutionAffiliation(contributors: any[], attribution: any, institutionIris: string[]) {
const attributedContributor = getContributorById(contributors, getSingleOsfmapValue(attribution, ['agent']));

if (!attributedContributor.affiliation) {
return false;
}

return attributedContributor.affiliation.some(
(affiliation: any) => affiliation.identifier.some(
(affiliationIdentifier: any) => institutionIris.includes(affiliationIdentifier['@value']),
),
);
}

function getContributorById(contributors: any[], contributorId: string) {
return contributors.find(contributor => contributor['@id'] === contributorId);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{{#each this.topInstitutionAffiliatedContributors as |contributor|}}
<OsfLink
@href={{contributor.url}}
>
{{contributor.name}}
</OsfLink>
{{t 'institutions.dashboard.object-list.table-items.permission-level' permissionLevel=contributor.permissionLevel}}
<div>
<OsfLink
@href={{contributor.url}}
>
{{contributor.name}}
</OsfLink>
{{t 'institutions.dashboard.object-list.table-items.permission-level' permissionLevel=contributor.permissionLevel}}
</div>
{{/each}}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{{#each this.dois as |doi|}}
<OsfLink @href={{doi.fullLink}} @target='_blank'>{{doi.displayText}}</OsfLink>
{{else}}
{{t 'institutions.dashboard.object-list.table-items.no-info' field=(t 'institutions.dashboard.object-list.table-headers.doi')}}
{{/each}}
15 changes: 12 additions & 3 deletions app/institutions/dashboard/preprints/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,28 @@ export default class InstitutionDashboardPreprints extends Controller {
},
{ // License
name: this.intl.t('institutions.dashboard.object-list.table-headers.license'),
getValue: searchResult => searchResult.license?.name,
getValue: searchResult => searchResult.license?.name ||
this.intl.t('institutions.dashboard.object-list.table-items.no-license-info'),
},
{ // Contributor name + permissions
name: this.intl.t('institutions.dashboard.object-list.table-headers.contributor_name'),
type: 'contributors',
},
{ // View count
name: this.intl.t('institutions.dashboard.object-list.table-headers.view_count'),
getValue: searchResult => searchResult.usageMetrics.viewCount,
getValue: searchResult => {
const metrics = searchResult.usageMetrics;
return metrics ? metrics.viewCount :
this.intl.t('institutions.dashboard.object-list.table-items.no-metrics');
},
},
{ // Download count
name: this.intl.t('institutions.dashboard.object-list.table-headers.download_count'),
getValue: searchResult => searchResult.usageMetrics.downloadCount,
getValue: searchResult => {
const metrics = searchResult.usageMetrics;
return metrics ? metrics.downloadCount :
this.intl.t('institutions.dashboard.object-list.table-items.no-metrics');
},
},
];

Expand Down
34 changes: 28 additions & 6 deletions app/institutions/dashboard/projects/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,31 +41,53 @@ export default class InstitutionDashboardProjects extends Controller {
},
{ // Total data stored
name: this.intl.t('institutions.dashboard.object-list.table-headers.total_data_stored'),
getValue: searchResult => humanFileSize(searchResult.getResourceMetadataField('storageByteCount')),
getValue: searchResult => {
const byteCount = searchResult.getResourceMetadataField('storageByteCount');
return byteCount ? humanFileSize(byteCount) :
this.intl.t('institutions.dashboard.object-list.table-items.no-storage-info');
},
},
{ // Contributor name + permissions
name: this.intl.t('institutions.dashboard.object-list.table-headers.contributor_name'),
type: 'contributors',
},
{ // View count
name: this.intl.t('institutions.dashboard.object-list.table-headers.view_count'),
getValue: searchResult => searchResult.usageMetrics.viewCount,
getValue: searchResult => {
const metrics = searchResult.usageMetrics;
return metrics ? metrics.viewCount :
this.intl.t('institutions.dashboard.object-list.table-items.no-metrics');
},
},
{ // Resource type
name: this.intl.t('institutions.dashboard.object-list.table-headers.resource_nature'),
getValue: searchResult => searchResult.resourceNature,
getValue: searchResult => {
const field = this.intl.t('institutions.dashboard.object-list.table-headers.resource_nature');
return searchResult.resourceNature ||
this.intl.t('institutions.dashboard.object-list.table-items.no-info', { field });
},
},
{ // License
name: this.intl.t('institutions.dashboard.object-list.table-headers.license'),
getValue: searchResult => searchResult.license?.name,
getValue: searchResult => searchResult.license?.name ||
this.intl.t('institutions.dashboard.object-list.table-items.no-license-info'),
},
{ // addons associated
name: this.intl.t('institutions.dashboard.object-list.table-headers.addons'),
getValue: searchResult => searchResult.configuredAddonNames,
getValue: searchResult => {
const field = this.intl.t('institutions.dashboard.object-list.table-headers.addons');
return searchResult.configuredAddonNames ||
this.intl.t('institutions.dashboard.object-list.table-items.no-info', { field });
},
},
{ // Funder name
name: this.intl.t('institutions.dashboard.object-list.table-headers.funder_name'),
getValue: searchResult => searchResult.funders.map((funder: {name: string}) => funder.name).join(', '),
getValue: searchResult => {
if (!searchResult.funders) {
return this.intl.t('institutions.dashboard.object-list.table-items.no-funder-info');
}
return searchResult.funders.map((funder: { name: string }) => funder.name).join(', ');
},
},
];

Expand Down
28 changes: 23 additions & 5 deletions app/institutions/dashboard/registrations/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,45 @@ export default class InstitutionDashboardRegistrations extends Controller {
},
{ // Total data stored
name: this.intl.t('institutions.dashboard.object-list.table-headers.total_data_stored'),
getValue: searchResult => humanFileSize(searchResult.getResourceMetadataField('storageByteCount')),
getValue: searchResult => {
const byteCount = searchResult.getResourceMetadataField('storageByteCount');
return byteCount ? humanFileSize(byteCount) :
this.intl.t('institutions.dashboard.object-list.table-items.no-storage-info');
},
},
{ // Contributor name + permissions
name: this.intl.t('institutions.dashboard.object-list.table-headers.contributor_name'),
type: 'contributors',
},
{ // View count
name: this.intl.t('institutions.dashboard.object-list.table-headers.view_count'),
getValue: searchResult => searchResult.usageMetrics.viewCount,
getValue: searchResult => {
const metrics = searchResult.usageMetrics;
return metrics ? metrics.viewCount :
this.intl.t('institutions.dashboard.object-list.table-items.no-metrics');
},
},
{ // Resource type
name: this.intl.t('institutions.dashboard.object-list.table-headers.resource_nature'),
getValue: searchResult => searchResult.resourceNature,
getValue: searchResult => {
const field = this.intl.t('institutions.dashboard.object-list.table-headers.resource_nature');
return searchResult.resourceNature ||
this.intl.t('institutions.dashboard.object-list.table-items.no-info', { field });
},
},
{ // License
name: this.intl.t('institutions.dashboard.object-list.table-headers.license'),
getValue: searchResult => searchResult.license?.name,
getValue: searchResult => searchResult.license?.name ||
this.intl.t('institutions.dashboard.object-list.table-items.no-license-info'),
},
{ // Funder name
name: this.intl.t('institutions.dashboard.object-list.table-headers.funder_name'),
getValue: searchResult => searchResult.funders.map((funder: {name: string}) => funder.name).join(', '),
getValue: searchResult => {
if (!searchResult.funders) {
return this.intl.t('institutions.dashboard.object-list.table-items.no-funder-info');
}
return searchResult.funders.map((funder: { name: string }) => funder.name).join(', ');
},
},
{ // schema
name: this.intl.t('institutions.dashboard.object-list.table-headers.registration_schema'),
Expand Down
12 changes: 9 additions & 3 deletions app/models/search-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,16 @@ export default class SearchResultModel extends Model {
}

get usageMetrics() {
if (!this.resourceMetadata.usage) {
return null;
}
const temporalCoverage = this.resourceMetadata.usage[0]['temporalCoverage'];
const viewCount = this.resourceMetadata.usage[0]['viewCount'];
const downloadCount = this.resourceMetadata.usage[0]['downloadCount'];
return {
period: this.resourceMetadata.usage[0]['temporalCoverage'][0]['@value'],
viewCount: this.resourceMetadata.usage[0]['viewCount'][0]['@value'],
downloadCount: this.resourceMetadata.usage[0]['downloadCount'][0]['@value'],
period: temporalCoverage ? temporalCoverage[0]['@value'] : null,
viewCount: viewCount ? viewCount[0]['@value'] : null,
downloadCount: downloadCount ? downloadCount[0]['@value'] : null,
};
}

Expand Down
43 changes: 43 additions & 0 deletions app/packages/osfmap/jsonld.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export function *iterOsfmapObjects(osfmapObject: any, propertyPath: string[]): IterableIterator<any> {
const [property, ...remainingPath] = propertyPath;
const innerObjArray = osfmapObject[property] || [];
if (remainingPath.length) {
for (const innerObj of innerObjArray) {
yield* iterOsfmapObjects(innerObj, remainingPath);
}
} else {
yield* innerObjArray;
}
}

export function *iterOsfmapValues(osfmapObject: any, propertyPath: string[]): IterableIterator<any> {
for (const obj of iterOsfmapObjects(osfmapObject, propertyPath)) {
yield (Object.hasOwn(obj, '@id') ? obj['@id'] : obj['@value']);
}
}

export function getOsfmapValues(osfmapObject: any, propertyPath: string[]) {
return Array.from(iterOsfmapValues(osfmapObject, propertyPath));
}

export function getSingleOsfmapValue(osfmapObject: any, propertyPath: string[]) {
return iterOsfmapValues(osfmapObject, propertyPath).next().value;
}
Comment on lines +23 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if you use this on something that's not a single value? Does it fail gracefully? Or does typescript help here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should just get the first one, and if there's no @id or @value, it should just return undefined


export function getOsfmapObjects(osfmapObject: any, propertyPath: string[]) {
return Array.from(iterOsfmapObjects(osfmapObject, propertyPath));
}

export function getSingleOsfmapObject(osfmapObject: any, propertyPath: string[]) {
return iterOsfmapObjects(osfmapObject, propertyPath).next().value;
}

export function hasOsfmapValue(osfmapObject: any, propertyPath: string[], expectedValue: any) {
// could use `Iterator.prototype.some()` instead, if polyfilled
for (const value of iterOsfmapValues(osfmapObject, propertyPath)) {
if (value === expectedValue) {
return true;
}
}
return false;
}
Loading
Loading