Revert "Separate token refresh"

This reverts commit 9fa69175024bfe29c0c633afa51730aeb205f81c.
This commit is contained in:
shamoon 2024-10-05 11:47:50 -07:00
parent d697e74d58
commit a4fd5fa7f5
8 changed files with 63 additions and 84 deletions

View File

@ -24,20 +24,6 @@
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@if (object?.expiration) {
<button type="button" class="btn btn-outline-secondary me-2" (click)="refreshToken()" [disabled]="networkActive || refreshTokenActive">
@if (refreshTokenActive) {
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
<span class="visually-hidden mr-1" i18n>Loading...</span>
}
<ng-container i18n>Refresh Token</ng-container>
</button>
}
<div class="m-0 me-auto">
@if (refreshTokenResult) {
<ngb-alert #refreshTokenResultAlert [type]="refreshTokenResult" class="mb-0 py-2" (closed)="refreshTokenResult = null">{{refreshTokenResultMessage}}</ngb-alert>
}
</div>
<div class="m-0 me-2"> <div class="m-0 me-2">
@if (testResult) { @if (testResult) {
<ngb-alert #testResultAlert [type]="testResult" class="mb-0 py-2" (closed)="testResult = null">{{testResultMessage}}</ngb-alert> <ngb-alert #testResultAlert [type]="testResult" class="mb-0 py-2" (closed)="testResult = null">{{testResultMessage}}</ngb-alert>

View File

@ -11,7 +11,7 @@ import {
import { FormsModule, ReactiveFormsModule } from '@angular/forms' import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap' import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { NgSelectModule } from '@ng-select/ng-select' import { NgSelectModule } from '@ng-select/ng-select'
import { IMAPSecurity, MailAccountType } from 'src/app/data/mail-account' import { IMAPSecurity } from 'src/app/data/mail-account'
import { IfOwnerDirective } from 'src/app/directives/if-owner.directive' import { IfOwnerDirective } from 'src/app/directives/if-owner.directive'
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive' import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
import { SettingsService } from 'src/app/services/settings.service' import { SettingsService } from 'src/app/services/settings.service'
@ -82,7 +82,6 @@ describe('MailAccountEditDialogComponent', () => {
imap_port: 443, imap_port: 443,
imap_security: IMAPSecurity.SSL, imap_security: IMAPSecurity.SSL,
is_token: false, is_token: false,
account_type: MailAccountType.IMAP,
} }
// success // success

View File

@ -21,14 +21,9 @@ const IMAP_SECURITY_OPTIONS = [
export class MailAccountEditDialogComponent extends EditDialogComponent<MailAccount> { export class MailAccountEditDialogComponent extends EditDialogComponent<MailAccount> {
testActive: boolean = false testActive: boolean = false
testResult: string testResult: string
testAlertTimeout alertTimeout
refreshTokenActive: boolean = false
refreshTokenResult: string
refreshTokenAlertTimeout
@ViewChild('testResultAlert', { static: false }) testResultAlert: NgbAlert @ViewChild('testResultAlert', { static: false }) testResultAlert: NgbAlert
@ViewChild('refreshTokenResultAlert', { static: false })
refreshTokenResultAlert: NgbAlert
constructor( constructor(
service: MailAccountService, service: MailAccountService,
@ -67,7 +62,7 @@ export class MailAccountEditDialogComponent extends EditDialogComponent<MailAcco
test() { test() {
this.testActive = true this.testActive = true
this.testResult = null this.testResult = null
clearTimeout(this.testAlertTimeout) clearTimeout(this.alertTimeout)
const mailService = this.service as MailAccountService const mailService = this.service as MailAccountService
const newObject = Object.assign( const newObject = Object.assign(
Object.assign({}, this.object), Object.assign({}, this.object),
@ -77,18 +72,12 @@ export class MailAccountEditDialogComponent extends EditDialogComponent<MailAcco
next: (result: { success: boolean }) => { next: (result: { success: boolean }) => {
this.testActive = false this.testActive = false
this.testResult = result.success ? 'success' : 'danger' this.testResult = result.success ? 'success' : 'danger'
this.testAlertTimeout = setTimeout( this.alertTimeout = setTimeout(() => this.testResultAlert.close(), 5000)
() => this.testResultAlert.close(),
5000
)
}, },
error: (e) => { error: (e) => {
this.testActive = false this.testActive = false
this.testResult = 'danger' this.testResult = 'danger'
this.testAlertTimeout = setTimeout( this.alertTimeout = setTimeout(() => this.testResultAlert.close(), 5000)
() => this.testResultAlert.close(),
5000
)
}, },
}) })
} }
@ -98,35 +87,4 @@ export class MailAccountEditDialogComponent extends EditDialogComponent<MailAcco
? $localize`Successfully connected to the mail server` ? $localize`Successfully connected to the mail server`
: $localize`Unable to connect to the mail server` : $localize`Unable to connect to the mail server`
} }
refreshToken() {
this.refreshTokenActive = true
this.refreshTokenResult = null
clearTimeout(this.refreshTokenAlertTimeout)
const mailService = this.service as MailAccountService
mailService.refreshOauthToken(this.object).subscribe({
next: (result: { success: boolean }) => {
this.refreshTokenActive = false
this.refreshTokenResult = result.success ? 'success' : 'danger'
this.refreshTokenAlertTimeout = setTimeout(
() => this.refreshTokenResultAlert.close(),
5000
)
},
error: (e) => {
this.refreshTokenActive = false
this.refreshTokenResult = 'danger'
this.refreshTokenAlertTimeout = setTimeout(
() => this.refreshTokenResultAlert.close(),
5000
)
},
})
}
get refreshTokenResultMessage() {
return this.refreshTokenResult === 'success'
? $localize`Successfully refreshed the token`
: $localize`Unable to refresh the token`
}
} }

View File

@ -20,7 +20,6 @@ const mail_accounts = [
username: 'user', username: 'user',
password: 'pass', password: 'pass',
is_token: false, is_token: false,
account_type: 1,
}, },
{ {
name: 'Mail Account 2', name: 'Mail Account 2',
@ -31,7 +30,6 @@ const mail_accounts = [
username: 'user', username: 'user',
password: 'pass', password: 'pass',
is_token: false, is_token: false,
account_type: 1,
}, },
{ {
name: 'Mail Account 3', name: 'Mail Account 3',
@ -42,7 +40,6 @@ const mail_accounts = [
username: 'user', username: 'user',
password: 'pass', password: 'pass',
is_token: false, is_token: false,
account_type: 1,
}, },
] ]
@ -58,6 +55,20 @@ describe(`Additional service tests for MailAccountService`, () => {
expect(req.request.method).toEqual('POST') expect(req.request.method).toEqual('POST')
}) })
it('should support patchMany', () => {
subscription = service.patchMany(mail_accounts).subscribe()
mail_accounts.forEach((mail_account) => {
const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}${endpoint}/${mail_account.id}/`
)
expect(req.request.method).toEqual('PATCH')
req.flush(mail_account)
})
httpTestingController.expectOne(
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
)
})
it('should support reload', () => { it('should support reload', () => {
service['reload']() service['reload']()
const req = httpTestingController.expectOne( const req = httpTestingController.expectOne(

View File

@ -1,5 +1,6 @@
import { HttpClient } from '@angular/common/http' import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { combineLatest, Observable } from 'rxjs'
import { tap } from 'rxjs/operators' import { tap } from 'rxjs/operators'
import { MailAccount } from 'src/app/data/mail-account' import { MailAccount } from 'src/app/data/mail-account'
import { AbstractPaperlessService } from './abstract-paperless-service' import { AbstractPaperlessService } from './abstract-paperless-service'
@ -33,11 +34,15 @@ export class MailAccountService extends AbstractPaperlessService<MailAccount> {
} }
update(o: MailAccount) { update(o: MailAccount) {
delete o.expiration
delete o.refresh_token
return super.update(o).pipe(tap(() => this.reload())) return super.update(o).pipe(tap(() => this.reload()))
} }
patchMany(objects: MailAccount[]): Observable<MailAccount[]> {
return combineLatest(objects.map((o) => super.patch(o))).pipe(
tap(() => this.reload())
)
}
delete(o: MailAccount) { delete(o: MailAccount) {
return super.delete(o).pipe(tap(() => this.reload())) return super.delete(o).pipe(tap(() => this.reload()))
} }
@ -47,8 +52,4 @@ export class MailAccountService extends AbstractPaperlessService<MailAccount> {
delete account['set_permissions'] delete account['set_permissions']
return this.http.post(this.getResourceUrl() + 'test/', account) return this.http.post(this.getResourceUrl() + 'test/', account)
} }
refreshOauthToken(o: MailAccount) {
return this.http.post(this.getResourceUrl(o.id) + 'refresh_oauth_token/', o)
}
} }

View File

@ -76,6 +76,21 @@ const mail_rules = [
commonAbstractPaperlessServiceTests(endpoint, MailRuleService) commonAbstractPaperlessServiceTests(endpoint, MailRuleService)
describe(`Additional service tests for MailRuleService`, () => { describe(`Additional service tests for MailRuleService`, () => {
it('should support patchMany', () => {
subscription = service.patchMany(mail_rules).subscribe()
mail_rules.forEach((mail_rule) => {
const req = httpTestingController.expectOne(
`${environment.apiBaseUrl}${endpoint}/${mail_rule.id}/`
)
expect(req.request.method).toEqual('PATCH')
req.flush(mail_rule)
})
const reloadReq = httpTestingController.expectOne(
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
)
reloadReq.flush({ results: mail_rules })
})
it('should support reload', () => { it('should support reload', () => {
service['reload']() service['reload']()
const req = httpTestingController.expectOne( const req = httpTestingController.expectOne(

View File

@ -37,6 +37,12 @@ export class MailRuleService extends AbstractPaperlessService<MailRule> {
return super.update(o).pipe(tap(() => this.reload())) return super.update(o).pipe(tap(() => this.reload()))
} }
patchMany(objects: MailRule[]): Observable<MailRule[]> {
return combineLatest(objects.map((o) => super.patch(o))).pipe(
tap(() => this.reload())
)
}
delete(o: MailRule) { delete(o: MailRule) {
return super.delete(o).pipe(tap(() => this.reload())) return super.delete(o).pipe(tap(() => this.reload()))
} }

View File

@ -7,7 +7,6 @@ from django.conf import settings
from django.http import HttpResponseBadRequest from django.http import HttpResponseBadRequest
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.utils import timezone from django.utils import timezone
from rest_framework.decorators import action
from rest_framework.generics import GenericAPIView from rest_framework.generics import GenericAPIView
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
@ -36,14 +35,6 @@ class MailAccountViewSet(ModelViewSet, PassUserMixin):
permission_classes = (IsAuthenticated, PaperlessObjectPermissions) permission_classes = (IsAuthenticated, PaperlessObjectPermissions)
filter_backends = (ObjectOwnedOrGrantedPermissionsFilter,) filter_backends = (ObjectOwnedOrGrantedPermissionsFilter,)
@action(methods=["post"], detail=True)
def refresh_oauth_token(self, request, pk=None):
return (
Response({"success": True})
if refresh_oauth_token(MailAccount.objects.get(id=pk))
else HttpResponseBadRequest("Unable to refresh token")
)
class MailRuleViewSet(ModelViewSet, PassUserMixin): class MailRuleViewSet(ModelViewSet, PassUserMixin):
model = MailRule model = MailRule
@ -65,14 +56,16 @@ class MailAccountTestView(GenericAPIView):
serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
# account exists, use the password from there instead of *** # account exists, use the password from there instead of *** and refresh_token / expiration
if ( if (
len(serializer.validated_data.get("password").replace("*", "")) == 0 len(serializer.validated_data.get("password").replace("*", "")) == 0
and request.data["id"] is not None and request.data["id"] is not None
): ):
serializer.validated_data["password"] = MailAccount.objects.get( existing_account = MailAccount.objects.get(pk=request.data["id"])
pk=request.data["id"], serializer.validated_data["password"] = existing_account.password
).password serializer.validated_data["account_type"] = existing_account.account_type
serializer.validated_data["refresh_token"] = existing_account.refresh_token
serializer.validated_data["expiration"] = existing_account.expiration
account = MailAccount(**serializer.validated_data) account = MailAccount(**serializer.validated_data)
@ -82,6 +75,16 @@ class MailAccountTestView(GenericAPIView):
account.imap_security, account.imap_security,
) as M: ) as M:
try: try:
if (
account.is_token
and account.expiration is not None
and account.expiration < timezone.now()
):
if refresh_oauth_token(account):
account.refresh_from_db()
else:
raise MailError("Unable to refresh oauth token")
mailbox_login(M, account) mailbox_login(M, account)
return Response({"success": True}) return Response({"success": True})
except MailError: except MailError: