Browse Source

Bugfixes for restore

pull/311/head
Sebastian Stehle 8 years ago
parent
commit
e052364595
  1. 3
      src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs
  2. 2
      src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs
  3. 2
      src/Squidex.Infrastructure/States/DefaultStreamNameResolver.cs
  4. 3
      src/Squidex/app/features/administration/pages/restore/restore-page.component.html
  5. 2
      src/Squidex/app/features/administration/pages/restore/restore-page.component.ts
  6. 5
      src/Squidex/app/shared/services/backups.service.spec.ts
  7. 12
      src/Squidex/app/shared/services/backups.service.ts
  8. 8
      src/Squidex/app/shared/state/backups.forms.ts

3
src/Squidex.Domain.Apps.Entities/Apps/BackupApps.cs

@ -11,6 +11,7 @@ using System.Threading.Tasks;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Orleans; using Orleans;
using Squidex.Domain.Apps.Entities.Apps.Indexes; using Squidex.Domain.Apps.Entities.Apps.Indexes;
using Squidex.Domain.Apps.Entities.Apps.State;
using Squidex.Domain.Apps.Entities.Backup; using Squidex.Domain.Apps.Entities.Backup;
using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Apps;
@ -166,6 +167,8 @@ namespace Squidex.Domain.Apps.Entities.Apps
public override async Task CompleteRestoreAsync(Guid appId, BackupReader reader) public override async Task CompleteRestoreAsync(Guid appId, BackupReader reader)
{ {
await RebuildAsync<AppState, AppGrain>(appId, (e, s) => s.Apply(e));
await grainFactory.GetGrain<IAppsByNameIndex>(SingleGrain.Id).AddAppAsync(appCreated.AppId.Id, appCreated.AppId.Name); await grainFactory.GetGrain<IAppsByNameIndex>(SingleGrain.Id).AddAppAsync(appCreated.AppId.Id, appCreated.AppId.Name);
foreach (var user in activeUsers) foreach (var user in activeUsers)

2
src/Squidex.Domain.Apps.Entities/Backup/BackupGrain.cs

@ -139,7 +139,7 @@ namespace Squidex.Domain.Apps.Entities.Backup
{ {
using (var stream = await backupArchiveLocation.OpenStreamAsync(job.Id)) using (var stream = await backupArchiveLocation.OpenStreamAsync(job.Id))
{ {
using (var writer = new BackupWriter(stream)) using (var writer = new BackupWriter(stream, true))
{ {
await eventStore.QueryAsync(async storedEvent => await eventStore.QueryAsync(async storedEvent =>
{ {

2
src/Squidex.Infrastructure/States/DefaultStreamNameResolver.cs

@ -38,7 +38,7 @@ namespace Squidex.Infrastructure.States
Guard.NotNullOrEmpty(streamName, nameof(streamName)); Guard.NotNullOrEmpty(streamName, nameof(streamName));
Guard.NotNull(idGenerator, nameof(idGenerator)); Guard.NotNull(idGenerator, nameof(idGenerator));
var positionOfDash = streamName.LastIndexOf('-'); var positionOfDash = streamName.IndexOf('-');
if (positionOfDash >= 0) if (positionOfDash >= 0)
{ {

3
src/Squidex/app/features/administration/pages/restore/restore-page.component.html

@ -55,6 +55,9 @@
<div class="col"> <div class="col">
<input class="form-control" name="url" formControlName="url" placeholder="Url to backup" /> <input class="form-control" name="url" formControlName="url" placeholder="Url to backup" />
</div> </div>
<div class="col pl-1">
<input class="form-control" name="name" formControlName="name" placeholder="Optional app name" />
</div>
<div class="col col-auto pl-1"> <div class="col col-auto pl-1">
<button type="submit" class="btn btn-success" [disabled]="restoreForm.hasNoUrl | async">Restore Backup</button> <button type="submit" class="btn btn-success" [disabled]="restoreForm.hasNoUrl | async">Restore Backup</button>
</div> </div>

2
src/Squidex/app/features/administration/pages/restore/restore-page.component.ts

@ -57,7 +57,7 @@ export class RestorePageComponent implements OnDestroy, OnInit {
if (value) { if (value) {
this.restoreForm.submitCompleted({}); this.restoreForm.submitCompleted({});
this.backupsService.postRestore(value.url) this.backupsService.postRestore(value)
.subscribe(() => { .subscribe(() => {
this.dialogs.notifyInfo('Restore started, it can take several minutes to complete.'); this.dialogs.notifyInfo('Restore started, it can take several minutes to complete.');
}, error => { }, error => {

5
src/Squidex/app/shared/services/backups.service.spec.ts

@ -14,7 +14,8 @@ import {
BackupDto, BackupDto,
BackupsService, BackupsService,
DateTime, DateTime,
RestoreDto RestoreDto,
StartRestoreDto
} from './../'; } from './../';
describe('BackupsService', () => { describe('BackupsService', () => {
@ -169,7 +170,7 @@ describe('BackupsService', () => {
it('should make post request to start restore', it('should make post request to start restore',
inject([BackupsService, HttpTestingController], (backupsService: BackupsService, httpMock: HttpTestingController) => { inject([BackupsService, HttpTestingController], (backupsService: BackupsService, httpMock: HttpTestingController) => {
backupsService.postRestore('http://url').subscribe(); backupsService.postRestore(new StartRestoreDto('http://url')).subscribe();
const req = httpMock.expectOne('http://service/p/api/apps/restore'); const req = httpMock.expectOne('http://service/p/api/apps/restore');

12
src/Squidex/app/shared/services/backups.service.ts

@ -43,6 +43,14 @@ export class RestoreDto {
} }
} }
export class StartRestoreDto {
constructor(
public readonly url: string,
public readonly newAppName?: string
) {
}
}
@Injectable() @Injectable()
export class BackupsService { export class BackupsService {
constructor( constructor(
@ -106,10 +114,10 @@ export class BackupsService {
pretifyError('Failed to start backup.')); pretifyError('Failed to start backup.'));
} }
public postRestore(downloadUrl: string): Observable<any> { public postRestore(dto: StartRestoreDto): Observable<any> {
const url = this.apiUrl.buildUrl(`api/apps/restore`); const url = this.apiUrl.buildUrl(`api/apps/restore`);
return this.http.post(url, { url: downloadUrl }).pipe( return this.http.post(url, dto).pipe(
tap(() => { tap(() => {
this.analytics.trackEvent('Restore', 'Started'); this.analytics.trackEvent('Restore', 'Started');
}), }),

8
src/Squidex/app/shared/state/backups.forms.ts

@ -8,7 +8,7 @@
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { map, startWith } from 'rxjs/operators'; import { map, startWith } from 'rxjs/operators';
import { Form } from '@app/framework'; import { Form, ValidatorsEx } from '@app/framework';
export class RestoreForm extends Form<FormGroup> { export class RestoreForm extends Form<FormGroup> {
public hasNoUrl = public hasNoUrl =
@ -16,6 +16,12 @@ export class RestoreForm extends Form<FormGroup> {
constructor(formBuilder: FormBuilder) { constructor(formBuilder: FormBuilder) {
super(formBuilder.group({ super(formBuilder.group({
name: [null,
[
Validators.maxLength(40),
ValidatorsEx.pattern('[a-z0-9]+(\-[a-z0-9]+)*', 'Name can contain lower case letters (a-z), numbers and dashes (not at the end).')
]
],
url: [null, url: [null,
[ [
Validators.required Validators.required

Loading…
Cancel
Save