Clean up of the playlists ui

This commit is contained in:
Fergal Moran
2018-05-12 13:31:51 +01:00
parent 082b7336bd
commit 19c5c3ae3c
10 changed files with 1064 additions and 58 deletions

0
client/.prettierc Normal file
View File

View File

@@ -1,33 +1,32 @@
<form class="push">
<div class="input-group input-group-lg">
<input type="text"
name="entry-url"
#input
[disabled]="isPosting"
[(ngModel)]="newEntrySourceUrl"
class="form-control"
placeholder="Paste (or type) URL and press enter or the button">
<input type="text" name="entry-url" [ngClass]="isPosting ? 'bg-gd-leaf' : ''" #input [disabled]="isPosting" [(ngModel)]="newEntrySourceUrl" class="form-control" placeholder="Paste (or type) URL and press enter or the button">
<div class="input-group-append">
<button type="submit"
class="btn btn-secondary"
[disabled]="isPosting"
(click)="addEntry(podcast)">
<i class="fa fa-plus"
*ngIf="!isPosting"></i>
<i class="fa fa-cog fa-spin"
*ngIf="isPosting"></i>
<button type="submit" class="btn btn-secondary" [disabled]="isPosting" (click)="addEntry(podcast)">
<i class="fa fa-plus" *ngIf="!isPosting"></i>
<i class="fa fa-cog fa-spin" *ngIf="isPosting"></i>
</button>
</div>
</div>
</form>
<div class="alert alert-danger alert-dismissible fade show animated fadeInDown"
role="alert"
*ngIf="errorText">
<div class="block block-themed" *ngIf="playlistProxy !== null">
<div class="block-header bg-corporate-light">
<h3 class="block-title font-w600">
This looks like a playlist? Shall we add all items (please note, this may result in a lot of episodes being downloaded to
your device).</h3>
<div class="block-options">
<button type="button" class="btn btn-sm btn-alt-primary" (click)="processPlaylist()">
<i class="fa fa-check"></i>Yes
</button>
<button type="button" class="btn btn-sm btn-alt-danger" (click)="resetUrl()">
<i class="fa fa-times"></i>No
</button>
</div>
</div>
</div>
<div class="alert alert-danger alert-dismissible fade show animated fadeInDown" role="alert" *ngIf="errorText">
<strong>Error!</strong> {{errorText}}
<button type="button"
class="close"
data-dismiss="alert"
aria-label="Close">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>

View File

@@ -17,21 +17,34 @@ import { debounceTime } from 'rxjs/operator/debounceTime';
})
export class PodcastAddUrlFormComponent implements AfterViewInit {
@Input() podcast: PodcastModel;
@Output() onUrlAddComplete: EventEmitter<any> = new EventEmitter();
@Output() onUploadDeferred: EventEmitter<any> = new EventEmitter();
@Output()
onUrlAddComplete: EventEmitter<any> = new EventEmitter();
@Output()
onPlaylistAdded: EventEmitter<any> = new EventEmitter();
newEntrySourceUrl: string;
errorText: string;
isPosting: boolean = false;
@ViewChild('input') vc: any;
playlistProxy: PodcastEntryModel = null;
constructor(private _service: PodcastService) {}
ngAfterViewInit() {
this.vc.nativeElement.focus();
}
isValidURL(str) {
var a = document.createElement('a');
let a = document.createElement('a');
a.href = str;
return a.host && a.host != window.location.host;
}
processPlaylist() {
this.onPlaylistAdded.emit(this.playlistProxy)
this.resetUrl();
}
resetUrl() {
this.playlistProxy = null;
this.isPosting = false;
this.newEntrySourceUrl = '';
}
addEntry(podcast: PodcastModel) {
const urlToCheck = this.newEntrySourceUrl;
this.newEntrySourceUrl = 'Checking (please wait).....';
@@ -43,7 +56,7 @@ export class PodcastAddUrlFormComponent implements AfterViewInit {
(e) => {
if (e) {
if (e.processingStatus === 'Deferred') {
this.onUploadDeferred.emit(e);
this.playlistProxy = e;
} else {
this.onUrlAddComplete.emit(e);
}

View File

@@ -28,22 +28,8 @@
<div class="block-content">
<app-podcast-upload-form *ngIf="uploadMode" [podcast]="podcast" (onUploadComplete)="onEntryUploadComplete($event)">
</app-podcast-upload-form>
<app-podcast-add-url-form *ngIf="urlMode" [podcast]="podcast" (onUrlAddComplete)="onUrlAddComplete($event)" (onUploadDeferred)="onEntryUploadDeferred($event)">
<app-podcast-add-url-form *ngIf="urlMode" [podcast]="podcast" (onUrlAddComplete)="onUrlAddComplete($event)" (onPlaylistAdded)="processPlaylist($event)">
</app-podcast-add-url-form>
<div class="block block-themed" *ngIf="pendingEntry">
<div class="block-header bg-danger">
<h3 class="block-title">This looks like a playlist? Shall we add all items (please note, this may result in a lot of episodes
being downloaded to your device).</h3>
<div class="block-options">
<button type="button" class="btn-block-option" (click)="processPlaylist()">
<i class="fa fa-check"></i>Yes
</button>
<button type="button" class="btn-block-option" (click)="dismissPlaylist()">
<i class="fa fa-times"></i>No
</button>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<tbody>

View File

@@ -24,7 +24,6 @@ import { BasePageComponent } from '../base-page/base-page.component';
})
export class PodcastComponent extends BasePageComponent {
selectedPodcast$: Observable<PodcastModel>;
pendingEntry: PodcastEntryModel = null;
entries$: Observable<PodcastEntryModel[]>;
uploadMode = false;
urlMode = false;
@@ -96,16 +95,16 @@ export class PodcastComponent extends BasePageComponent {
this._store.dispatch(new fromEntriesActions.AddSuccessAction(entry));
this._store.dispatch(new fromEntriesActions.UpdateAction(entry));
}
onEntryUploadDeferred(entry: PodcastEntryModel) {
this.pendingEntry = entry;
}
onUrlAddComplete(entry: PodcastEntryModel) {
this.urlMode = false;
this._store.dispatch(new fromEntriesActions.AddSuccessAction(entry));
}
processPlaylist() {
if (this.pendingEntry) {
this._service.addPlaylist(this.pendingEntry).subscribe((e) => {
processPlaylist(entry: PodcastEntryModel) {
this.urlMode = false;
this.uploadMode = false;
this._service.addPlaylist(entry).subscribe((e) => {
if (e) {
this._toasty.info(
'Playlist added, check back here (and on your device) for new episodes'
@@ -114,8 +113,3 @@ export class PodcastComponent extends BasePageComponent {
});
}
}
dismissPlaylist() {
this.urlMode = false;
this.pendingEntry = null;
}
}

View File

@@ -0,0 +1,509 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PodNoms.Api.Persistence;
namespace PodNoms.Api.Migrations
{
[DbContext(typeof(PodNomsDbContext))]
[Migration("20180512101017_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.1.0-rc1-32029")
.HasAnnotation("Relational:MaxIdentifierLength", 128)
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex")
.HasFilter("[NormalizedName] IS NOT NULL");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider");
b.Property<string>("ProviderKey");
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider");
b.Property<string>("Name");
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("PodNoms.Api.Models.ChatMessage", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<DateTime>("CreateDate")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("getdate()");
b.Property<string>("FromUserId");
b.Property<string>("Message");
b.Property<DateTime?>("MessageSeen");
b.Property<Guid>("NewId")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("newsequentialid()");
b.Property<string>("ToUserId");
b.Property<string>("Uid");
b.Property<DateTime>("UpdateDate")
.ValueGeneratedOnAddOrUpdate()
.HasDefaultValueSql("getdate()");
b.HasKey("Id");
b.HasIndex("FromUserId");
b.HasIndex("ToUserId");
b.ToTable("ChatMessages");
});
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<DateTime>("CreateDate")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("getdate()");
b.Property<bool>("IsProcessed");
b.Property<Guid>("NewId")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("newsequentialid()");
b.Property<int?>("PlaylistId");
b.Property<string>("Uid");
b.Property<DateTime>("UpdateDate")
.ValueGeneratedOnAddOrUpdate()
.HasDefaultValueSql("getdate()");
b.Property<string>("VideoId");
b.Property<string>("VideoType");
b.HasKey("Id");
b.HasIndex("PlaylistId");
b.ToTable("ParsedPlaylistItems");
});
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<DateTime>("CreateDate")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("getdate()");
b.Property<Guid>("NewId")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("newsequentialid()");
b.Property<int?>("PodcastId");
b.Property<string>("SourceUrl");
b.Property<string>("Uid");
b.Property<DateTime>("UpdateDate")
.ValueGeneratedOnAddOrUpdate()
.HasDefaultValueSql("getdate()");
b.HasKey("Id");
b.HasIndex("PodcastId");
b.ToTable("Playlists");
});
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<string>("AppUserId");
b.Property<DateTime>("CreateDate")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("getdate()");
b.Property<string>("Description");
b.Property<Guid>("NewId")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("newsequentialid()");
b.Property<string>("Slug");
b.Property<string>("TemporaryImageUrl");
b.Property<string>("Title");
b.Property<string>("Uid");
b.Property<DateTime>("UpdateDate")
.ValueGeneratedOnAddOrUpdate()
.HasDefaultValueSql("getdate()");
b.HasKey("Id");
b.HasIndex("AppUserId");
b.ToTable("Podcasts");
});
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<long>("AudioFileSize");
b.Property<float>("AudioLength");
b.Property<string>("AudioUrl");
b.Property<string>("Author");
b.Property<DateTime>("CreateDate")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("getdate()");
b.Property<string>("Description");
b.Property<string>("ImageUrl");
b.Property<Guid>("NewId")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("newsequentialid()");
b.Property<int?>("PlaylistId");
b.Property<int?>("PodcastId");
b.Property<bool>("Processed");
b.Property<string>("ProcessingPayload");
b.Property<int>("ProcessingStatus");
b.Property<string>("SourceUrl");
b.Property<string>("Title");
b.Property<string>("Uid");
b.Property<DateTime>("UpdateDate")
.ValueGeneratedOnAddOrUpdate()
.HasDefaultValueSql("getdate()");
b.HasKey("Id");
b.HasIndex("PlaylistId");
b.HasIndex("PodcastId");
b.ToTable("PodcastEntries");
});
modelBuilder.Entity("PodNoms.Api.Models.ServerConfig", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
b.Property<DateTime>("CreateDate")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("getdate()");
b.Property<string>("Key");
b.Property<Guid>("NewId")
.ValueGeneratedOnAdd()
.HasDefaultValueSql("newsequentialid()");
b.Property<string>("Uid");
b.Property<DateTime>("UpdateDate")
.ValueGeneratedOnAddOrUpdate()
.HasDefaultValueSql("getdate()");
b.Property<string>("Value");
b.HasKey("Id");
b.ToTable("ServerConfig","admin");
});
modelBuilder.Entity("PodNoms.Api.Services.Auth.ApplicationUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<long?>("FacebookId");
b.Property<string>("FirstName");
b.Property<string>("LastName");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("PictureUrl");
b.Property<string>("SecurityStamp");
b.Property<string>("Slug");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex")
.HasFilter("[NormalizedUserName] IS NOT NULL");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("PodNoms.Api.Models.ChatMessage", b =>
{
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser", "FromUser")
.WithMany()
.HasForeignKey("FromUserId");
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser", "ToUser")
.WithMany()
.HasForeignKey("ToUserId");
});
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistItem", b =>
{
b.HasOne("PodNoms.Api.Models.Playlist", "Playlist")
.WithMany("ParsedPlaylistItems")
.HasForeignKey("PlaylistId");
});
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
{
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
.WithMany()
.HasForeignKey("PodcastId");
});
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
{
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser", "AppUser")
.WithMany()
.HasForeignKey("AppUserId");
});
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
{
b.HasOne("PodNoms.Api.Models.Playlist")
.WithMany("PodcastEntries")
.HasForeignKey("PlaylistId");
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
.WithMany("PodcastEntries")
.HasForeignKey("PodcastId");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,451 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
namespace PodNoms.Api.Migrations
{
public partial class Initial : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.EnsureSchema(
name: "admin");
migrationBuilder.CreateTable(
name: "AspNetRoles",
columns: table => new
{
Id = table.Column<string>(nullable: false),
Name = table.Column<string>(maxLength: 256, nullable: true),
NormalizedName = table.Column<string>(maxLength: 256, nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUsers",
columns: table => new
{
Id = table.Column<string>(nullable: false),
UserName = table.Column<string>(maxLength: 256, nullable: true),
NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
Email = table.Column<string>(maxLength: 256, nullable: true),
NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
EmailConfirmed = table.Column<bool>(nullable: false),
PasswordHash = table.Column<string>(nullable: true),
SecurityStamp = table.Column<string>(nullable: true),
ConcurrencyStamp = table.Column<string>(nullable: true),
PhoneNumber = table.Column<string>(nullable: true),
PhoneNumberConfirmed = table.Column<bool>(nullable: false),
TwoFactorEnabled = table.Column<bool>(nullable: false),
LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
LockoutEnabled = table.Column<bool>(nullable: false),
AccessFailedCount = table.Column<int>(nullable: false),
FirstName = table.Column<string>(nullable: true),
LastName = table.Column<string>(nullable: true),
FacebookId = table.Column<long>(nullable: true),
PictureUrl = table.Column<string>(nullable: true),
Slug = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ServerConfig",
schema: "admin",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Uid = table.Column<string>(nullable: true),
NewId = table.Column<Guid>(nullable: false, defaultValueSql: "newsequentialid()"),
CreateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
UpdateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
Key = table.Column<string>(nullable: true),
Value = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ServerConfig", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetRoleClaims",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
RoleId = table.Column<string>(nullable: false),
ClaimType = table.Column<string>(nullable: true),
ClaimValue = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
UserId = table.Column<string>(nullable: false),
ClaimType = table.Column<string>(nullable: true),
ClaimValue = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(nullable: false),
ProviderKey = table.Column<string>(nullable: false),
ProviderDisplayName = table.Column<string>(nullable: true),
UserId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<string>(nullable: false),
RoleId = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserTokens",
columns: table => new
{
UserId = table.Column<string>(nullable: false),
LoginProvider = table.Column<string>(nullable: false),
Name = table.Column<string>(nullable: false),
Value = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
table.ForeignKey(
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ChatMessages",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Uid = table.Column<string>(nullable: true),
NewId = table.Column<Guid>(nullable: false, defaultValueSql: "newsequentialid()"),
CreateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
UpdateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
FromUserId = table.Column<string>(nullable: true),
ToUserId = table.Column<string>(nullable: true),
Message = table.Column<string>(nullable: true),
MessageSeen = table.Column<DateTime>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ChatMessages", x => x.Id);
table.ForeignKey(
name: "FK_ChatMessages_AspNetUsers_FromUserId",
column: x => x.FromUserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_ChatMessages_AspNetUsers_ToUserId",
column: x => x.ToUserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Podcasts",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Uid = table.Column<string>(nullable: true),
NewId = table.Column<Guid>(nullable: false, defaultValueSql: "newsequentialid()"),
CreateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
UpdateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
AppUserId = table.Column<string>(nullable: true),
Title = table.Column<string>(nullable: true),
Description = table.Column<string>(nullable: true),
Slug = table.Column<string>(nullable: true),
TemporaryImageUrl = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Podcasts", x => x.Id);
table.ForeignKey(
name: "FK_Podcasts_AspNetUsers_AppUserId",
column: x => x.AppUserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "Playlists",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Uid = table.Column<string>(nullable: true),
NewId = table.Column<Guid>(nullable: false, defaultValueSql: "newsequentialid()"),
CreateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
UpdateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
SourceUrl = table.Column<string>(nullable: true),
PodcastId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Playlists", x => x.Id);
table.ForeignKey(
name: "FK_Playlists_Podcasts_PodcastId",
column: x => x.PodcastId,
principalTable: "Podcasts",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "ParsedPlaylistItems",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Uid = table.Column<string>(nullable: true),
NewId = table.Column<Guid>(nullable: false, defaultValueSql: "newsequentialid()"),
CreateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
UpdateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
VideoId = table.Column<string>(nullable: true),
VideoType = table.Column<string>(nullable: true),
IsProcessed = table.Column<bool>(nullable: false),
PlaylistId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ParsedPlaylistItems", x => x.Id);
table.ForeignKey(
name: "FK_ParsedPlaylistItems_Playlists_PlaylistId",
column: x => x.PlaylistId,
principalTable: "Playlists",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "PodcastEntries",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
Uid = table.Column<string>(nullable: true),
NewId = table.Column<Guid>(nullable: false, defaultValueSql: "newsequentialid()"),
CreateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
UpdateDate = table.Column<DateTime>(nullable: false, defaultValueSql: "getdate()"),
Author = table.Column<string>(nullable: true),
Title = table.Column<string>(nullable: true),
Description = table.Column<string>(nullable: true),
SourceUrl = table.Column<string>(nullable: true),
AudioUrl = table.Column<string>(nullable: true),
AudioLength = table.Column<float>(nullable: false),
AudioFileSize = table.Column<long>(nullable: false),
ImageUrl = table.Column<string>(nullable: true),
ProcessingPayload = table.Column<string>(nullable: true),
ProcessingStatus = table.Column<int>(nullable: false),
Processed = table.Column<bool>(nullable: false),
PodcastId = table.Column<int>(nullable: true),
PlaylistId = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_PodcastEntries", x => x.Id);
table.ForeignKey(
name: "FK_PodcastEntries_Playlists_PlaylistId",
column: x => x.PlaylistId,
principalTable: "Playlists",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_PodcastEntries_Podcasts_PodcastId",
column: x => x.PodcastId,
principalTable: "Podcasts",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_AspNetRoleClaims_RoleId",
table: "AspNetRoleClaims",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "RoleNameIndex",
table: "AspNetRoles",
column: "NormalizedName",
unique: true,
filter: "[NormalizedName] IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserClaims_UserId",
table: "AspNetUserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserLogins_UserId",
table: "AspNetUserLogins",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AspNetUserRoles_RoleId",
table: "AspNetUserRoles",
column: "RoleId");
migrationBuilder.CreateIndex(
name: "EmailIndex",
table: "AspNetUsers",
column: "NormalizedEmail");
migrationBuilder.CreateIndex(
name: "UserNameIndex",
table: "AspNetUsers",
column: "NormalizedUserName",
unique: true,
filter: "[NormalizedUserName] IS NOT NULL");
migrationBuilder.CreateIndex(
name: "IX_ChatMessages_FromUserId",
table: "ChatMessages",
column: "FromUserId");
migrationBuilder.CreateIndex(
name: "IX_ChatMessages_ToUserId",
table: "ChatMessages",
column: "ToUserId");
migrationBuilder.CreateIndex(
name: "IX_ParsedPlaylistItems_PlaylistId",
table: "ParsedPlaylistItems",
column: "PlaylistId");
migrationBuilder.CreateIndex(
name: "IX_Playlists_PodcastId",
table: "Playlists",
column: "PodcastId");
migrationBuilder.CreateIndex(
name: "IX_PodcastEntries_PlaylistId",
table: "PodcastEntries",
column: "PlaylistId");
migrationBuilder.CreateIndex(
name: "IX_PodcastEntries_PodcastId",
table: "PodcastEntries",
column: "PodcastId");
migrationBuilder.CreateIndex(
name: "IX_Podcasts_AppUserId",
table: "Podcasts",
column: "AppUserId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AspNetRoleClaims");
migrationBuilder.DropTable(
name: "AspNetUserClaims");
migrationBuilder.DropTable(
name: "AspNetUserLogins");
migrationBuilder.DropTable(
name: "AspNetUserRoles");
migrationBuilder.DropTable(
name: "AspNetUserTokens");
migrationBuilder.DropTable(
name: "ChatMessages");
migrationBuilder.DropTable(
name: "ParsedPlaylistItems");
migrationBuilder.DropTable(
name: "PodcastEntries");
migrationBuilder.DropTable(
name: "ServerConfig",
schema: "admin");
migrationBuilder.DropTable(
name: "AspNetRoles");
migrationBuilder.DropTable(
name: "Playlists");
migrationBuilder.DropTable(
name: "Podcasts");
migrationBuilder.DropTable(
name: "AspNetUsers");
}
}
}

View File

@@ -0,0 +1,9 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace PodNoms.Api.Models {
[Table("ServerConfig", Schema = "admin")]
public class ServerConfig : BaseEntity, IEntity {
public string Key { get; set; }
public string Value { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using System.Threading.Tasks;
using AutoMapper;
using PodNoms.Api.Models;
using PodNoms.Api.Models.ViewModels;
using PodNoms.Api.Persistence;
namespace PodNoms.Api.Providers {
internal class PodcastForeignKeyResolver : IValueResolver<PodcastEntryViewModel, PodcastEntry, Podcast> {
private IPodcastRepository _sourceRepository;
public PodcastForeignKeyResolver(IPodcastRepository sourceRepository) {
this._sourceRepository = sourceRepository;
}
public Podcast Resolve(PodcastEntryViewModel source, PodcastEntry destination, Podcast destMember, ResolutionContext context) {
return Task.Run(async () => await _sourceRepository.GetAsync(source.PodcastId)).Result;
}
}
}

26
server/SeedData.cs Normal file
View File

@@ -0,0 +1,26 @@
using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using PodNoms.Api.Models;
using PodNoms.Api.Persistence;
using PodNoms.Api.Utils.Extensions;
namespace PodNoms.Api {
internal class SeedData {
public static void Initialize(IServiceProvider serviceProvider) {
using (var context = new PodNomsDbContext(serviceProvider.GetRequiredService<DbContextOptions<PodNomsDbContext>>(), null)) {
context.Database.EnsureCreated();
if (context.ServerConfig.Any()) {
return; // DB has been seeded
}
context.ServerConfig.Add(new ServerConfig {
Key = "ServerScaffoldDate",
Value = DateTime.Now.ToRFC822String()
});
context.SaveChangesAsync().Wait();
}
}
}
}