• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CenterForOpenScience / ember-osf-web / 13249070322

10 Feb 2025 07:40PM UTC coverage: 66.764%. First build
13249070322

Pull #2506

github

web-flow
Merge 52576f0d1 into 571e129de
Pull Request #2506: [ENG-7174] Update Preprint versions to be a relationship

3110 of 5081 branches covered (61.21%)

Branch coverage included in aggregate %.

0 of 3 new or added lines in 2 files covered. (0.0%)

7900 of 11410 relevant lines covered (69.24%)

189.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.64
/app/preprints/detail/controller.ts
1
import Controller from '@ember/controller';
2
import { action } from '@ember/object';
3
import RouterService from '@ember/routing/router-service';
4
import { inject as service } from '@ember/service';
5
import { waitFor } from '@ember/test-waiters';
6
import Store from '@ember-data/store';
7
import { tracked } from '@glimmer/tracking';
8
import { task } from 'ember-concurrency';
9
import Features from 'ember-feature-flags';
10
import Intl from 'ember-intl/services/intl';
11
import Media from 'ember-responsive';
12
import Toast from 'ember-toastr/services/toast';
13

14
import config from 'ember-osf-web/config/environment';
15
import ContributorModel from 'ember-osf-web/models/contributor';
16
import { Permission } from 'ember-osf-web/models/osf-model';
17
import { VersionStatusSimpleLabelKey } from 'ember-osf-web/models/preprint';
18
import { PreprintProviderReviewsWorkFlow, ReviewsState } from 'ember-osf-web/models/provider';
19
import CurrentUserService from 'ember-osf-web/services/current-user';
20
import Theme from 'ember-osf-web/services/theme';
21
import captureException, { getApiErrorMessage } from 'ember-osf-web/utils/capture-exception';
22
import { getOwner } from '@ember/application';
23

24

25
/**
26
 * Takes an object with query parameter name as the key and value,
27
 * or [value, maxLength] as the values.
28
 *
29
 * @method queryStringify
30
 * @param queryParams {!object}
31
 * @param queryParams.key {!array|!string}
32
 * @param queryParams.key[0] {!string}
33
 * @param queryParams.key[1] {int}
34
 * @return {string}
35
 */
36

37
const DATE_LABEL = {
1✔
38
    created: 'preprints.detail.date_label.created_on',
39
    submitted: 'preprints.detail.date_label.submitted_on',
40
};
41

42
/**
43
 * @module ember-preprints
44
 * @submodule controllers
45
 */
46

47
/**
48
 * @class Content Controller
49
 */
