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

CenterForOpenScience / ember-osf-web / 12757530942

13 Jan 2025 10:47PM UTC coverage: 68.206%. First build
12757530942

Pull #2468

github

web-flow
Merge c9d745a39 into 51f651b65
Pull Request #2468: [ENG-6461] [ENG-6462] Move withdraw button

2960 of 4721 branches covered (62.7%)

Branch coverage included in aggregate %.

9 of 27 new or added lines in 3 files covered. (33.33%)

7425 of 10505 relevant lines covered (70.68%)

202.94 hits per line

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

69.03
/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 {
×
190
            const url = this.model.preprint.links.preprint_versions as string;
×
191
            const newVersion = await this.currentUser.authenticatedAJAX({
×
192
                url,
193
                type: 'POST',
194
            });
195
            this.transitionToRoute('preprints.new-version', this.model.provider.id, newVersion.data.id);
×
196
        } catch (e) {
197
            const errorTitle = this.intl.t('preprints.submit.new-version.error.title');
×
198
            const errorMessage = getApiErrorMessage(e);
×
199
            captureException(e, { errorMessage });
×
200
            this.toast.error(errorMessage, errorTitle);
×
201
        }
202
    }
203

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

NEW
217
            await preprintRequest.save();
×
218

NEW
219
            this.toast.success(
×
220
                this.intl.t('preprints.submit.action-flow.success-withdrawal',
221
                    {
222
                        singularCapitalizedPreprintWord: this.model.provider.documentType.singularCapitalized,
223
                    }),
224
            );
225

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

238
    get isMobile() {
239
        return this.media.isMobile;
6✔
240
    }
241
}
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