Skip to content

Commit 68e47d2

Browse files
authored
Merge pull request #996 from nsemets/fix/merge-conflicts-pbs-26-9
Merged `develop` into `pbs-26-9`
2 parents 44583e9 + 2ea839d commit 68e47d2

14 files changed

Lines changed: 101 additions & 34 deletions

File tree

CHANGELOG

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22

33
We follow the CalVer (https://calver.org/) versioning scheme: YY.MINOR.MICRO.
44

5+
26.10.1 (2026-05-15)
6+
====================
7+
8+
* Hotfix to take users to the links they clicked instead of the dashboard
9+
10+
26.10.0 (2026-05-07)
11+
====================
12+
13+
* OSF4I In-progress SSO Project - FE Piece
14+
15+
26.9.2 (2026-05-06)
16+
===================
17+
18+
* Hotfix to avoid errors on creating preprint versions
19+
520
26.9.1 (2026-04-28)
621
===================
722

package-lock.json

Lines changed: 24 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "osf",
3-
"version": "26.9.1",
3+
"version": "26.10.1",
44
"scripts": {
55
"ng": "ng",
66
"analyze-bundle": "ng build --configuration=analyze-bundle && source-map-explorer dist/**/*.js --no-border-checks",

src/app/core/interceptors/error.interceptor.spec.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Router } from '@angular/router';
1010
import { SENTRY_TOKEN } from '@core/provider/sentry.provider';
1111
import { AuthService } from '@core/services/auth.service';
1212
import { MaintenanceModeService } from '@core/services/maintenance-mode.service';
13+
import { UserSelectors } from '@core/store/user';
1314
import { ToastService } from '@osf/shared/services/toast.service';
1415
import { ViewOnlyLinkHelperService } from '@osf/shared/services/view-only-link-helper.service';
1516

@@ -22,6 +23,7 @@ import {
2223
} from '@testing/providers/maintenance-mode.service.mock';
2324
import { RouterMockBuilder, RouterMockType } from '@testing/providers/router-provider.mock';
2425
import { SentryMock, SentryMockType } from '@testing/providers/sentry-provider.mock';
26+
import { provideMockStore } from '@testing/providers/store-provider.mock';
2527
import { ToastServiceMock, ToastServiceMockType } from '@testing/providers/toast-provider.mock';
2628
import { ViewOnlyLinkHelperMock, ViewOnlyLinkHelperMockType } from '@testing/providers/view-only-link-helper.mock';
2729

@@ -37,7 +39,12 @@ describe('errorInterceptor', () => {
3739
let viewOnlyHelperMock: ViewOnlyLinkHelperMockType;
3840
let sentryMock: SentryMockType;
3941

40-
function setup(platformId: 'browser' | 'server' = 'browser', viewOnly = false, routerUrl = '/dashboard') {
42+
function setup(
43+
platformId: 'browser' | 'server' = 'browser',
44+
viewOnly = false,
45+
routerUrl = '/dashboard',
46+
isAuthenticated = false
47+
) {
4148
router = RouterMockBuilder.create().withUrl(routerUrl).withNavigate(vi.fn().mockResolvedValue(true)).build();
4249
toastServiceMock = ToastServiceMock.simple();
4350
loaderServiceMock = new LoaderServiceMock();
@@ -50,6 +57,9 @@ describe('errorInterceptor', () => {
5057
providers: [
5158
provideOSFCore(),
5259
provideLoaderServiceMock(loaderServiceMock),
60+
provideMockStore({
61+
selectors: [{ selector: UserSelectors.isAuthenticated, value: isAuthenticated }],
62+
}),
5363
MockProvider(Router, router),
5464
MockProvider(ToastService, toastServiceMock),
5565
MockProvider(AuthService, authServiceMock),
@@ -115,15 +125,30 @@ describe('errorInterceptor', () => {
115125
expect(toastServiceMock.showError).not.toHaveBeenCalled();
116126
});
117127

118-
it('should logout on 401 in browser when not view-only', async () => {
119-
setup('browser', false);
128+
it('should navigate to sign in on 401 in browser when anonymous and not view-only', async () => {
129+
setup('browser', false, '/dashboard', false);
130+
const request = createRequest('/api/v2/nodes/abc');
131+
const error = new HttpErrorResponse({ status: 401, error: {}, url: request.url });
132+
133+
const caught = await runInterceptor(request, error);
134+
135+
expect(caught?.status).toBe(401);
136+
expect(authServiceMock.navigateToSignIn).toHaveBeenCalled();
137+
expect(authServiceMock.logout).not.toHaveBeenCalled();
138+
expect(loaderServiceMock.hide).not.toHaveBeenCalled();
139+
expect(toastServiceMock.showError).not.toHaveBeenCalled();
140+
});
141+
142+
it('should logout on 401 in browser when authenticated and not view-only', async () => {
143+
setup('browser', false, '/dashboard', true);
120144
const request = createRequest('/api/v2/nodes/abc');
121145
const error = new HttpErrorResponse({ status: 401, error: {}, url: request.url });
122146

123147
const caught = await runInterceptor(request, error);
124148

125149
expect(caught?.status).toBe(401);
126-
expect(authServiceMock.logout).toHaveBeenCalled();
150+
expect(authServiceMock.logout).toHaveBeenCalledWith(window.location.href);
151+
expect(authServiceMock.navigateToSignIn).not.toHaveBeenCalled();
127152
expect(loaderServiceMock.hide).not.toHaveBeenCalled();
128153
expect(toastServiceMock.showError).not.toHaveBeenCalled();
129154
});

src/app/core/interceptors/error.interceptor.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Store } from '@ngxs/store';
2+
13
import { throwError } from 'rxjs';
24
import { catchError } from 'rxjs/operators';
35

@@ -11,6 +13,7 @@ import { MaintenanceResponse } from '@core/models/maintenance-response.model';
1113
import { SENTRY_TOKEN } from '@core/provider/sentry.provider';
1214
import { AuthService } from '@core/services/auth.service';
1315
import { MaintenanceModeService } from '@core/services/maintenance-mode.service';
16+
import { UserSelectors } from '@core/store/user';
1417
import { LoaderService } from '@osf/shared/services/loader.service';
1518
import { ToastService } from '@osf/shared/services/toast.service';
1619
import { ViewOnlyLinkHelperService } from '@osf/shared/services/view-only-link-helper.service';
@@ -26,6 +29,7 @@ export const errorInterceptor: HttpInterceptorFn = (req, next) => {
2629
const sentry = inject(SENTRY_TOKEN);
2730
const platformId = inject(PLATFORM_ID);
2831
const viewOnlyHelper = inject(ViewOnlyLinkHelperService);
32+
const store = inject(Store);
2933

3034
return next(req).pipe(
3135
catchError((error: HttpErrorResponse) => {
@@ -69,7 +73,11 @@ export const errorInterceptor: HttpInterceptorFn = (req, next) => {
6973
if (error.status === 401) {
7074
if (!viewOnlyHelper.hasViewOnlyParam(router)) {
7175
if (isPlatformBrowser(platformId)) {
72-
authService.logout();
76+
if (store.selectSnapshot(UserSelectors.isAuthenticated)) {
77+
authService.logout(window.location.href);
78+
} else {
79+
authService.navigateToSignIn();
80+
}
7381
}
7482
}
7583
return throwError(() => error);

src/app/core/services/auth.service.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,14 @@ export class AuthService {
4141
}
4242

4343
this.loaderService.show();
44-
const loginUrl = `${this.casUrl}/login?${urlParam({ service: `${this.webUrl}/login`, next: window.location.href })}`;
45-
window.location.href = loginUrl;
44+
45+
const serviceUrl = new URL(`${this.webUrl}/login`);
46+
serviceUrl.searchParams.set('next', window.location.href);
47+
48+
const loginUrl = new URL(`${this.casUrl}/login`);
49+
loginUrl.searchParams.set('service', serviceUrl.toString());
50+
51+
window.location.href = loginUrl.toString();
4652
}
4753

4854
navigateToOrcidSignIn(): void {
@@ -79,7 +85,7 @@ export class AuthService {
7985

8086
if (isPlatformBrowser(this.platformId)) {
8187
this.cookieService.deleteAll();
82-
window.location.href = `${this.webUrl}/logout/?next=${encodeURIComponent(nextUrl || '/')}`;
88+
window.location.href = `${this.webUrl}/logout/?next=${encodeURIComponent(nextUrl || `${window.location.origin}/`)}`;
8389
}
8490
}
8591

src/app/features/preprints/pages/preprint-details/preprint-details.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,9 @@ export class PreprintDetailsComponent implements OnInit, OnDestroy {
186186
const preprint = this.preprint();
187187
if (!preprint) return false;
188188

189-
return this.hasAdminAccess() && preprint.datePublished && preprint.isLatestVersion;
189+
const preprintIsRejected = preprint.reviewsState === ReviewsState.Rejected;
190+
191+
return this.hasAdminAccess() && (preprint.datePublished || preprintIsRejected) && preprint.isLatestVersion;
190192
});
191193

192194
editButtonVisible = computed(() => {

src/app/features/profile/components/profile-information/profile-information.component.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ describe('ProfileInformationComponent', () => {
3737
},
3838
institutionalRequestAccessEnabled: true,
3939
logoPath: 'logo.png',
40+
sso_availability: 'Public',
4041
},
4142
];
4243

src/app/features/project/overview/components/add-component-dialog/add-component-dialog.component.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ describe('AddComponentDialogComponent', () => {
6464
assets: { logo: '', logo_rounded: '', banner: '' },
6565
institutionalRequestAccessEnabled: false,
6666
logoPath: '',
67+
sso_availability: 'Public',
6768
},
6869
{
6970
id: 'inst-2',
@@ -76,6 +77,7 @@ describe('AddComponentDialogComponent', () => {
7677
assets: { logo: '', logo_rounded: '', banner: '' },
7778
institutionalRequestAccessEnabled: false,
7879
logoPath: '',
80+
sso_availability: 'Public',
7981
},
8082
];
8183

@@ -91,6 +93,7 @@ describe('AddComponentDialogComponent', () => {
9193
assets: { logo: '', logo_rounded: '', banner: '' },
9294
institutionalRequestAccessEnabled: false,
9395
logoPath: '',
96+
sso_availability: 'Public',
9497
},
9598
];
9699

src/app/shared/components/affiliated-institution-select/affiliated-institution-select.component.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ describe('AffiliatedInstitutionSelectComponent', () => {
6868
},
6969
institutionalRequestAccessEnabled: false,
7070
logoPath: '/logos/unavailable.png',
71+
sso_availability: 'Unavailable',
7172
};
7273

7374
fixture.componentRef.setInput('institutions', mockInstitutions);
@@ -134,6 +135,7 @@ describe('AffiliatedInstitutionSelectComponent', () => {
134135
},
135136
institutionalRequestAccessEnabled: false,
136137
logoPath: '/logos/unavailable.png',
138+
sso_availability: 'Unavailable',
137139
};
138140

139141
fixture.componentRef.setInput('institutions', mockInstitutions);
@@ -181,6 +183,7 @@ describe('AffiliatedInstitutionSelectComponent', () => {
181183
},
182184
institutionalRequestAccessEnabled: false,
183185
logoPath: '/logos/unavailable.png',
186+
sso_availability: 'Unavailable',
184187
};
185188

186189
fixture.componentRef.setInput('institutions', mockInstitutions);

0 commit comments

Comments
 (0)