50
export default class PrePrintsDetailController extends Controller {
51
    @service store!: Store;
52
    @service theme!: Theme;
53
    @service currentUser!: CurrentUserService;
54
    @service features!: Features;
55
    @service intl!: Intl;
56
    @service media!: Media;
57
    @service toast!: Toast;
58
    @service router!: RouterService;
59

60
    @tracked fullScreenMFR = false;
4✔
61
    @tracked plauditIsReady = false;
4✔
62

63
    metricsStartDate = config.OSF.metricsStartDate;
6✔
64
    reviewStateLabelKeyMap = VersionStatusSimpleLabelKey;
6✔
65

66
    get hyperlink(): string {
67
        return window.location.href;
4✔
68
    }
69

70
    get fileDownloadUrl(): string {
71
        const version = this.model.primaryFile.version;
4✔
72
        const path = `${this.model.preprint.id}/download/?`;
4✔
73
        return `${config.OSF.url}${path}${version ? `version=${version}` : ''}`.replace(/[&?]$/, '');
4!
74
    }
75

76
    get facebookAppId(): string {
77
        return this.model.provider.facebookAppId ? this.model.provider.facebookAppId : config.FB_APP_ID;
4!
78
    }
79

80
    get dateLabel(): string {
81
        return this.model.provider.reviewsWorkflow === PreprintProviderReviewsWorkFlow.PRE_MODERATION ?
4!
82
            DATE_LABEL.submitted :
83
            DATE_LABEL.created;
84
    }
85

86
    get showEditButton() {
87
        const providerIsPremod = this.model.provider.reviewsWorkflow === PreprintProviderReviewsWorkFlow.PRE_MODERATION;
10✔
88
        const preprintIsRejected = this.model.preprint.reviewsState === ReviewsState.REJECTED;
10✔
89
        const preprintIsFirstVersion = this.model.preprint.version === 1;
10✔
90

91
        if (!this.userIsContrib) {
10✔
92
            return false;
1✔
93
        }
94

95
        if (this.model.preprint.isWithdrawn) {
9!
96
            return false;
×
97
        }
98

99
        if (this.model.preprint.isLatestVersion || this.model.preprint.reviewsState === ReviewsState.INITIAL) {
9✔
100
            return true;
4✔
101
        }
102
        if (providerIsPremod) {
5!
103
            if (this.model.preprint.reviewsState === ReviewsState.PENDING) {
5✔
104
                return true;
1✔
105
            }
106
            // Edit and resubmit
107
            if (preprintIsFirstVersion && preprintIsRejected
4✔
108
                && this.model.preprint.currentUserIsAdmin) {
109
                return true;
1✔
110
            }
111
        }
112
        return false;
3✔
113
    }
114
    get editButtonLabel(): string {
115
        const providerIsPremod = this.model.provider.reviewsWorkflow === PreprintProviderReviewsWorkFlow.PRE_MODERATION;
5✔
116
        const preprintIsRejected = this.model.preprint.reviewsState === ReviewsState.REJECTED;
5✔
117

118
        const editPreprint = 'preprints.detail.edit_preprint';
5✔
119
        const editResubmitPreprint = 'preprints.detail.edit_resubmit_preprint';
5✔
120
        const translation = providerIsPremod && preprintIsRejected && this.model.preprint.currentUserIsAdmin
5✔
121
            ? editResubmitPreprint : editPreprint;
122
        return this.intl.t(translation, {
5✔
123
            documentType: this.model.provider.documentType.singular,
124
        });
125
    }
126

127
    get displayTitle(): string {
128
        if (this.model.preprint.isWithdrawn) {
8✔
129
            return this.intl.t('preprints.detail.withdrawn_title', {
3✔
130
                title: this.model.preprint.title,
131
            });
132
        }
133
        return this.model.preprint.title;
5✔
134
    }
135

136
    private hasReadWriteAccess(): boolean {
137
        // True if the current user has write permissions for the node that contains the preprint
138
        return (this.model.preprint.currentUserPermissions.includes(Permission.Write));
×
139
    }
140

141

142
    get userIsContrib(): boolean {
143
        if (this.model.preprint.currentUserIsAdmin) {
23✔
144
            return true;
21✔
145
        } else if (this.model.contributors.length) {
2!
146
            const authorIds = [] as string[];
2✔
147
            this.model.contributors.forEach((author: ContributorModel) => {
2✔
148
                authorIds.push(author.id);
8✔
149
            });
150
            const authorId = `${this.model.preprint.id}-${this.currentUser.currentUserId}`;
2✔
151
            return this.currentUser.currentUserId ? authorIds.includes(authorId) && this.hasReadWriteAccess() : false;
2!
152
        }
153
        return false;
×
154
    }
155

156
    get showStatusBanner(): boolean {
157
        return (
13✔
158
            this.model.provider.reviewsWorkflow
62✔
159
            && this.model.preprint.public
160
            && this.userIsContrib
161
            && this.model.preprint.reviewsState !== ReviewsState.INITIAL
162
            && !this.model.preprint.isPreprintOrphan
163
        );
164
    }
165

166
    get authors(): ContributorModel[] {
167
        return this.model.contributors;
×
168
    }
169

170
    emailHref(): string {
171
        const titleEncoded = encodeURIComponent(this.model.title);
×
172
        const hrefEncoded = encodeURIComponent(window.location.href);
×
173
        return `mailto:?subject=${titleEncoded}&body=${hrefEncoded}`;
×
174
    }
175

176
    @action
177
    expandMFR() {
178
        this.fullScreenMFR = !this.fullScreenMFR;
×
179
    }
180

181
    @action
182
    trackNonContributors(category: string, label: string, url: string): void {
183
        this.send('click', category, label, url);
×
184
    }
185

186
    @task
187
    @waitFor
188
    async createNewVersion() {
189
        try {
×
NEW
190
            const newVersion = await this.model.preprint.makeNewVersion();
×
191
            this.transitionToRoute('preprints.new-version', this.model.provider.id, newVersion.data.id);
×
192
        } catch (e) {
193
            const errorTitle = this.intl.t('preprints.submit.new-version.error.title');
×
194
            const errorMessage = getApiErrorMessage(e);
×
195
            captureException(e, { errorMessage });
×
196
            this.toast.error(errorMessage, errorTitle);
×
197
        }
198
    }
199

200
    /**
201
     * Callback for the action-flow component
202
     */
203
    @task
204
    @waitFor
205
    public async onWithdrawal(): Promise<void> {
206
        try {
×
207
            const preprintRequest = await this.store.createRecord('preprint-request', {
×
208
                comment: this.model.preprint.withdrawalJustification,
209
                requestType: 'withdrawal',
210
                target: this.model.preprint,
211
            });
212

213
            await preprintRequest.save();
×
214

215
            this.toast.success(
×
216
                this.intl.t('preprints.submit.action-flow.success-withdrawal',
217
                    {
218
                        singularCapitalizedPreprintWord: this.model.provider.documentType.singularCapitalized,
219
                    }),
220
            );
221

222
            const { currentRouteName } = this.router;
×
223
            getOwner(this).lookup(`route:${currentRouteName}`).refresh();
×
224
        } catch (e) {
225
            const errorMessage = this.intl.t('preprints.submit.action-flow.error-withdrawal',
×
226
                {
227
                    singularPreprintWord: this.model.provider.documentType.singular,
228
                });
229
            this.toast.error(errorMessage);
×
230
            captureException(e, { errorMessage });
×
231
        }
232
    }
233

234
    get isMobile() {
235
        return this.media.isMobile;
6✔
236
    }
237
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc