From 9d12c234002bda48a8c3bf231b61b5c2b04dc053 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Tue, 29 Sep 2026 17:13:02 +0330 Subject: [PATCH] people tags #387 --- GanjooRazor/Pages/FamilyTree.cshtml | 82 + GanjooRazor/Pages/FamilyTree.cshtml.cs | 70 + GanjooRazor/Pages/People.cshtml | 1 + GanjooRazor/Pages/Person.cshtml | 5 +- GanjooRazor/wwwroot/js/familytree.js | 327 + .../GanjoorRelatedPersonController.cs | 18 + ...AddGanjoorPersonEditSuggestion.Designer.cs | 6484 +++++++++++++++++ ...29104427_AddGanjoorPersonEditSuggestion.cs | 105 + .../RMuseumDbContextModelSnapshot.cs | 117 + .../ViewModels/GanjoorFamilyTreeViewModel.cs | 43 + RMuseum/RMuseum.xml | 68 + .../Services/IGanjoorRelatedPersonService.cs | 9 + .../GanjoorRelatedPersonService.cs | 87 + 13 files changed, 7415 insertions(+), 1 deletion(-) create mode 100644 GanjooRazor/Pages/FamilyTree.cshtml create mode 100644 GanjooRazor/Pages/FamilyTree.cshtml.cs create mode 100644 GanjooRazor/wwwroot/js/familytree.js create mode 100644 RMuseum/Migrations/20260929104427_AddGanjoorPersonEditSuggestion.Designer.cs create mode 100644 RMuseum/Migrations/20260929104427_AddGanjoorPersonEditSuggestion.cs create mode 100644 RMuseum/Models/Ganjoor/ViewModels/GanjoorFamilyTreeViewModel.cs diff --git a/GanjooRazor/Pages/FamilyTree.cshtml b/GanjooRazor/Pages/FamilyTree.cshtml new file mode 100644 index 00000000..222306ac --- /dev/null +++ b/GanjooRazor/Pages/FamilyTree.cshtml @@ -0,0 +1,82 @@ +@page "{id:int}" +@model GanjooRazor.Pages.FamilyTreeModel +@{ + Layout = "_Layout"; +} +@section Head { + +} +@if (!string.IsNullOrEmpty(Model.LastError)) +{ + @Model.LastError +} +else +{ + + +
+ +
+ + + +
 
+ +
+

+ شجره‌نامهٔ @(string.IsNullOrEmpty(Model.RootPerson.FamilyTreeCaption) ? Model.RootPerson.Name : Model.RootPerson.FamilyTreeCaption) + بازگشت به صفحهٔ شخصیت +

+

+ برای مشاهدهٔ توضیحات هر شخصیت، روی آن کلیک کنید. برای پیمایش نمودار آن را با ماوس بکشید و با غلتک ماوس بزرگ/کوچک کنید. + این نمودار محدود به فرزندان این شخصیت نیست؛ تمام خویشاوندان به‌هم‌پیوسته (از جمله نیاکان و خانوادهٔ همسر) را نشان می‌دهد. +

+ +
+ + +
+
+ +
 
+ +
+ + + +
+ + + + + + + + @if (ViewData["TrackingScript"] != null && !string.IsNullOrEmpty(ViewData["TrackingScript"].ToString())) + { + @Html.Raw(ViewData["TrackingScript"]) + } +} diff --git a/GanjooRazor/Pages/FamilyTree.cshtml.cs b/GanjooRazor/Pages/FamilyTree.cshtml.cs new file mode 100644 index 00000000..1a884ed0 --- /dev/null +++ b/GanjooRazor/Pages/FamilyTree.cshtml.cs @@ -0,0 +1,70 @@ +using System.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Newtonsoft.Json; +using RMuseum.Models.Ganjoor; +using RMuseum.Models.Ganjoor.ViewModels; + +namespace GanjooRazor.Pages +{ + /// + /// interactive family-tree chart, drawn client-side (vanilla JS/SVG - see the <script> block + /// in FamilyTree.cshtml) from the connected kinship component GET api/people/{id}/familytree + /// returns. Public/read-only counterpart of Person.cshtml's plain relatives list, reachable from + /// there and from People.cshtml's family-tree index. + /// + public class FamilyTreeModel : LoginPartialEnabledPageModel + { + public FamilyTreeModel(HttpClient httpClient, IConfiguration configuration) : base(httpClient, configuration) + { + } + + public string LastError { get; set; } + + public GanjoorRelatedPerson RootPerson { get; set; } + + public GanjoorFamilyTreeViewModel Tree { get; set; } + + /// + /// Tree, re-serialized with an explicit camelCase contract (same convention ReviewEdits.cshtml.cs + /// uses for AllLocationsJson/AllPeopleJson) so the client-side layout script has a predictable + /// shape to parse, regardless of the API's own default casing + /// + public string TreeDataJson => + JsonConvert.SerializeObject( + Tree, + new JsonSerializerSettings { ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() } + ); + + public async Task OnGetAsync(int id) + { + InitializeCommonPageState(); + + var personResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/people/{id}"); + if (!personResponse.IsSuccessStatusCode) + { + LastError = await ReadErrorMessageAsync(personResponse); + return Page(); + } + RootPerson = JsonConvert.DeserializeObject(await personResponse.Content.ReadAsStringAsync()); + if (RootPerson == null) + { + LastError = "شخصیتی با این کد پیدا نشد."; + return Page(); + } + + ViewData["Title"] = $"گنجور » شجره‌نامهٔ {(string.IsNullOrEmpty(RootPerson.FamilyTreeCaption) ? RootPerson.Name : RootPerson.FamilyTreeCaption)}"; + + var treeResponse = await _httpClient.GetAsync($"{APIRoot.Url}/api/people/{id}/familytree"); + if (!treeResponse.IsSuccessStatusCode) + { + LastError = await ReadErrorMessageAsync(treeResponse); + return Page(); + } + Tree = JsonConvert.DeserializeObject(await treeResponse.Content.ReadAsStringAsync()); + + return Page(); + } + } +} diff --git a/GanjooRazor/Pages/People.cshtml b/GanjooRazor/Pages/People.cshtml index 75dda7ea..5540afd9 100644 --- a/GanjooRazor/Pages/People.cshtml +++ b/GanjooRazor/Pages/People.cshtml @@ -36,6 +36,7 @@ else
  • @root.FamilyTreeCaption (@root.Name) + — نمایش نمودار
  • } diff --git a/GanjooRazor/Pages/Person.cshtml b/GanjooRazor/Pages/Person.cshtml index 9288e510..3e5f048d 100644 --- a/GanjooRazor/Pages/Person.cshtml +++ b/GanjooRazor/Pages/Person.cshtml @@ -66,7 +66,10 @@ else {
     
    -

    خویشاوندان

    +

    + خویشاوندان + نمایش نمودار شجره‌نامه +

      @foreach (var row in Model.RelationRows) { diff --git a/GanjooRazor/wwwroot/js/familytree.js b/GanjooRazor/wwwroot/js/familytree.js new file mode 100644 index 00000000..0c61b13c --- /dev/null +++ b/GanjooRazor/wwwroot/js/familytree.js @@ -0,0 +1,327 @@ +// Renders the interactive family-tree chart on /FamilyTree/{id}. Pure vanilla JS + SVG - no external +// charting library - since the shape of the problem (a handful to a few hundred nodes, drawn once, +// panned/zoomed by the user) doesn't need one, and the project prefers self-hosted, dependency-light +// front-end code. +// +// Input (window.familyTreeData, set inline by FamilyTree.cshtml): the JSON of +// RMuseum.Models.Ganjoor.ViewModels.GanjoorFamilyTreeViewModel, camelCased - +// { rootId, persons: [{id, name, birthYearInLHijri, deathYearInLHijri, validBirthDate, +// validDeathDate, description, wikiUrl, familyTreeCaption, ...}], relations: [{person1Id, +// person2Id, relationType, degreeHint}] } where relationType is PersonRelationType's numeric +// value: 0=Parent, 1=Sibling, 2=Spouse, 3=Ancestor (Person1 is the parent/ancestor side for +// 0 and 3; order doesn't matter for 1 and 2). +// +// The graph is a general kinship graph, not a strict tree (a person can have two recorded parents, +// multiple spouses, etc.), so this builds a reasonable tree-like DRAWING out of it with a few +// simplifying choices - see comments below - rather than claiming to be an exact rendering of every +// edge. That mirrors what similar Shahnameh genealogy charts do in practice. + +(function () { + 'use strict'; + + function dedup(arr) { + return arr ? Array.from(new Set(arr)) : []; + } + + function buildLayout(data, requestedRootId) { + var persons = {}; + data.persons.forEach(function (p) { persons[p.id] = p; }); + + var parentsOf = {}; // childId -> [parentId,...] + var childrenOf = {}; // parentId -> [childId,...] + var spouseOf = {}; // id -> [spouseId,...] + + function addParentChild(parentId, childId) { + (parentsOf[childId] = parentsOf[childId] || []).push(parentId); + (childrenOf[parentId] = childrenOf[parentId] || []).push(childId); + } + function addSpouse(a, b) { + (spouseOf[a] = spouseOf[a] || []).push(b); + (spouseOf[b] = spouseOf[b] || []).push(a); + } + + (data.relations || []).forEach(function (r) { + if (r.relationType === 0 || r.relationType === 3) { + addParentChild(r.person1Id, r.person2Id); + } else if (r.relationType === 2) { + addSpouse(r.person1Id, r.person2Id); + } + // relationType === 1 (Sibling) isn't needed for layout: siblings normally end up + // adjacent anyway once they share a primaryParentOf below. + }); + + Object.keys(childrenOf).forEach(function (k) { childrenOf[k] = dedup(childrenOf[k]); }); + Object.keys(parentsOf).forEach(function (k) { parentsOf[k] = dedup(parentsOf[k]); }); + Object.keys(spouseOf).forEach(function (k) { spouseOf[k] = dedup(spouseOf[k]); }); + + var allIds = data.persons.map(function (p) { return p.id; }); + var isRoot = {}; + allIds.forEach(function (id) { isRoot[id] = !parentsOf[id] || parentsOf[id].length === 0; }); + + // one child can have two recorded parents (mother + father) - pick a single "primary" + // parent per child to build a drawable tree, preferring whichever parent is NOT themselves + // a chart-root (so the root-level spouse ends up as the "attached" side, see below) + var primaryParentOf = {}; + var secondaryParentOf = {}; + allIds.forEach(function (childId) { + var ps = parentsOf[childId]; + if (!ps || ps.length === 0) return; + if (ps.length === 1) { primaryParentOf[childId] = ps[0]; return; } + var sorted = ps.slice().sort(function (a, b) { + var ar = isRoot[a] ? 1 : 0, br = isRoot[b] ? 1 : 0; + if (ar !== br) return ar - br; + return a - b; + }); + primaryParentOf[childId] = sorted[0]; + secondaryParentOf[childId] = sorted[1]; + }); + + var hasOwnChildren = {}; + Object.keys(primaryParentOf).forEach(function (childId) { + hasOwnChildren[primaryParentOf[childId]] = true; + }); + + // a childless, parentless spouse (the common case - a wife with no recorded parents/kids + // of her own beyond this marriage) is drawn as a small box attached beside their partner + // rather than given their own column, same visual idea as the heart-linked pairs in + // akhakhafrasiyab.ir's chart + var attachedTo = {}; // spouseId -> primaryId + var attachedList = {}; // primaryId -> [spouseId,...] + + function tryAttach(primaryId, spouseId) { + if (attachedTo[spouseId] !== undefined || spouseId === primaryId) return false; + if (isRoot[spouseId] && !hasOwnChildren[spouseId]) { + attachedTo[spouseId] = primaryId; + (attachedList[primaryId] = attachedList[primaryId] || []).push(spouseId); + return true; + } + return false; + } + + Object.keys(secondaryParentOf).forEach(function (childId) { + tryAttach(primaryParentOf[childId], secondaryParentOf[childId]); + }); + Object.keys(spouseOf).forEach(function (a) { + spouseOf[a].forEach(function (b) { + if (attachedTo[a] !== undefined || attachedTo[b] !== undefined) return; + if (tryAttach(a, b)) return; + tryAttach(b, a); + }); + }); + + var topLevelRoots = allIds.filter(function (id) { return isRoot[id] && attachedTo[id] === undefined; }); + + function subtreeContains(rootId, targetId, guard) { + guard = guard || {}; + if (rootId === targetId) return true; + if (guard[rootId]) return false; + guard[rootId] = true; + var kids = childrenOf[rootId] || []; + for (var i = 0; i < kids.length; i++) if (subtreeContains(kids[i], targetId, guard)) return true; + var att = attachedList[rootId] || []; + for (var j = 0; j < att.length; j++) if (att[j] === targetId) return true; + return false; + } + topLevelRoots.sort(function (a, b) { + var aHas = subtreeContains(a, requestedRootId) ? 0 : 1; + var bHas = subtreeContains(b, requestedRootId) ? 0 : 1; + if (aHas !== bHas) return aHas - bHas; + return a - b; + }); + + // classic tidy-tree-ish pass: leaves get sequential column indices, a parent's column is + // the midpoint of its children's - good enough for the mostly-linear/lightly-branching + // lineages this data tends to have + var xCounter = 0; + var nodeX = {}, nodeDepth = {}; + function layout(id, depth) { + nodeDepth[id] = depth; + var kids = dedup(childrenOf[id] || []).sort(function (a, b) { return a - b; }); + if (kids.length === 0) { + nodeX[id] = xCounter++; + } else { + kids.forEach(function (k) { layout(k, depth + 1); }); + var xs = kids.map(function (k) { return nodeX[k]; }); + nodeX[id] = (Math.min.apply(null, xs) + Math.max.apply(null, xs)) / 2; + } + } + topLevelRoots.forEach(function (r) { layout(r, 0); }); + + return { + persons: persons, + childrenOf: childrenOf, + primaryParentOf: primaryParentOf, + secondaryParentOf: secondaryParentOf, + attachedList: attachedList, + topLevelRoots: topLevelRoots, + nodeX: nodeX, + nodeDepth: nodeDepth + }; + } + + var SVG_NS = 'http://www.w3.org/2000/svg'; + function el(tag, attrs) { + var e = document.createElementNS(SVG_NS, tag); + if (attrs) { + Object.keys(attrs).forEach(function (k) { e.setAttribute(k, attrs[k]); }); + } + return e; + } + + function personLabel(p) { + var s = p.name || ''; + return s; + } + + function renderFamilyTree(containerId, svgId, tooltipId, data, requestedRootId) { + var container = document.getElementById(containerId); + var svg = document.getElementById(svgId); + var tooltip = document.getElementById(tooltipId); + if (!container || !svg || !data || !data.persons || data.persons.length === 0) return; + + var layoutInfo = buildLayout(data, requestedRootId); + + var COL_WIDTH = 220; + var ROW_HEIGHT = 130; + var BOX_W = 140; + var BOX_H = 56; + var ATTACH_GAP = 14; + var ATTACH_W = 100; + var MARGIN = 60; + + var canvas = el('g', { id: 'ft-canvas', transform: 'translate(0,0) scale(1)' }); + while (svg.firstChild) svg.removeChild(svg.firstChild); + svg.appendChild(canvas); + + var linesGroup = el('g', { 'class': 'ft-lines' }); + var nodesGroup = el('g', { 'class': 'ft-nodes' }); + canvas.appendChild(linesGroup); + canvas.appendChild(nodesGroup); + + function pos(id) { + return { + x: MARGIN + layoutInfo.nodeX[id] * COL_WIDTH, + y: MARGIN + layoutInfo.nodeDepth[id] * ROW_HEIGHT + }; + } + + function line(x1, y1, x2, y2, cls) { + var l = el('path', { + d: 'M ' + x1 + ' ' + y1 + ' C ' + x1 + ' ' + (y1 + (y2 - y1) / 2) + ', ' + x2 + ' ' + (y1 + (y2 - y1) / 2) + ', ' + x2 + ' ' + y2, + 'class': cls || 'ft-line' + }); + linesGroup.appendChild(l); + } + + // parent -> child connectors + Object.keys(layoutInfo.primaryParentOf).forEach(function (childId) { + childId = parseInt(childId, 10); + var parentId = layoutInfo.primaryParentOf[childId]; + if (layoutInfo.nodeX[parentId] === undefined || layoutInfo.nodeX[childId] === undefined) return; + var pp = pos(parentId), cp = pos(childId); + line(pp.x, pp.y + BOX_H / 2, cp.x, cp.y - BOX_H / 2, 'ft-line ft-line-parent'); + }); + + var maxX = 0, maxY = 0; + + function drawBox(id, x, y, w, h, isRequested) { + var p = layoutInfo.persons[id]; + var g = el('g', { 'class': 'ft-node', 'data-person-id': id, style: 'cursor:pointer' }); + var rect = el('rect', { + x: x - w / 2, y: y - h / 2, width: w, height: h, rx: 8, ry: 8, + 'class': isRequested ? 'ft-box ft-box-current' : 'ft-box' + }); + g.appendChild(rect); + var text = el('text', { + x: x, y: y + 5, 'text-anchor': 'middle', 'class': 'ft-box-text', direction: 'rtl' + }); + text.textContent = personLabel(p); + g.appendChild(text); + g.addEventListener('click', function () { showDetails(p); }); + nodesGroup.appendChild(g); + maxX = Math.max(maxX, x + w / 2); + maxY = Math.max(maxY, y + h / 2); + } + + Object.keys(layoutInfo.nodeX).forEach(function (idStr) { + var id = parseInt(idStr, 10); + var p = pos(id); + drawBox(id, p.x, p.y, BOX_W, BOX_H, id === requestedRootId); + + var attached = layoutInfo.attachedList[id] || []; + attached.forEach(function (spouseId, i) { + var ax = p.x + BOX_W / 2 + ATTACH_GAP + ATTACH_W / 2 + i * (ATTACH_W + ATTACH_GAP); + var ay = p.y; + drawBox(spouseId, ax, ay, ATTACH_W, BOX_H, spouseId === requestedRootId); + line(p.x + BOX_W / 2, p.y, ax - ATTACH_W / 2, ay, 'ft-line ft-line-spouse'); + var heartX = p.x + BOX_W / 2 + ATTACH_GAP / 2; + var heart = el('text', { x: heartX, y: ay + 4, 'text-anchor': 'middle', 'class': 'ft-heart' }); + heart.textContent = '♥'; + nodesGroup.appendChild(heart); + maxX = Math.max(maxX, ax + ATTACH_W / 2); + }); + }); + + svg.setAttribute('viewBox', '0 0 ' + (maxX + MARGIN) + ' ' + (maxY + MARGIN)); + + function showDetails(p) { + if (!tooltip) return; + var html = '' + + '

      ' + escapeHtml(personLabel(p)) + '

      '; + if (p.birthYearInLHijri || p.deathYearInLHijri) { + html += '

      '; + if (p.birthYearInLHijri) html += 'زاده ' + p.birthYearInLHijri.toLocaleString('fa-IR') + (p.validBirthDate ? '' : ' (تخمینی)'); + if (p.birthYearInLHijri && p.deathYearInLHijri) html += ' — '; + if (p.deathYearInLHijri) html += 'وفات ' + p.deathYearInLHijri.toLocaleString('fa-IR') + (p.validDeathDate ? '' : ' (تخمینی)'); + html += '

      '; + } + if (p.description) { + html += '

      ' + escapeHtml(p.description) + '

      '; + } + html += '

      مشاهدهٔ صفحهٔ شخصیت

      '; + tooltip.innerHTML = html; + tooltip.style.display = 'block'; + tooltip.querySelector('.ft-tooltip-close').addEventListener('click', function () { + tooltip.style.display = 'none'; + }); + } + + function escapeHtml(s) { + var d = document.createElement('div'); + d.textContent = s || ''; + return d.innerHTML; + } + + // pan + zoom - a small, dependency-free version of the usual SVG drag/wheel recipe + var scale = 1, tx = 0, ty = 0; + var dragging = false, lastX = 0, lastY = 0; + + function applyTransform() { + canvas.setAttribute('transform', 'translate(' + tx + ',' + ty + ') scale(' + scale + ')'); + } + + svg.addEventListener('mousedown', function (e) { + dragging = true; lastX = e.clientX; lastY = e.clientY; + svg.style.cursor = 'grabbing'; + }); + window.addEventListener('mouseup', function () { dragging = false; svg.style.cursor = 'grab'; }); + window.addEventListener('mousemove', function (e) { + if (!dragging) return; + tx += (e.clientX - lastX); ty += (e.clientY - lastY); + lastX = e.clientX; lastY = e.clientY; + applyTransform(); + }); + svg.addEventListener('wheel', function (e) { + e.preventDefault(); + var factor = e.deltaY < 0 ? 1.1 : 0.9; + scale = Math.min(3, Math.max(0.2, scale * factor)); + applyTransform(); + }, { passive: false }); + svg.style.cursor = 'grab'; + svg.removeAttribute('viewBox'); // pan/zoom via transform, not viewBox, once we have a canvas group + svg.setAttribute('width', Math.max(container.clientWidth, maxX + MARGIN)); + svg.setAttribute('height', Math.max(container.clientHeight, maxY + MARGIN)); + } + + window.GanjoorFamilyTree = { render: renderFamilyTree }; +})(); diff --git a/RMuseum/Controllers/GanjoorRelatedPersonController.cs b/RMuseum/Controllers/GanjoorRelatedPersonController.cs index fc3d5fd4..581b67b8 100644 --- a/RMuseum/Controllers/GanjoorRelatedPersonController.cs +++ b/RMuseum/Controllers/GanjoorRelatedPersonController.cs @@ -111,6 +111,24 @@ namespace RMuseum.Controllers return Ok(res.Result); } + /// + /// get the whole connected kinship component reachable from this person (ancestors, + /// descendants, spouses, siblings), for the interactive family-tree chart + /// + /// + /// + [HttpGet("{id:int}/familytree")] + [AllowAnonymous] + [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorFamilyTreeViewModel))] + [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] + public async Task GetFamilyTreeAsync(int id) + { + var res = await _personService.GetFamilyTreeAsync(id); + if (!string.IsNullOrEmpty(res.ExceptionString)) + return BadRequest(res.ExceptionString); + return Ok(res.Result); + } + /// /// suggest an edit to an already-approved person's own fields - any logged-in user, same as /// suggesting a poem correction. Goes into the pending queue; does not change the person. diff --git a/RMuseum/Migrations/20260929104427_AddGanjoorPersonEditSuggestion.Designer.cs b/RMuseum/Migrations/20260929104427_AddGanjoorPersonEditSuggestion.Designer.cs new file mode 100644 index 00000000..70d19caf --- /dev/null +++ b/RMuseum/Migrations/20260929104427_AddGanjoorPersonEditSuggestion.Designer.cs @@ -0,0 +1,6484 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using RMuseum.DbContext; + +#nullable disable + +namespace RMuseum.Migrations +{ + [DbContext(typeof(RMuseumDbContext))] + [Migration("20260929104427_AddGanjoorPersonEditSuggestion")] + partial class AddGanjoorPersonEditSuggestion + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("RMuseum.Models.Accounting.DonationExpenditure", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("GanjoorDonationId") + .HasColumnType("int"); + + b.Property("GanjoorExpenseId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("GanjoorDonationId"); + + b.HasIndex("GanjoorExpenseId"); + + b.ToTable("DonationExpenditure"); + }); + + modelBuilder.Entity("RMuseum.Models.Accounting.GanjoorDonation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("AmountString") + .HasColumnType("nvarchar(max)"); + + b.Property("DateString") + .HasColumnType("nvarchar(max)"); + + b.Property("DonorLink") + .HasColumnType("nvarchar(max)"); + + b.Property("DonorName") + .HasColumnType("nvarchar(max)"); + + b.Property("ExpenditureDesc") + .HasColumnType("nvarchar(max)"); + + b.Property("ImportedRecord") + .HasColumnType("bit"); + + b.Property("RecordDate") + .HasColumnType("datetime2"); + + b.Property("Remaining") + .HasColumnType("decimal(18,2)"); + + b.Property("Unit") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("GanjoorDonations"); + }); + + modelBuilder.Entity("RMuseum.Models.Accounting.GanjoorExpense", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("decimal(18,2)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("ExpenseDate") + .HasColumnType("datetime2"); + + b.Property("Unit") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("GanjoorExpenses"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RArtifactItemRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CoverImageIndex") + .HasColumnType("int"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DescriptionInEnglish") + .HasColumnType("nvarchar(max)"); + + b.Property("FriendlyUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("NameInEnglish") + .HasColumnType("nvarchar(max)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("RArtifactMasterRecordId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RArtifactMasterRecordId", "FriendlyUrl") + .IsUnique() + .HasFilter("[FriendlyUrl] IS NOT NULL"); + + b.HasIndex("RArtifactMasterRecordId", "Order") + .IsUnique(); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RArtifactMasterRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CoverImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("CoverItemIndex") + .HasColumnType("int"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DescriptionInEnglish") + .HasColumnType("nvarchar(max)"); + + b.Property("FriendlyUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("ItemCount") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("NameInEnglish") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CoverImageId"); + + b.HasIndex("FriendlyUrl") + .IsUnique() + .HasFilter("[FriendlyUrl] IS NOT NULL"); + + b.HasIndex("LastModified"); + + b.HasIndex("CoverItemIndex", "Status"); + + b.ToTable("Artifacts"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("FriendlyUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("GlobalValue") + .HasColumnType("bit"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("NameInEnglish") + .HasColumnType("nvarchar(max)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("PluralName") + .HasColumnType("nvarchar(max)"); + + b.Property("PluralNameInEnglish") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TagType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("FriendlyUrl"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RTagValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BookId") + .HasColumnType("int"); + + b.Property("FriendlyUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("PDFBookId") + .HasColumnType("int"); + + b.Property("PDFPageId") + .HasColumnType("int"); + + b.Property("RArtifactItemRecordId") + .HasColumnType("uniqueidentifier"); + + b.Property("RArtifactMasterRecordId") + .HasColumnType("uniqueidentifier"); + + b.Property("RTagId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.Property("ValueInEnglish") + .HasColumnType("nvarchar(max)"); + + b.Property("ValueSupplement") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("BookId"); + + b.HasIndex("FriendlyUrl"); + + b.HasIndex("PDFBookId"); + + b.HasIndex("PDFPageId"); + + b.HasIndex("RArtifactItemRecordId"); + + b.HasIndex("RArtifactMasterRecordId"); + + b.HasIndex("RTagId"); + + b.ToTable("TagValues"); + }); + + modelBuilder.Entity("RMuseum.Models.Bookmark.RUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("RAppUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RArtifactItemRecordId") + .HasColumnType("uniqueidentifier"); + + b.Property("RArtifactMasterRecordId") + .HasColumnType("uniqueidentifier"); + + b.Property("RBookmarkType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("RAppUserId"); + + b.HasIndex("RArtifactItemRecordId"); + + b.HasIndex("RArtifactMasterRecordId"); + + b.ToTable("UserBookmarks"); + }); + + modelBuilder.Entity("RMuseum.Models.ExternalFTPUpload.QueuedFTPUpload", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DeleteFileAfterUpload") + .HasColumnType("bit"); + + b.Property("Error") + .HasColumnType("nvarchar(max)"); + + b.Property("LocalFilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("ProcessDate") + .HasColumnType("datetime2"); + + b.Property("Processing") + .HasColumnType("bit"); + + b.Property("QueueDate") + .HasColumnType("datetime2"); + + b.Property("RemoteFilePath") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("QueuedFTPUploads"); + }); + + modelBuilder.Entity("RMuseum.Models.FAQ.FAQCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CatOrder") + .HasColumnType("int"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Published") + .HasColumnType("bit"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("FAQCategories"); + }); + + modelBuilder.Entity("RMuseum.Models.FAQ.FAQItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AnswerExcerpt") + .HasColumnType("nvarchar(max)"); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("ContentForSearch") + .HasColumnType("nvarchar(max)"); + + b.Property("FullAnswer") + .HasColumnType("nvarchar(max)"); + + b.Property("HashTag1") + .HasColumnType("nvarchar(max)"); + + b.Property("HashTag2") + .HasColumnType("nvarchar(max)"); + + b.Property("HashTag3") + .HasColumnType("nvarchar(max)"); + + b.Property("HashTag4") + .HasColumnType("nvarchar(max)"); + + b.Property("ItemOrderInCategory") + .HasColumnType("int"); + + b.Property("Pinned") + .HasColumnType("bit"); + + b.Property("PinnedItemOrder") + .HasColumnType("int"); + + b.Property("Published") + .HasColumnType("bit"); + + b.Property("Question") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("FAQItems"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.CategoryWordCount", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CatId") + .HasColumnType("int"); + + b.Property("Count") + .HasColumnType("int"); + + b.Property("RowNmbrInCat") + .HasColumnType("int"); + + b.Property("Word") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("CatId", "Word") + .IsUnique() + .HasFilter("[Word] IS NOT NULL"); + + b.ToTable("CategoryWordCounts"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.CategoryWordCountSummary", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CatId") + .HasColumnType("int"); + + b.Property("TotalWordCount") + .HasColumnType("int"); + + b.Property("UniqueWordCount") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CatId") + .IsUnique(); + + b.ToTable("CategoryWordCountSummaries"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.DigitalSource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoupletsCount") + .HasColumnType("int"); + + b.Property("FullName") + .HasColumnType("nvarchar(max)"); + + b.Property("ShortName") + .HasColumnType("nvarchar(max)"); + + b.Property("SourceType") + .HasColumnType("nvarchar(max)"); + + b.Property("UrlSlug") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("DigitalSources"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.DiscoverQuotedQueueItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("RelatedPoemId") + .HasColumnType("int"); + + b.Property("RelatedPoetId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("DiscoverQuotedQueueItems"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCachedRelatedPoem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FullTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("FullUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("HtmlExcerpt") + .HasColumnType("nvarchar(max)"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("PoetImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("PoetMorePoemsLikeThisCount") + .HasColumnType("int"); + + b.Property("PoetName") + .HasColumnType("nvarchar(max)"); + + b.Property("RelationOrder") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("FullUrl"); + + b.HasIndex("PoemId"); + + b.ToTable("GanjoorCachedRelatedPoems"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCachedRelatedSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FullTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("FullUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("HtmlExcerpt") + .HasColumnType("nvarchar(max)"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("PoetImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("PoetMorePoemsLikeThisCount") + .HasColumnType("int"); + + b.Property("PoetName") + .HasColumnType("nvarchar(max)"); + + b.Property("RelationOrder") + .HasColumnType("int"); + + b.Property("SectionIndex") + .HasColumnType("int"); + + b.Property("TargetPoemId") + .HasColumnType("int"); + + b.Property("TargetSectionIndex") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PoemId", "SectionIndex"); + + b.ToTable("GanjoorCachedRelatedSections"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCat", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("BookName") + .HasColumnType("nvarchar(max)"); + + b.Property("CatType") + .HasColumnType("int"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DescriptionHtml") + .HasColumnType("nvarchar(max)"); + + b.Property("FullUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("MapName") + .HasColumnType("nvarchar(max)"); + + b.Property("MixedModeOrder") + .HasColumnType("int"); + + b.Property("ParentId") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("Published") + .HasColumnType("bit"); + + b.Property("RImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("SumUpSubsGeoLocations") + .HasColumnType("bit"); + + b.Property("TableOfContentsStyle") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("UrlSlug") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("FullUrl"); + + b.HasIndex("PoetId"); + + b.HasIndex("RImageId"); + + b.HasIndex("ParentId", "PoetId"); + + SqlServerIndexBuilderExtensions.IncludeProperties(b.HasIndex("ParentId", "PoetId"), new[] { "Id" }); + + b.ToTable("GanjoorCategories"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCatCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AffectedTheCat") + .HasColumnType("bit"); + + b.Property("ApplicationOrder") + .HasColumnType("int"); + + b.Property("CatId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DescriptionHtml") + .HasColumnType("nvarchar(max)"); + + b.Property("HideMyName") + .HasColumnType("bit"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalDescription") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalDescriptionHtml") + .HasColumnType("nvarchar(max)"); + + b.Property("PageId") + .HasColumnType("int"); + + b.Property("Result") + .HasColumnType("int"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewNote") + .HasColumnType("nvarchar(max)"); + + b.Property("Reviewed") + .HasColumnType("bit"); + + b.Property("ReviewerUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("CatId"); + + b.HasIndex("ReviewerUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GanjoorCatCorrections"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCentury", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EndYear") + .HasColumnType("int"); + + b.Property("HalfCenturyOrder") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("ShowInTimeLine") + .HasColumnType("bit"); + + b.Property("StartYear") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("GanjoorCenturies"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCenturyPoet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("GanjoorCenturyId") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("PoetOrder") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("GanjoorCenturyId"); + + b.HasIndex("PoetId"); + + b.ToTable("GanjoorCenturyPoet"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorComment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("AuthorIpAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("AuthorName") + .HasColumnType("nvarchar(max)"); + + b.Property("AuthorUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("CommentDate") + .HasColumnType("datetime2"); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("DislikeCount") + .HasColumnType("int"); + + b.Property("HtmlComment") + .HasColumnType("nvarchar(max)"); + + b.Property("InReplyToId") + .HasColumnType("int"); + + b.Property("LikeCount") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("SortKey") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Verse12d") + .HasColumnType("int"); + + b.Property("Verse1Id") + .HasColumnType("int"); + + b.Property("Verse2Id") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CommentDate"); + + b.HasIndex("InReplyToId"); + + b.HasIndex("Status"); + + b.HasIndex("UserId"); + + b.HasIndex("Verse1Id"); + + b.HasIndex("Verse2Id"); + + b.HasIndex("PoemId", "CommentDate"); + + b.HasIndex("PoemId", "SortKey"); + + b.ToTable("GanjoorComments"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCommentAbuseReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("GanjoorCommentId") + .HasColumnType("int"); + + b.Property("ReasonCode") + .HasColumnType("nvarchar(max)"); + + b.Property("ReasonText") + .HasColumnType("nvarchar(max)"); + + b.Property("ReportedById") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("GanjoorCommentId"); + + b.HasIndex("ReportedById"); + + b.ToTable("GanjoorReportedComments"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCommentReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("GanjoorCommentId") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("ReactionDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("GanjoorCommentId", "UserId") + .IsUnique(); + + b.HasIndex("PoemId", "UserId"); + + b.ToTable("GanjoorCommentReactions"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorDuplicate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DestPoemId") + .HasColumnType("int"); + + b.Property("SrcCatId") + .HasColumnType("int"); + + b.Property("SrcPoemId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("DestPoemId"); + + b.HasIndex("SrcPoemId"); + + b.ToTable("GanjoorDuplicates"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorGeoLocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Latitude") + .HasColumnType("decimal(12,9)"); + + b.Property("Longitude") + .HasColumnType("decimal(12,9)"); + + b.Property("MachineGenerated") + .HasColumnType("bit"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("GanjoorGeoLocations"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorHealthCheckError", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BrokenLink") + .HasColumnType("bit"); + + b.Property("MulipleTargets") + .HasColumnType("bit"); + + b.Property("ReferrerPageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("TargetUrl") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("GanjoorHealthCheckErrors"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorLanguage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Code") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("NativeName") + .HasColumnType("nvarchar(max)"); + + b.Property("RightToLeft") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique() + .HasFilter("[Name] IS NOT NULL"); + + b.ToTable("GanjoorLanguages"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorMetre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("Rhythm") + .HasColumnType("nvarchar(max)"); + + b.Property("UrlSlug") + .HasColumnType("nvarchar(max)"); + + b.Property("VerseCount") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("GanjoorMetres"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorNumbering", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("EndCatId") + .HasColumnType("int"); + + b.Property("LastCountingDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("StartCatId") + .HasColumnType("int"); + + b.Property("TotalCouplets") + .HasColumnType("int"); + + b.Property("TotalLines") + .HasColumnType("int"); + + b.Property("TotalParagraphs") + .HasColumnType("int"); + + b.Property("TotalVerses") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("EndCatId"); + + b.HasIndex("StartCatId"); + + b.ToTable("GanjoorNumberings"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPage", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("CatId") + .HasColumnType("int"); + + b.Property("FullTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("FullUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("GanjoorPageType") + .HasColumnType("int"); + + b.Property("HtmlText") + .HasColumnType("nvarchar(max)"); + + b.Property("NoIndex") + .HasColumnType("bit"); + + b.Property("PageOrder") + .HasColumnType("int"); + + b.Property("ParentId") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("PostDate") + .HasColumnType("datetime2"); + + b.Property("Published") + .HasColumnType("bit"); + + b.Property("RedirectFromFullUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("SecondPoetId") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("UrlSlug") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CatId"); + + b.HasIndex("FullUrl"); + + b.HasIndex("ParentId"); + + b.HasIndex("PoemId"); + + b.HasIndex("PoetId"); + + b.HasIndex("SecondPoetId"); + + b.ToTable("GanjoorPages"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPageSnapshot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("GanjoorPageId") + .HasColumnType("int"); + + b.Property("HtmlText") + .HasColumnType("nvarchar(max)"); + + b.Property("MadeObsoleteByUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("OldTag") + .HasColumnType("nvarchar(max)"); + + b.Property("OldTagPageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("RecordDate") + .HasColumnType("datetime2"); + + b.Property("RhymeLetters") + .HasColumnType("nvarchar(max)"); + + b.Property("Rhythm") + .HasColumnType("nvarchar(max)"); + + b.Property("SourceName") + .HasColumnType("nvarchar(max)"); + + b.Property("SourceUrlSlug") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("UrlSlug") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("GanjoorPageId"); + + b.HasIndex("MadeObsoleteByUserId"); + + b.ToTable("GanjoorPageSnapshots"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonAffiliation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AffiliationType") + .HasColumnType("int"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("Person1Id") + .HasColumnType("int"); + + b.Property("Person2Id") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Person1Id"); + + b.HasIndex("Person2Id"); + + b.ToTable("GanjoorPersonAffiliations"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonEditSuggestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("PersonId") + .HasColumnType("int"); + + b.Property("Result") + .HasColumnType("int"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewNote") + .HasColumnType("nvarchar(max)"); + + b.Property("Reviewed") + .HasColumnType("bit"); + + b.Property("ReviewerUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("SuggestedBirthLocationId") + .HasColumnType("int"); + + b.Property("SuggestedBirthYearInLHijri") + .HasColumnType("int"); + + b.Property("SuggestedDeathLocationId") + .HasColumnType("int"); + + b.Property("SuggestedDeathYearInLHijri") + .HasColumnType("int"); + + b.Property("SuggestedDescription") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestedFamilyTreeCaption") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestedName") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestedValidBirthDate") + .HasColumnType("bit"); + + b.Property("SuggestedValidDeathDate") + .HasColumnType("bit"); + + b.Property("SuggestedWikiUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestionNote") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("PersonId"); + + b.HasIndex("ReviewerUserId"); + + b.HasIndex("SuggestedBirthLocationId"); + + b.HasIndex("SuggestedDeathLocationId"); + + b.HasIndex("UserId"); + + b.ToTable("GanjoorPersonEditSuggestions"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonRelation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DegreeHint") + .HasColumnType("int"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("Person1Id") + .HasColumnType("int"); + + b.Property("Person2Id") + .HasColumnType("int"); + + b.Property("RelationType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("Person1Id"); + + b.HasIndex("Person2Id"); + + b.ToTable("GanjoorPersonRelations"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoem", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("CatId") + .HasColumnType("int"); + + b.Property("ClaimedByMultiplePoets") + .HasColumnType("bit"); + + b.Property("FullTitle") + .HasMaxLength(1500) + .HasColumnType("nvarchar(1500)"); + + b.Property("FullUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("GanjoorMetreId") + .HasColumnType("int"); + + b.Property("HtmlText") + .HasColumnType("nvarchar(max)"); + + b.Property("Language") + .HasMaxLength(8) + .HasColumnType("nvarchar(8)"); + + b.Property("MixedModeOrder") + .HasColumnType("int"); + + b.Property("OldTag") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("OldTagPageUrl") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.Property("PlainText") + .HasColumnType("nvarchar(max)"); + + b.Property("PoemSummary") + .HasMaxLength(3000) + .HasColumnType("nvarchar(3000)"); + + b.Property("Published") + .HasColumnType("bit"); + + b.Property("RhymeLetters") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("SourceName") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("SourceUrlSlug") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("Title") + .HasMaxLength(1500) + .HasColumnType("nvarchar(1500)"); + + b.Property("UrlSlug") + .HasMaxLength(32) + .HasColumnType("nvarchar(32)"); + + b.HasKey("Id"); + + b.HasIndex("CatId"); + + b.HasIndex("FullUrl"); + + b.HasIndex("GanjoorMetreId"); + + b.HasIndex("Id"); + + b.ToTable("GanjoorPoems"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AffectedThePoem") + .HasColumnType("bit"); + + b.Property("ApplicationOrder") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("HideMyName") + .HasColumnType("bit"); + + b.Property("Language") + .HasColumnType("nvarchar(max)"); + + b.Property("LanguageReviewResult") + .HasColumnType("int"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalLanguage") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalPoemFormat") + .HasColumnType("int"); + + b.Property("OriginalPoemSummary") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalRhymeLetters") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalRhythm") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalRhythm2") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalRhythm3") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalRhythm4") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("PoemFormat") + .HasColumnType("int"); + + b.Property("PoemFormatReviewResult") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("PoemSummary") + .HasColumnType("nvarchar(max)"); + + b.Property("Result") + .HasColumnType("int"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewNote") + .HasColumnType("nvarchar(max)"); + + b.Property("Reviewed") + .HasColumnType("bit"); + + b.Property("ReviewerUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RhymeLetters") + .HasColumnType("nvarchar(max)"); + + b.Property("RhymeLettersReviewResult") + .HasColumnType("int"); + + b.Property("Rhythm") + .HasColumnType("nvarchar(max)"); + + b.Property("Rhythm2") + .HasColumnType("nvarchar(max)"); + + b.Property("Rhythm2Result") + .HasColumnType("int"); + + b.Property("Rhythm3") + .HasColumnType("nvarchar(max)"); + + b.Property("Rhythm3Result") + .HasColumnType("int"); + + b.Property("Rhythm4") + .HasColumnType("nvarchar(max)"); + + b.Property("Rhythm4Result") + .HasColumnType("int"); + + b.Property("RhythmResult") + .HasColumnType("int"); + + b.Property("SummaryReviewResult") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("PoemId"); + + b.HasIndex("ReviewerUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GanjoorPoemCorrections"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemGeoDateTagCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("ExistingTagId") + .HasColumnType("int"); + + b.Property("GanjoorPoemCorrectionId") + .HasColumnType("int"); + + b.Property("IgnoreInCategory") + .HasColumnType("bit"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("LunarDay") + .HasColumnType("int"); + + b.Property("LunarMonth") + .HasColumnType("int"); + + b.Property("LunarYear") + .HasColumnType("int"); + + b.Property("MarkForDelete") + .HasColumnType("bit"); + + b.Property("PersonId") + .HasColumnType("int"); + + b.Property("Result") + .HasColumnType("int"); + + b.Property("ReviewNote") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestedLatitude") + .HasColumnType("float"); + + b.Property("SuggestedLocationName") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestedLongitude") + .HasColumnType("float"); + + b.Property("SuggestedPersonGraphJson") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestionNote") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("GanjoorPoemCorrectionId"); + + b.HasIndex("LocationId"); + + b.HasIndex("PersonId"); + + b.ToTable("GanjoorPoemGeoDateTagCorrection"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemProbableMetre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Metre") + .HasColumnType("nvarchar(max)"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("SectionId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PoemId"); + + b.ToTable("GanjoorPoemProbableMetres"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CachedFirstCoupletIndex") + .HasColumnType("int"); + + b.Property("CoupletsCount") + .HasColumnType("int"); + + b.Property("GanjoorMetreId") + .HasColumnType("int"); + + b.Property("GanjoorMetreRefSectionIndex") + .HasColumnType("int"); + + b.Property("HtmlText") + .HasColumnType("nvarchar(max)"); + + b.Property("Index") + .HasColumnType("int"); + + b.Property("Language") + .HasColumnType("nvarchar(max)"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("PlainText") + .HasColumnType("nvarchar(max)"); + + b.Property("PoemFormat") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("RhymeLetters") + .HasColumnType("nvarchar(450)"); + + b.Property("SectionType") + .HasColumnType("int"); + + b.Property("VerseType") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PoetId"); + + b.HasIndex("RhymeLetters"); + + b.HasIndex("GanjoorMetreId", "RhymeLetters"); + + b.HasIndex("PoemId", "Index"); + + b.HasIndex("GanjoorMetreId", "RhymeLetters", "Id"); + + b.HasIndex("GanjoorMetreId", "RhymeLetters", "SectionType"); + + b.ToTable("GanjoorPoemSections"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemSectionCorrection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AffectedThePoem") + .HasColumnType("bit"); + + b.Property("ApplicationOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse10VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse10VOrderResult") + .HasColumnType("int"); + + b.Property("BreakFromVerse1VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse1VOrderResult") + .HasColumnType("int"); + + b.Property("BreakFromVerse2VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse2VOrderResult") + .HasColumnType("int"); + + b.Property("BreakFromVerse3VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse3VOrderResult") + .HasColumnType("int"); + + b.Property("BreakFromVerse4VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse4VOrderResult") + .HasColumnType("int"); + + b.Property("BreakFromVerse5VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse5VOrderResult") + .HasColumnType("int"); + + b.Property("BreakFromVerse6VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse6VOrderResult") + .HasColumnType("int"); + + b.Property("BreakFromVerse7VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse7VOrderResult") + .HasColumnType("int"); + + b.Property("BreakFromVerse8VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse8VOrderResult") + .HasColumnType("int"); + + b.Property("BreakFromVerse9VOrder") + .HasColumnType("int"); + + b.Property("BreakFromVerse9VOrderResult") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("HideMyName") + .HasColumnType("bit"); + + b.Property("Language") + .HasColumnType("nvarchar(max)"); + + b.Property("LanguageReviewResult") + .HasColumnType("int"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalLanguage") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalPoemFormat") + .HasColumnType("int"); + + b.Property("OriginalRhymeLetters") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalRhythm") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalRhythm2") + .HasColumnType("nvarchar(max)"); + + b.Property("PoemFormat") + .HasColumnType("int"); + + b.Property("PoemFormatReviewResult") + .HasColumnType("int"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewNote") + .HasColumnType("nvarchar(max)"); + + b.Property("Reviewed") + .HasColumnType("bit"); + + b.Property("ReviewerUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RhymeLetters") + .HasColumnType("nvarchar(max)"); + + b.Property("RhymeLettersReviewResult") + .HasColumnType("int"); + + b.Property("Rhythm") + .HasColumnType("nvarchar(max)"); + + b.Property("Rhythm2") + .HasColumnType("nvarchar(max)"); + + b.Property("RhythmResult") + .HasColumnType("int"); + + b.Property("RhythmResult2") + .HasColumnType("int"); + + b.Property("SectionId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ReviewerUserId"); + + b.HasIndex("SectionId"); + + b.HasIndex("UserId"); + + b.ToTable("GanjoorPoemSectionCorrections"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoet", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("BirthLocationId") + .HasColumnType("int"); + + b.Property("BirthYearInLHijri") + .HasColumnType("int"); + + b.Property("DeathLocationId") + .HasColumnType("int"); + + b.Property("DeathYearInLHijri") + .HasColumnType("int"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("Nickname") + .HasColumnType("nvarchar(max)"); + + b.Property("PinOrder") + .HasColumnType("int"); + + b.Property("Published") + .HasColumnType("bit"); + + b.Property("RImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("ValidBirthDate") + .HasColumnType("bit"); + + b.Property("ValidDeathDate") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("BirthLocationId"); + + b.HasIndex("DeathLocationId"); + + b.HasIndex("RImageId"); + + b.HasIndex("Published", "Id"); + + SqlServerIndexBuilderExtensions.IncludeProperties(b.HasIndex("Published", "Id"), new[] { "Name", "Nickname", "RImageId" }); + + b.ToTable("GanjoorPoets"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoetSuggestedPicture", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ChosenOne") + .HasColumnType("bit"); + + b.Property("PicOrder") + .HasColumnType("int"); + + b.Property("PictureId") + .HasColumnType("uniqueidentifier"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("PublicationDate") + .HasColumnType("datetime2"); + + b.Property("Published") + .HasColumnType("bit"); + + b.Property("SuggestedById") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("PictureId"); + + b.HasIndex("PoetId"); + + b.HasIndex("SuggestedById"); + + b.ToTable("GanjoorPoetSuggestedPictures"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoetSuggestedSpecLine", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Contents") + .HasColumnType("nvarchar(max)"); + + b.Property("LineOrder") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("PublicationDate") + .HasColumnType("datetime2"); + + b.Property("Published") + .HasColumnType("bit"); + + b.Property("SuggestedById") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("PoetId"); + + b.HasIndex("SuggestedById"); + + b.ToTable("GanjoorPoetSuggestedSpecLines"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorQuotedPoem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CachedRelatedPoemFullTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("CachedRelatedPoemFullUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("CachedRelatedPoemPoetDeathYearInLHijri") + .HasColumnType("int"); + + b.Property("CachedRelatedPoemPoetImage") + .HasColumnType("nvarchar(max)"); + + b.Property("CachedRelatedPoemPoetName") + .HasColumnType("nvarchar(max)"); + + b.Property("CachedRelatedPoemPoetUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("ChosenForMainList") + .HasColumnType("bit"); + + b.Property("ClaimedByBothPoets") + .HasColumnType("bit"); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("CoupletVerse1") + .HasColumnType("nvarchar(max)"); + + b.Property("CoupletVerse1ShouldBeEmphasized") + .HasColumnType("bit"); + + b.Property("CoupletVerse2") + .HasColumnType("nvarchar(max)"); + + b.Property("CoupletVerse2ShouldBeEmphasized") + .HasColumnType("bit"); + + b.Property("IndirectQuotation") + .HasColumnType("bit"); + + b.Property("IsPriorToRelated") + .HasColumnType("bit"); + + b.Property("Note") + .HasColumnType("nvarchar(max)"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("Published") + .HasColumnType("bit"); + + b.Property("Rejected") + .HasColumnType("bit"); + + b.Property("RelatedCoupletIndex") + .HasColumnType("int"); + + b.Property("RelatedCoupletVerse1") + .HasColumnType("nvarchar(max)"); + + b.Property("RelatedCoupletVerse1ShouldBeEmphasized") + .HasColumnType("bit"); + + b.Property("RelatedCoupletVerse2") + .HasColumnType("nvarchar(max)"); + + b.Property("RelatedCoupletVerse2ShouldBeEmphasized") + .HasColumnType("bit"); + + b.Property("RelatedPoemId") + .HasColumnType("int"); + + b.Property("RelatedPoetId") + .HasColumnType("int"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewNote") + .HasColumnType("nvarchar(max)"); + + b.Property("ReviewerUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("SamePoemsQuotedCount") + .HasColumnType("int"); + + b.Property("SortOrder") + .HasColumnType("int"); + + b.Property("SuggestedById") + .HasColumnType("uniqueidentifier"); + + b.Property("SuggestionDate") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("PoemId"); + + b.HasIndex("ReviewerUserId"); + + b.HasIndex("SuggestedById"); + + b.ToTable("GanjoorQuotedPoems"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BirthLocationId") + .HasColumnType("int"); + + b.Property("BirthYearInLHijri") + .HasColumnType("int"); + + b.Property("DeathLocationId") + .HasColumnType("int"); + + b.Property("DeathYearInLHijri") + .HasColumnType("int"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("FamilyTreeCaption") + .HasColumnType("nvarchar(max)"); + + b.Property("MachineGenerated") + .HasColumnType("bit"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("ValidBirthDate") + .HasColumnType("bit"); + + b.Property("ValidDeathDate") + .HasColumnType("bit"); + + b.Property("WikiUrl") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("BirthLocationId"); + + b.HasIndex("DeathLocationId"); + + b.ToTable("GanjoorRelatedPersons"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorSiteBanner", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("AlternateText") + .HasColumnType("nvarchar(max)"); + + b.Property("RImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("TargetUrl") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("RImageId"); + + b.ToTable("GanjoorSiteBanners"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorTajikCat", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("PoetId") + .HasColumnType("int"); + + b.Property("TajikDescription") + .HasColumnType("nvarchar(max)"); + + b.Property("TajikTitle") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("PoetId"); + + b.ToTable("TajikCats"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorTajikPage", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("TajikHtmlText") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("TajikPages"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorTajikPoem", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("CatId") + .HasColumnType("int"); + + b.Property("FullTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("FullUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("TajikPlainText") + .HasColumnType("nvarchar(max)"); + + b.Property("TajikTitle") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CatId"); + + b.ToTable("TajikPoems"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorTajikPoet", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("BirthYearInLHijri") + .HasColumnType("int"); + + b.Property("TajikDescription") + .HasColumnType("nvarchar(max)"); + + b.Property("TajikNickname") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("TajikPoets"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorTajikVerse", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("TajikText") + .HasColumnType("nvarchar(max)"); + + b.Property("VOrder") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("TajikVerses"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorUserBookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("PrivateNote") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Verse2Id") + .HasColumnType("int"); + + b.Property("VerseId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PoemId"); + + b.HasIndex("UserId", "PoemId", "CoupletIndex"); + + b.ToTable("GanjoorUserBookmarks"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorUserPoemVisit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Counter") + .HasColumnType("int"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("PoemId"); + + b.HasIndex("UserId"); + + b.HasIndex("UserId", "PoemId"); + + b.ToTable("GanjoorUserPoemVisits"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorVerse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("CoupletSummary") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("LanguageId") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("SectionIndex1") + .HasColumnType("int"); + + b.Property("SectionIndex2") + .HasColumnType("int"); + + b.Property("SectionIndex3") + .HasColumnType("int"); + + b.Property("SectionIndex4") + .HasColumnType("int"); + + b.Property("Text") + .HasColumnType("nvarchar(max)"); + + b.Property("VOrder") + .HasColumnType("int"); + + b.Property("VersePosition") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("LanguageId"); + + b.HasIndex("PoemId"); + + b.HasIndex("PoemId", "CoupletIndex"); + + b.ToTable("GanjoorVerses"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorVerseNumber", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("IsPoemVerse") + .HasColumnType("bit"); + + b.Property("Number") + .HasColumnType("int"); + + b.Property("NumberingId") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("SameTypeNumber") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("PoemId", "CoupletIndex"); + + b.HasIndex("NumberingId", "PoemId", "CoupletIndex") + .IsUnique(); + + b.ToTable("GanjoorVerseNumbers"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorVerseVOrderText", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("CoupletSummary") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorPoemCorrectionId") + .HasColumnType("int"); + + b.Property("LanguageId") + .HasColumnType("int"); + + b.Property("LanguageReviewResult") + .HasColumnType("int"); + + b.Property("MarkForDelete") + .HasColumnType("bit"); + + b.Property("MarkForDeleteResult") + .HasColumnType("int"); + + b.Property("NewVerse") + .HasColumnType("bit"); + + b.Property("NewVerseResult") + .HasColumnType("int"); + + b.Property("OriginalCoupletSummary") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalLanguageId") + .HasColumnType("int"); + + b.Property("OriginalText") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalVersePosition") + .HasColumnType("int"); + + b.Property("Result") + .HasColumnType("int"); + + b.Property("ReviewNote") + .HasColumnType("nvarchar(max)"); + + b.Property("SummaryReviewResult") + .HasColumnType("int"); + + b.Property("Text") + .HasColumnType("nvarchar(max)"); + + b.Property("VORder") + .HasColumnType("int"); + + b.Property("VersePosition") + .HasColumnType("int"); + + b.Property("VersePositionResult") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("GanjoorPoemCorrectionId"); + + b.ToTable("GanjoorVerseVOrderText"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.PoemGeoDateTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("IgnoreInCategory") + .HasColumnType("bit"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("LunarDateTotalNumber") + .HasColumnType("int"); + + b.Property("LunarDay") + .HasColumnType("int"); + + b.Property("LunarMonth") + .HasColumnType("int"); + + b.Property("LunarYear") + .HasColumnType("int"); + + b.Property("MachineGenerated") + .HasColumnType("bit"); + + b.Property("PersonId") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("VerifiedDate") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("LocationId"); + + b.HasIndex("PersonId"); + + b.HasIndex("PoemId"); + + b.ToTable("PoemGeoDateTags"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.PoemMusicTrack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AlbumName") + .HasColumnType("nvarchar(max)"); + + b.Property("AlbumUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("ApprovalDate") + .HasColumnType("datetime2"); + + b.Property("Approved") + .HasColumnType("bit"); + + b.Property("ArtistName") + .HasColumnType("nvarchar(max)"); + + b.Property("ArtistUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("BrokenLink") + .HasColumnType("bit"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorTrackId") + .HasColumnType("int"); + + b.Property("GolhaTrackId") + .HasColumnType("int"); + + b.Property("PoemId") + .HasColumnType("int"); + + b.Property("Rejected") + .HasColumnType("bit"); + + b.Property("RejectionCause") + .HasColumnType("nvarchar(max)"); + + b.Property("SingerId") + .HasColumnType("int"); + + b.Property("SongOrder") + .HasColumnType("int"); + + b.Property("SuggestedById") + .HasColumnType("uniqueidentifier"); + + b.Property("TrackName") + .HasColumnType("nvarchar(max)"); + + b.Property("TrackType") + .HasColumnType("int"); + + b.Property("TrackUrl") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("GanjoorTrackId"); + + b.HasIndex("GolhaTrackId"); + + b.HasIndex("PoemId"); + + b.HasIndex("SingerId"); + + b.HasIndex("SuggestedById"); + + b.HasIndex("Approved", "Rejected"); + + b.ToTable("GanjoorPoemMusicTracks"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.SemanticSearch.SemanticSearchQueryLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClickedAtUtc") + .HasColumnType("datetime2"); + + b.Property("ClickedPoemId") + .HasColumnType("int"); + + b.Property("ClickedResultRank") + .HasColumnType("int"); + + b.Property("DateTimeUtc") + .HasColumnType("datetime2"); + + b.Property("DetectedCategoryName") + .HasColumnType("nvarchar(max)"); + + b.Property("DetectedPoetName") + .HasColumnType("nvarchar(max)"); + + b.Property("Query") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestedTopK") + .HasColumnType("int"); + + b.Property("ResultCount") + .HasColumnType("int"); + + b.Property("ScopeDetected") + .HasColumnType("bit"); + + b.Property("ScopeDetectionDisabled") + .HasColumnType("bit"); + + b.Property("TopResultScore") + .HasColumnType("real"); + + b.HasKey("Id"); + + b.ToTable("SemanticSearchQueryLogs"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.UpdatingRelSectsLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("MeterId") + .HasColumnType("int"); + + b.Property("RhymeLettes") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("UpdatingRelSectsLogs"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.Recitation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AudioArtist") + .HasColumnType("nvarchar(max)"); + + b.Property("AudioArtistUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("AudioOrder") + .HasColumnType("int"); + + b.Property("AudioSrc") + .HasColumnType("nvarchar(max)"); + + b.Property("AudioSrcUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("AudioSyncStatus") + .HasColumnType("int"); + + b.Property("AudioTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("FileLastUpdated") + .HasColumnType("datetime2"); + + b.Property("FileNameWithoutExtension") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorAudioId") + .HasColumnType("int"); + + b.Property("GanjoorPostId") + .HasColumnType("int"); + + b.Property("InSyncWithText") + .HasColumnType("bit"); + + b.Property("InitialScore") + .HasColumnType("int"); + + b.Property("LegacyAudioGuid") + .HasColumnType("uniqueidentifier"); + + b.Property("LocalMp3FilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("LocalXmlFilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("Mp3FileCheckSum") + .HasColumnType("nvarchar(max)"); + + b.Property("Mp3SizeInBytes") + .HasColumnType("int"); + + b.Property("OggSizeInBytes") + .HasColumnType("int"); + + b.Property("OwnerId") + .HasColumnType("uniqueidentifier"); + + b.Property("RecitationType") + .HasColumnType("int"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewMsg") + .HasColumnType("nvarchar(max)"); + + b.Property("ReviewStatus") + .HasColumnType("int"); + + b.Property("ReviewerId") + .HasColumnType("uniqueidentifier"); + + b.Property("SoundFilesFolder") + .HasColumnType("nvarchar(max)"); + + b.Property("UploadDate") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("GanjoorAudioId"); + + b.HasIndex("GanjoorPostId"); + + b.HasIndex("OwnerId"); + + b.HasIndex("ReviewerId"); + + b.HasIndex("ReviewStatus", "GanjoorPostId"); + + b.ToTable("Recitations"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.RecitationApprovedMistake", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("Mistake") + .HasColumnType("nvarchar(max)"); + + b.Property("NumberOfLinesAffected") + .HasColumnType("int"); + + b.Property("RecitationId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("RecitationId"); + + b.ToTable("RecitationApprovedMistakes"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.RecitationErrorReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoupletIndex") + .HasColumnType("int"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("NumberOfLinesAffected") + .HasColumnType("int"); + + b.Property("ReasonText") + .HasColumnType("nvarchar(max)"); + + b.Property("RecitationId") + .HasColumnType("int"); + + b.Property("ReporterId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RecitationId"); + + b.HasIndex("ReporterId"); + + b.ToTable("RecitationErrorReports"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.RecitationPublishingTracker", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("FinishDate") + .HasColumnType("datetime2"); + + b.Property("Finished") + .HasColumnType("bit"); + + b.Property("FirstDbUpdated") + .HasColumnType("bit"); + + b.Property("LastException") + .HasColumnType("nvarchar(max)"); + + b.Property("Mp3FileCopied") + .HasColumnType("bit"); + + b.Property("PoemNarrationId") + .HasColumnType("int"); + + b.Property("SecondDbUpdated") + .HasColumnType("bit"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("XmlFileCopied") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("PoemNarrationId"); + + b.ToTable("RecitationPublishingTrackers"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.RecitationUserUpVote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("RecitationId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("RecitationId", "UserId") + .IsUnique() + .HasFilter("[UserId] IS NOT NULL"); + + b.ToTable("RecitationUserUpVotes"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.UserRecitationProfile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ArtistName") + .HasColumnType("nvarchar(max)"); + + b.Property("ArtistUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("AudioSrc") + .HasColumnType("nvarchar(max)"); + + b.Property("AudioSrcUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("FileSuffixWithoutDash") + .HasColumnType("nvarchar(max)"); + + b.Property("IsDefault") + .HasColumnType("bit"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserRecitationProfiles"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorIntegration.GanjoorLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ArtifactId") + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayOnPage") + .HasColumnType("bit"); + + b.Property("GanjoorPostId") + .HasColumnType("int"); + + b.Property("GanjoorTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("IsTextOriginalSource") + .HasColumnType("bit"); + + b.Property("ItemId") + .HasColumnType("uniqueidentifier"); + + b.Property("LinkToOriginalSource") + .HasColumnType("bit"); + + b.Property("OriginalSourceUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewResult") + .HasColumnType("int"); + + b.Property("ReviewerId") + .HasColumnType("uniqueidentifier"); + + b.Property("SuggestedById") + .HasColumnType("uniqueidentifier"); + + b.Property("SuggestionDate") + .HasColumnType("datetime2"); + + b.Property("Synchronized") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("ArtifactId"); + + b.HasIndex("ItemId"); + + b.HasIndex("ReviewerId"); + + b.HasIndex("SuggestedById"); + + b.ToTable("GanjoorLinks"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorIntegration.GanjoorPaperSource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("BookFullTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("BookFullUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("BookType") + .HasColumnType("int"); + + b.Property("CoverThumbnailImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorCatFullTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorCatFullUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorCatId") + .HasColumnType("int"); + + b.Property("GanjoorPoetId") + .HasColumnType("int"); + + b.Property("HumanReviewed") + .HasColumnType("bit"); + + b.Property("IsTextOriginalSource") + .HasColumnType("bit"); + + b.Property("MatchPercent") + .HasColumnType("int"); + + b.Property("NaskbanBookId") + .HasColumnType("int"); + + b.Property("OrderIndicator") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("GanjoorPaperSources"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorIntegration.PDFGanjoorLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ExternalThumbnailImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorPostId") + .HasColumnType("int"); + + b.Property("GanjoorTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("IsTextOriginalSource") + .HasColumnType("bit"); + + b.Property("PDFBookId") + .HasColumnType("int"); + + b.Property("PDFPageTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("PageNumber") + .HasColumnType("int"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewResult") + .HasColumnType("int"); + + b.Property("ReviewerId") + .HasColumnType("uniqueidentifier"); + + b.Property("SuggestedById") + .HasColumnType("uniqueidentifier"); + + b.Property("SuggestedByMachine") + .HasColumnType("bit"); + + b.Property("SuggestionDate") + .HasColumnType("datetime2"); + + b.Property("Synchronized") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("ReviewerId"); + + b.HasIndex("SuggestedById"); + + b.ToTable("PDFGanjoorLinks"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorIntegration.PinterestLink", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AltText") + .HasColumnType("nvarchar(max)"); + + b.Property("ArtifactId") + .HasColumnType("uniqueidentifier"); + + b.Property("GanjoorPostId") + .HasColumnType("int"); + + b.Property("GanjoorTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("GanjoorUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("HumanReviewed") + .HasColumnType("bit"); + + b.Property("IsTextOriginalSource") + .HasColumnType("bit"); + + b.Property("ItemId") + .HasColumnType("uniqueidentifier"); + + b.Property("LinkType") + .HasColumnType("int"); + + b.Property("MatchPercent") + .HasColumnType("int"); + + b.Property("NaskbanLinkId") + .HasColumnType("uniqueidentifier"); + + b.Property("PDFBookId") + .HasColumnType("int"); + + b.Property("PageNumber") + .HasColumnType("int"); + + b.Property("PinterestImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("PinterestUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewDesc") + .HasColumnType("nvarchar(max)"); + + b.Property("ReviewResult") + .HasColumnType("int"); + + b.Property("ReviewerId") + .HasColumnType("uniqueidentifier"); + + b.Property("SuggestedById") + .HasColumnType("uniqueidentifier"); + + b.Property("SuggestionDate") + .HasColumnType("datetime2"); + + b.Property("Synchronized") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.HasIndex("ArtifactId"); + + b.HasIndex("ItemId"); + + b.HasIndex("ReviewerId"); + + b.HasIndex("SuggestedById"); + + b.ToTable("PinterestLinks"); + }); + + modelBuilder.Entity("RMuseum.Models.ImportJob.ImportJob", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ArtifactId") + .HasColumnType("uniqueidentifier"); + + b.Property("EndTime") + .HasColumnType("datetime2"); + + b.Property("Exception") + .HasColumnType("nvarchar(max)"); + + b.Property("FriendlyUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("JobType") + .HasColumnType("int"); + + b.Property("ProgressPercent") + .HasColumnType("decimal(18,2)"); + + b.Property("QueueTime") + .HasColumnType("datetime2"); + + b.Property("ResourceNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("SrcContent") + .HasColumnType("nvarchar(max)"); + + b.Property("SrcUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ArtifactId"); + + b.ToTable("ImportJobs"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GanjoorAlbum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("SingerId") + .HasColumnType("int"); + + b.Property("Url") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("SingerId"); + + b.ToTable("GanjoorAlbum"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GanjoorSinger", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("RImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("Url") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.HasIndex("RImageId"); + + b.ToTable("GanjoorSingers"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GanjoorTrack", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AlbumId") + .HasColumnType("int"); + + b.Property("BlockReason") + .HasColumnType("nvarchar(max)"); + + b.Property("Blocked") + .HasColumnType("bit"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Url") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AlbumId"); + + b.HasIndex("Name"); + + b.ToTable("GanjoorMusicCatalogueTracks"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GolhaCollection", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("GolhaCollections"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GolhaProgram", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("GolhaCollectionId") + .HasColumnType("int"); + + b.Property("Mp3") + .HasColumnType("nvarchar(max)"); + + b.Property("ProgramOrder") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("GolhaCollectionId"); + + b.ToTable("GolhaPrograms"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GolhaTrack", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("BlockReason") + .HasColumnType("nvarchar(max)"); + + b.Property("Blocked") + .HasColumnType("bit"); + + b.Property("GolhaProgramId") + .HasColumnType("int"); + + b.Property("SingerId") + .HasColumnType("int"); + + b.Property("Timing") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("TrackNo") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("GolhaProgramId"); + + b.HasIndex("SingerId"); + + b.ToTable("GolhaTracks"); + }); + + modelBuilder.Entity("RMuseum.Models.Note.RUserNote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("HtmlContent") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("Modified") + .HasColumnType("bit"); + + b.Property("NoteType") + .HasColumnType("int"); + + b.Property("RAppUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RArtifactItemRecordId") + .HasColumnType("uniqueidentifier"); + + b.Property("RArtifactMasterRecordId") + .HasColumnType("uniqueidentifier"); + + b.Property("ReferenceNoteId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("RAppUserId"); + + b.HasIndex("RArtifactItemRecordId"); + + b.HasIndex("RArtifactMasterRecordId"); + + b.HasIndex("ReferenceNoteId"); + + b.ToTable("UserNotes"); + }); + + modelBuilder.Entity("RMuseum.Models.Note.RUserNoteAbuseReport", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("NoteId") + .HasColumnType("uniqueidentifier"); + + b.Property("ReasonText") + .HasColumnType("nvarchar(max)"); + + b.Property("ReporterId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("NoteId"); + + b.HasIndex("ReporterId"); + + b.ToTable("ReportedUserNotes"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.Author", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Bio") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtenalImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("ImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("NameInOriginalLanguage") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("ImageId"); + + b.ToTable("Authors"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.AuthorRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorId") + .HasColumnType("int"); + + b.Property("BookId") + .HasColumnType("int"); + + b.Property("PDFBookId") + .HasColumnType("int"); + + b.Property("Role") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorId"); + + b.HasIndex("BookId"); + + b.HasIndex("PDFBookId"); + + b.ToTable("AuthorRole"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.Book", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CoverImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtenalCoverImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("CoverImageId"); + + b.ToTable("Books"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.MultiVolumePDFCollection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("BookId") + .HasColumnType("int"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("VolumeCount") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("BookId"); + + b.ToTable("MultiVolumePDFCollections"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.OCRQueue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("PDFBookId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("OCRQueuedItems"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.PDFBook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AuthorsLine") + .HasColumnType("nvarchar(max)"); + + b.Property("BookId") + .HasColumnType("int"); + + b.Property("BookScriptType") + .HasColumnType("int"); + + b.Property("BookText") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimedPageCount") + .HasColumnType("int"); + + b.Property("CoverImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtenalCoverImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("ExternalPDFFileUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("FileMD5CheckSum") + .HasColumnType("nvarchar(max)"); + + b.Property("ISBN") + .HasColumnType("nvarchar(max)"); + + b.Property("IsTranslation") + .HasColumnType("bit"); + + b.Property("Language") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("MultiVolumePDFCollectionId") + .HasColumnType("int"); + + b.Property("OCRTime") + .HasColumnType("datetime2"); + + b.Property("OCRed") + .HasColumnType("bit"); + + b.Property("OriginalFileName") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalFileUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalSourceName") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalSourceUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("PDFFileId") + .HasColumnType("uniqueidentifier"); + + b.Property("PDFSourceId") + .HasColumnType("int"); + + b.Property("PageCount") + .HasColumnType("int"); + + b.Property("PublisherLine") + .HasColumnType("nvarchar(max)"); + + b.Property("PublishingDate") + .HasColumnType("nvarchar(max)"); + + b.Property("PublishingLocation") + .HasColumnType("nvarchar(max)"); + + b.Property("PublishingNumber") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("StorageFolderName") + .HasColumnType("nvarchar(max)"); + + b.Property("SubTitle") + .HasColumnType("nvarchar(max)"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("TitleInOriginalLanguage") + .HasColumnType("nvarchar(max)"); + + b.Property("TranslatorsLine") + .HasColumnType("nvarchar(max)"); + + b.Property("VolumeOrder") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("BookId"); + + b.HasIndex("CoverImageId"); + + b.HasIndex("MultiVolumePDFCollectionId"); + + b.HasIndex("PDFFileId"); + + b.HasIndex("PDFSourceId"); + + b.ToTable("PDFBooks"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.PDFPage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("ExtenalThumbnailImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("FullResolutionImageHeight") + .HasColumnType("int"); + + b.Property("FullResolutionImageWidth") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("OCRTime") + .HasColumnType("datetime2"); + + b.Property("OCRed") + .HasColumnType("bit"); + + b.Property("PDFBookId") + .HasColumnType("int"); + + b.Property("PageNumber") + .HasColumnType("int"); + + b.Property("PageText") + .HasColumnType("nvarchar(max)"); + + b.Property("ThumbnailImageId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("PDFBookId"); + + b.HasIndex("ThumbnailImageId"); + + b.ToTable("PDFPages"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.PDFSource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("Url") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("PDFSources"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.QueuedPDFBook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AuthorsLine") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DownloadOrder") + .HasColumnType("int"); + + b.Property("IsTranslation") + .HasColumnType("bit"); + + b.Property("Language") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalFileUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalSourceName") + .HasColumnType("nvarchar(max)"); + + b.Property("OriginalSourceUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("ProcessResult") + .HasColumnType("nvarchar(max)"); + + b.Property("Processed") + .HasColumnType("bit"); + + b.Property("ResultId") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("TranslatorsLine") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("QueuedPDFBooks"); + }); + + modelBuilder.Entity("RMuseum.Models.UploadSession.UploadSession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ProcessEndTime") + .HasColumnType("datetime2"); + + b.Property("ProcessProgress") + .HasColumnType("int"); + + b.Property("ProcessStartTime") + .HasColumnType("datetime2"); + + b.Property("SessionType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("UploadEndTime") + .HasColumnType("datetime2"); + + b.Property("UploadStartTime") + .HasColumnType("datetime2"); + + b.Property("UseId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UploadSessions"); + }); + + modelBuilder.Entity("RMuseum.Models.UploadSession.UploadSessionFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContentDisposition") + .HasColumnType("nvarchar(max)"); + + b.Property("ContentType") + .HasColumnType("nvarchar(max)"); + + b.Property("FileName") + .HasColumnType("nvarchar(max)"); + + b.Property("FilePath") + .HasColumnType("nvarchar(max)"); + + b.Property("Length") + .HasColumnType("bigint"); + + b.Property("MP3FileCheckSum") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("ProcessResult") + .HasColumnType("bit"); + + b.Property("ProcessResultMsg") + .HasColumnType("nvarchar(max)"); + + b.Property("UploadSessionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UploadSessionId"); + + b.ToTable("UploadedFiles"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Audit.Db.REvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EventType") + .HasColumnType("nvarchar(max)"); + + b.Property("IpAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("JsonData") + .HasColumnType("nvarchar(max)"); + + b.Property("RequestUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("ResponseStatusCode") + .HasColumnType("int"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("AuditLogs"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.BannedEmail", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("NormalizedEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("BannedEmails"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RAppRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RAppUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("Bio") + .HasColumnType("nvarchar(max)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("FirstName") + .HasColumnType("nvarchar(max)"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("LockoutMessage") + .HasColumnType("nvarchar(max)"); + + b.Property("NickName") + .HasColumnType("nvarchar(max)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("RImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("ScreenName") + .HasColumnType("nvarchar(max)"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SurName") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Website") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.HasIndex("RImageId"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RCaptchaImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("RImageId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("RImageId"); + + b.ToTable("CaptchaImages"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RPermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("OperationShortName") + .HasColumnType("nvarchar(max)"); + + b.Property("RAppRoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("SecurableItemShortName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("RAppRoleId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RTemporaryUserSession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientAppName") + .HasColumnType("nvarchar(max)"); + + b.Property("ClientIPAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("Language") + .HasColumnType("nvarchar(max)"); + + b.Property("LastRenewal") + .HasColumnType("datetime2"); + + b.Property("LoginTime") + .HasColumnType("datetime2"); + + b.Property("RAppUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Token") + .HasColumnType("nvarchar(max)"); + + b.Property("ValidUntil") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("RAppUserId"); + + b.ToTable("Sessions"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RUserBehaviourLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserBehaviourLogs"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RVerifyQueueItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ClientAppName") + .HasColumnType("nvarchar(max)"); + + b.Property("ClientIPAddress") + .HasColumnType("nvarchar(max)"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasColumnType("nvarchar(max)"); + + b.Property("Language") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("QueueType") + .HasColumnType("int"); + + b.Property("Secret") + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("Secret") + .IsUnique() + .HasFilter("[Secret] IS NOT NULL"); + + b.ToTable("VerifyQueueItems"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.UserOldContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ChangeDate") + .HasColumnType("datetime2"); + + b.Property("IsEmail") + .HasColumnType("bit"); + + b.Property("NormalizedValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserOldContacts"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.ChangeTracking.RChangeLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("EntityId") + .HasColumnType("int"); + + b.Property("EntityJson") + .HasColumnType("nvarchar(max)"); + + b.Property("EntityName") + .HasMaxLength(16) + .HasColumnType("nvarchar(16)"); + + b.Property("EntityUId") + .HasColumnType("uniqueidentifier"); + + b.Property("Operation") + .HasMaxLength(24) + .HasColumnType("nvarchar(24)"); + + b.Property("RAppUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("WorkspaceId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RAppUserId"); + + b.HasIndex("WorkspaceId"); + + b.ToTable("RChangeLogs"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWSPermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("OperationShortName") + .HasColumnType("nvarchar(max)"); + + b.Property("RWSRoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("SecurableItemShortName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("RWSRoleId"); + + b.ToTable("RWSPermissions"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWSRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("NormalizedName") + .HasColumnType("nvarchar(max)"); + + b.Property("WorkspaceId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("WorkspaceId"); + + b.ToTable("RWSRoles"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWSUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("InviteDate") + .HasColumnType("datetime2"); + + b.Property("MemberFrom") + .HasColumnType("datetime2"); + + b.Property("RAppUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("RWorkspaceId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("WorkspaceOrder") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("RAppUserId"); + + b.HasIndex("RWorkspaceId"); + + b.ToTable("RWSUsers"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWSUserRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("RoleId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("WorkspaceId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.HasIndex("UserId"); + + b.HasIndex("WorkspaceId"); + + b.ToTable("RWSUserRoles"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWorkspace", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("Active") + .HasColumnType("bit"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("RWorkspaces"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.WorkspaceUserInvitation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.Property("WorkspaceId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.HasIndex("WorkspaceId"); + + b.ToTable("WorkspaceUserInvitations"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Generic.Db.RGenericOption", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("RAppUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.Property("WorkspaceId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("WorkspaceId"); + + b.HasIndex("RAppUserId", "Name") + .IsUnique() + .HasFilter("[RAppUserId] IS NOT NULL AND [Name] IS NOT NULL"); + + b.ToTable("Options"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Generic.Db.RLongRunningJobStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("EndTime") + .HasColumnType("datetime2"); + + b.Property("Exception") + .HasColumnType("nvarchar(max)"); + + b.Property("LastUpdate") + .HasColumnType("datetime2"); + + b.Property("Name") + .HasColumnType("nvarchar(max)"); + + b.Property("Progress") + .HasColumnType("float"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.Property("Step") + .HasColumnType("nvarchar(max)"); + + b.Property("Succeeded") + .HasColumnType("bit"); + + b.HasKey("Id"); + + b.ToTable("LongRunningJobs"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Image.RImage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ContentType") + .HasColumnType("nvarchar(max)"); + + b.Property("DataTime") + .HasColumnType("datetime2"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(13) + .HasColumnType("nvarchar(13)"); + + b.Property("FileSizeInBytes") + .HasColumnType("bigint"); + + b.Property("FolderName") + .HasColumnType("nvarchar(max)"); + + b.Property("ImageHeight") + .HasColumnType("int"); + + b.Property("ImageWidth") + .HasColumnType("int"); + + b.Property("LastModified") + .HasColumnType("datetime2"); + + b.Property("OriginalFileName") + .HasColumnType("nvarchar(max)"); + + b.Property("StoredFileName") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("GeneralImages"); + + b.HasDiscriminator("Discriminator").HasValue("RImage"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Notification.RUserNotification", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DateTime") + .HasColumnType("datetime2"); + + b.Property("HtmlText") + .HasColumnType("nvarchar(max)"); + + b.Property("NotificationType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("Subject") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Notifications"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RPictureFile", b => + { + b.HasBaseType("RSecurityBackend.Models.Image.RImage"); + + b.Property("Description") + .HasColumnType("nvarchar(max)"); + + b.Property("DescriptionInEnglish") + .HasColumnType("nvarchar(max)"); + + b.Property("ExternalNormalSizeImageUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedMeta") + .HasColumnType("datetime2"); + + b.Property("NormalSizeImageHeight") + .HasColumnType("int"); + + b.Property("NormalSizeImageStoredFileName") + .HasColumnType("nvarchar(max)"); + + b.Property("NormalSizeImageWidth") + .HasColumnType("int"); + + b.Property("Order") + .HasColumnType("int"); + + b.Property("RArtifactItemRecordId") + .HasColumnType("uniqueidentifier"); + + b.Property("SrcUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("ThumbnailImageHeight") + .HasColumnType("int"); + + b.Property("ThumbnailImageStoredFileName") + .HasColumnType("nvarchar(max)"); + + b.Property("ThumbnailImageWidth") + .HasColumnType("int"); + + b.Property("Title") + .HasColumnType("nvarchar(max)"); + + b.Property("TitleInEnglish") + .HasColumnType("nvarchar(max)"); + + b.HasIndex("RArtifactItemRecordId"); + + b.HasDiscriminator().HasValue("RPictureFile"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RMuseum.Models.Accounting.DonationExpenditure", b => + { + b.HasOne("RMuseum.Models.Accounting.GanjoorDonation", "GanjoorDonation") + .WithMany() + .HasForeignKey("GanjoorDonationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RMuseum.Models.Accounting.GanjoorExpense", null) + .WithMany("DonationExpenditures") + .HasForeignKey("GanjoorExpenseId"); + + b.Navigation("GanjoorDonation"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RArtifactItemRecord", b => + { + b.HasOne("RMuseum.Models.Artifact.RArtifactMasterRecord", null) + .WithMany("Items") + .HasForeignKey("RArtifactMasterRecordId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RArtifactMasterRecord", b => + { + b.HasOne("RMuseum.Models.Artifact.RPictureFile", "CoverImage") + .WithMany() + .HasForeignKey("CoverImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CoverImage"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RTagValue", b => + { + b.HasOne("RMuseum.Models.PDFLibrary.Book", null) + .WithMany("Tags") + .HasForeignKey("BookId"); + + b.HasOne("RMuseum.Models.PDFLibrary.PDFBook", null) + .WithMany("Tags") + .HasForeignKey("PDFBookId"); + + b.HasOne("RMuseum.Models.PDFLibrary.PDFPage", null) + .WithMany("Tags") + .HasForeignKey("PDFPageId"); + + b.HasOne("RMuseum.Models.Artifact.RArtifactItemRecord", null) + .WithMany("Tags") + .HasForeignKey("RArtifactItemRecordId"); + + b.HasOne("RMuseum.Models.Artifact.RArtifactMasterRecord", null) + .WithMany("Tags") + .HasForeignKey("RArtifactMasterRecordId"); + + b.HasOne("RMuseum.Models.Artifact.RTag", "RTag") + .WithMany() + .HasForeignKey("RTagId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RTag"); + }); + + modelBuilder.Entity("RMuseum.Models.Bookmark.RUserBookmark", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "RAppUser") + .WithMany() + .HasForeignKey("RAppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RMuseum.Models.Artifact.RArtifactItemRecord", "RArtifactItemRecord") + .WithMany() + .HasForeignKey("RArtifactItemRecordId"); + + b.HasOne("RMuseum.Models.Artifact.RArtifactMasterRecord", "RArtifactMasterRecord") + .WithMany() + .HasForeignKey("RArtifactMasterRecordId"); + + b.Navigation("RAppUser"); + + b.Navigation("RArtifactItemRecord"); + + b.Navigation("RArtifactMasterRecord"); + }); + + modelBuilder.Entity("RMuseum.Models.FAQ.FAQItem", b => + { + b.HasOne("RMuseum.Models.FAQ.FAQCategory", "Category") + .WithMany() + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCachedRelatedPoem", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poem"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCachedRelatedSection", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poem"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCat", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorCat", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoet", "Poet") + .WithMany() + .HasForeignKey("PoetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Image.RImage", "RImage") + .WithMany() + .HasForeignKey("RImageId"); + + b.Navigation("Parent"); + + b.Navigation("Poet"); + + b.Navigation("RImage"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCatCorrection", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorCat", "Cat") + .WithMany() + .HasForeignKey("CatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "ReviewerUser") + .WithMany() + .HasForeignKey("ReviewerUserId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cat"); + + b.Navigation("ReviewerUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCenturyPoet", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorCentury", null) + .WithMany("Poets") + .HasForeignKey("GanjoorCenturyId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoet", "Poet") + .WithMany() + .HasForeignKey("PoetId"); + + b.Navigation("Poet"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorComment", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorComment", "InReplyTo") + .WithMany() + .HasForeignKey("InReplyToId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorVerse", "Verse1") + .WithMany() + .HasForeignKey("Verse1Id"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorVerse", "Verse2") + .WithMany() + .HasForeignKey("Verse2Id"); + + b.Navigation("InReplyTo"); + + b.Navigation("Poem"); + + b.Navigation("User"); + + b.Navigation("Verse1"); + + b.Navigation("Verse2"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCommentAbuseReport", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorComment", "GanjoorComment") + .WithMany() + .HasForeignKey("GanjoorCommentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "ReportedBy") + .WithMany() + .HasForeignKey("ReportedById"); + + b.Navigation("GanjoorComment"); + + b.Navigation("ReportedBy"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCommentReaction", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorComment", "GanjoorComment") + .WithMany() + .HasForeignKey("GanjoorCommentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GanjoorComment"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorDuplicate", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "DestPoem") + .WithMany() + .HasForeignKey("DestPoemId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "SrcPoem") + .WithMany() + .HasForeignKey("SrcPoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DestPoem"); + + b.Navigation("SrcPoem"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorNumbering", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorCat", "EndCat") + .WithMany() + .HasForeignKey("EndCatId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorCat", "StartCat") + .WithMany() + .HasForeignKey("StartCatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EndCat"); + + b.Navigation("StartCat"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPage", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorCat", "Cat") + .WithMany() + .HasForeignKey("CatId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPage", "Parent") + .WithMany() + .HasForeignKey("ParentId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoet", "Poet") + .WithMany() + .HasForeignKey("PoetId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoet", "SecondPoet") + .WithMany() + .HasForeignKey("SecondPoetId"); + + b.Navigation("Cat"); + + b.Navigation("Parent"); + + b.Navigation("Poem"); + + b.Navigation("Poet"); + + b.Navigation("SecondPoet"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPageSnapshot", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPage", "GanjoorPage") + .WithMany() + .HasForeignKey("GanjoorPageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "MadeObsoleteByUser") + .WithMany() + .HasForeignKey("MadeObsoleteByUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GanjoorPage"); + + b.Navigation("MadeObsoleteByUser"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonAffiliation", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", "Person1") + .WithMany() + .HasForeignKey("Person1Id") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", "Person2") + .WithMany() + .HasForeignKey("Person2Id") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Person1"); + + b.Navigation("Person2"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonEditSuggestion", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", "Person") + .WithMany() + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "ReviewerUser") + .WithMany() + .HasForeignKey("ReviewerUserId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "SuggestedBirthLocation") + .WithMany() + .HasForeignKey("SuggestedBirthLocationId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "SuggestedDeathLocation") + .WithMany() + .HasForeignKey("SuggestedDeathLocationId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Person"); + + b.Navigation("ReviewerUser"); + + b.Navigation("SuggestedBirthLocation"); + + b.Navigation("SuggestedDeathLocation"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonRelation", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", "Person1") + .WithMany() + .HasForeignKey("Person1Id") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", "Person2") + .WithMany() + .HasForeignKey("Person2Id") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Person1"); + + b.Navigation("Person2"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoem", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorCat", "Cat") + .WithMany() + .HasForeignKey("CatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorMetre", "GanjoorMetre") + .WithMany() + .HasForeignKey("GanjoorMetreId"); + + b.Navigation("Cat"); + + b.Navigation("GanjoorMetre"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemCorrection", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "ReviewerUser") + .WithMany() + .HasForeignKey("ReviewerUserId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poem"); + + b.Navigation("ReviewerUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemGeoDateTagCorrection", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoemCorrection", null) + .WithMany("GeoDateTags") + .HasForeignKey("GanjoorPoemCorrectionId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "Location") + .WithMany() + .HasForeignKey("LocationId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", "Person") + .WithMany() + .HasForeignKey("PersonId"); + + b.Navigation("Location"); + + b.Navigation("Person"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemProbableMetre", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poem"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemSection", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorMetre", "GanjoorMetre") + .WithMany() + .HasForeignKey("GanjoorMetreId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoet", "Poet") + .WithMany() + .HasForeignKey("PoetId"); + + b.Navigation("GanjoorMetre"); + + b.Navigation("Poem"); + + b.Navigation("Poet"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemSectionCorrection", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "ReviewerUser") + .WithMany() + .HasForeignKey("ReviewerUserId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoemSection", "Section") + .WithMany() + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReviewerUser"); + + b.Navigation("Section"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoet", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "BirthLocation") + .WithMany() + .HasForeignKey("BirthLocationId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "DeathLocation") + .WithMany() + .HasForeignKey("DeathLocationId"); + + b.HasOne("RSecurityBackend.Models.Image.RImage", "RImage") + .WithMany() + .HasForeignKey("RImageId"); + + b.Navigation("BirthLocation"); + + b.Navigation("DeathLocation"); + + b.Navigation("RImage"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoetSuggestedPicture", b => + { + b.HasOne("RMuseum.Models.Artifact.RPictureFile", "Picture") + .WithMany() + .HasForeignKey("PictureId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoet", "Poet") + .WithMany() + .HasForeignKey("PoetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "SuggestedBy") + .WithMany() + .HasForeignKey("SuggestedById"); + + b.Navigation("Picture"); + + b.Navigation("Poet"); + + b.Navigation("SuggestedBy"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoetSuggestedSpecLine", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoet", "Poet") + .WithMany() + .HasForeignKey("PoetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "SuggestedBy") + .WithMany() + .HasForeignKey("SuggestedById"); + + b.Navigation("Poet"); + + b.Navigation("SuggestedBy"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorQuotedPoem", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "ReviewerUser") + .WithMany() + .HasForeignKey("ReviewerUserId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "SuggestedBy") + .WithMany() + .HasForeignKey("SuggestedById"); + + b.Navigation("Poem"); + + b.Navigation("ReviewerUser"); + + b.Navigation("SuggestedBy"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "BirthLocation") + .WithMany() + .HasForeignKey("BirthLocationId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "DeathLocation") + .WithMany() + .HasForeignKey("DeathLocationId"); + + b.Navigation("BirthLocation"); + + b.Navigation("DeathLocation"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorSiteBanner", b => + { + b.HasOne("RSecurityBackend.Models.Image.RImage", "RImage") + .WithMany() + .HasForeignKey("RImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RImage"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorTajikCat", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorTajikPoet", "Poet") + .WithMany() + .HasForeignKey("PoetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poet"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorTajikPoem", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorTajikCat", "Cat") + .WithMany() + .HasForeignKey("CatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cat"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorUserBookmark", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poem"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorUserPoemVisit", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Poem"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorVerse", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorLanguage", "Language") + .WithMany() + .HasForeignKey("LanguageId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Language"); + + b.Navigation("Poem"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorVerseNumber", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorNumbering", "Numbering") + .WithMany() + .HasForeignKey("NumberingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Numbering"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorVerseVOrderText", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoemCorrection", null) + .WithMany("VerseOrderText") + .HasForeignKey("GanjoorPoemCorrectionId"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.PoemGeoDateTag", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "Location") + .WithMany() + .HasForeignKey("LocationId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", "Person") + .WithMany() + .HasForeignKey("PersonId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + + b.Navigation("Person"); + + b.Navigation("Poem"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.PoemMusicTrack", b => + { + b.HasOne("RMuseum.Models.MusicCatalogue.GanjoorTrack", "GanjoorTrack") + .WithMany() + .HasForeignKey("GanjoorTrackId"); + + b.HasOne("RMuseum.Models.MusicCatalogue.GolhaTrack", "GolhaTrack") + .WithMany() + .HasForeignKey("GolhaTrackId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorPoem", "Poem") + .WithMany() + .HasForeignKey("PoemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RMuseum.Models.MusicCatalogue.GanjoorSinger", "Singer") + .WithMany() + .HasForeignKey("SingerId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "SuggestedBy") + .WithMany() + .HasForeignKey("SuggestedById"); + + b.Navigation("GanjoorTrack"); + + b.Navigation("GolhaTrack"); + + b.Navigation("Poem"); + + b.Navigation("Singer"); + + b.Navigation("SuggestedBy"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.Recitation", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "Owner") + .WithMany() + .HasForeignKey("OwnerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "Reviewer") + .WithMany() + .HasForeignKey("ReviewerId"); + + b.Navigation("Owner"); + + b.Navigation("Reviewer"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.RecitationApprovedMistake", b => + { + b.HasOne("RMuseum.Models.GanjoorAudio.Recitation", "Recitation") + .WithMany() + .HasForeignKey("RecitationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Recitation"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.RecitationErrorReport", b => + { + b.HasOne("RMuseum.Models.GanjoorAudio.Recitation", "Recitation") + .WithMany() + .HasForeignKey("RecitationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "Reporter") + .WithMany() + .HasForeignKey("ReporterId"); + + b.Navigation("Recitation"); + + b.Navigation("Reporter"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.RecitationPublishingTracker", b => + { + b.HasOne("RMuseum.Models.GanjoorAudio.Recitation", "PoemNarration") + .WithMany() + .HasForeignKey("PoemNarrationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PoemNarration"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.RecitationUserUpVote", b => + { + b.HasOne("RMuseum.Models.GanjoorAudio.Recitation", "Recitation") + .WithMany() + .HasForeignKey("RecitationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Recitation"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorAudio.UserRecitationProfile", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorIntegration.GanjoorLink", b => + { + b.HasOne("RMuseum.Models.Artifact.RArtifactMasterRecord", "Artifact") + .WithMany() + .HasForeignKey("ArtifactId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RMuseum.Models.Artifact.RArtifactItemRecord", "Item") + .WithMany() + .HasForeignKey("ItemId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "Reviewer") + .WithMany() + .HasForeignKey("ReviewerId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "SuggestedBy") + .WithMany() + .HasForeignKey("SuggestedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Artifact"); + + b.Navigation("Item"); + + b.Navigation("Reviewer"); + + b.Navigation("SuggestedBy"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorIntegration.PDFGanjoorLink", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "Reviewer") + .WithMany() + .HasForeignKey("ReviewerId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "SuggestedBy") + .WithMany() + .HasForeignKey("SuggestedById") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reviewer"); + + b.Navigation("SuggestedBy"); + }); + + modelBuilder.Entity("RMuseum.Models.GanjoorIntegration.PinterestLink", b => + { + b.HasOne("RMuseum.Models.Artifact.RArtifactMasterRecord", "Artifact") + .WithMany() + .HasForeignKey("ArtifactId"); + + b.HasOne("RMuseum.Models.Artifact.RArtifactItemRecord", "Item") + .WithMany() + .HasForeignKey("ItemId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "Reviewer") + .WithMany() + .HasForeignKey("ReviewerId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "SuggestedBy") + .WithMany() + .HasForeignKey("SuggestedById"); + + b.Navigation("Artifact"); + + b.Navigation("Item"); + + b.Navigation("Reviewer"); + + b.Navigation("SuggestedBy"); + }); + + modelBuilder.Entity("RMuseum.Models.ImportJob.ImportJob", b => + { + b.HasOne("RMuseum.Models.Artifact.RArtifactMasterRecord", "Artifact") + .WithMany() + .HasForeignKey("ArtifactId"); + + b.Navigation("Artifact"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GanjoorAlbum", b => + { + b.HasOne("RMuseum.Models.MusicCatalogue.GanjoorSinger", "Singer") + .WithMany("Albums") + .HasForeignKey("SingerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Singer"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GanjoorSinger", b => + { + b.HasOne("RSecurityBackend.Models.Image.RImage", "RImage") + .WithMany() + .HasForeignKey("RImageId"); + + b.Navigation("RImage"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GanjoorTrack", b => + { + b.HasOne("RMuseum.Models.MusicCatalogue.GanjoorAlbum", "Album") + .WithMany("Tracks") + .HasForeignKey("AlbumId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Album"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GolhaProgram", b => + { + b.HasOne("RMuseum.Models.MusicCatalogue.GolhaCollection", "GolhaCollection") + .WithMany("Programs") + .HasForeignKey("GolhaCollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GolhaCollection"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GolhaTrack", b => + { + b.HasOne("RMuseum.Models.MusicCatalogue.GolhaProgram", "GolhaProgram") + .WithMany("Tracks") + .HasForeignKey("GolhaProgramId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RMuseum.Models.MusicCatalogue.GanjoorSinger", "Singer") + .WithMany() + .HasForeignKey("SingerId"); + + b.Navigation("GolhaProgram"); + + b.Navigation("Singer"); + }); + + modelBuilder.Entity("RMuseum.Models.Note.RUserNote", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "RAppUser") + .WithMany() + .HasForeignKey("RAppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RMuseum.Models.Artifact.RArtifactItemRecord", "RArtifactItemRecord") + .WithMany() + .HasForeignKey("RArtifactItemRecordId"); + + b.HasOne("RMuseum.Models.Artifact.RArtifactMasterRecord", "RArtifactMasterRecord") + .WithMany() + .HasForeignKey("RArtifactMasterRecordId"); + + b.HasOne("RMuseum.Models.Note.RUserNote", "ReferenceNote") + .WithMany() + .HasForeignKey("ReferenceNoteId"); + + b.Navigation("RAppUser"); + + b.Navigation("RArtifactItemRecord"); + + b.Navigation("RArtifactMasterRecord"); + + b.Navigation("ReferenceNote"); + }); + + modelBuilder.Entity("RMuseum.Models.Note.RUserNoteAbuseReport", b => + { + b.HasOne("RMuseum.Models.Note.RUserNote", "Note") + .WithMany() + .HasForeignKey("NoteId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "Reporter") + .WithMany() + .HasForeignKey("ReporterId"); + + b.Navigation("Note"); + + b.Navigation("Reporter"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.Author", b => + { + b.HasOne("RSecurityBackend.Models.Image.RImage", "Image") + .WithMany() + .HasForeignKey("ImageId"); + + b.Navigation("Image"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.AuthorRole", b => + { + b.HasOne("RMuseum.Models.PDFLibrary.Author", "Author") + .WithMany() + .HasForeignKey("AuthorId"); + + b.HasOne("RMuseum.Models.PDFLibrary.Book", null) + .WithMany("Authors") + .HasForeignKey("BookId"); + + b.HasOne("RMuseum.Models.PDFLibrary.PDFBook", null) + .WithMany("Contributers") + .HasForeignKey("PDFBookId"); + + b.Navigation("Author"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.Book", b => + { + b.HasOne("RSecurityBackend.Models.Image.RImage", "CoverImage") + .WithMany() + .HasForeignKey("CoverImageId"); + + b.Navigation("CoverImage"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.MultiVolumePDFCollection", b => + { + b.HasOne("RMuseum.Models.PDFLibrary.Book", "Book") + .WithMany() + .HasForeignKey("BookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Book"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.PDFBook", b => + { + b.HasOne("RMuseum.Models.PDFLibrary.Book", "Book") + .WithMany() + .HasForeignKey("BookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Image.RImage", "CoverImage") + .WithMany() + .HasForeignKey("CoverImageId"); + + b.HasOne("RMuseum.Models.PDFLibrary.MultiVolumePDFCollection", "MultiVolumePDFCollection") + .WithMany() + .HasForeignKey("MultiVolumePDFCollectionId"); + + b.HasOne("RSecurityBackend.Models.Image.RImage", "PDFFile") + .WithMany() + .HasForeignKey("PDFFileId"); + + b.HasOne("RMuseum.Models.PDFLibrary.PDFSource", "PDFSource") + .WithMany() + .HasForeignKey("PDFSourceId"); + + b.Navigation("Book"); + + b.Navigation("CoverImage"); + + b.Navigation("MultiVolumePDFCollection"); + + b.Navigation("PDFFile"); + + b.Navigation("PDFSource"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.PDFPage", b => + { + b.HasOne("RMuseum.Models.PDFLibrary.PDFBook", null) + .WithMany("Pages") + .HasForeignKey("PDFBookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Image.RImage", "ThumbnailImage") + .WithMany() + .HasForeignKey("ThumbnailImageId"); + + b.Navigation("ThumbnailImage"); + }); + + modelBuilder.Entity("RMuseum.Models.UploadSession.UploadSession", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.UploadSession.UploadSessionFile", b => + { + b.HasOne("RMuseum.Models.UploadSession.UploadSession", null) + .WithMany("UploadedFiles") + .HasForeignKey("UploadSessionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RAppUser", b => + { + b.HasOne("RSecurityBackend.Models.Image.RImage", "RImage") + .WithMany() + .HasForeignKey("RImageId"); + + b.Navigation("RImage"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RCaptchaImage", b => + { + b.HasOne("RSecurityBackend.Models.Image.RImage", "RImage") + .WithMany() + .HasForeignKey("RImageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RImage"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RPermission", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppRole", null) + .WithMany("Permissions") + .HasForeignKey("RAppRoleId"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RTemporaryUserSession", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "RAppUser") + .WithMany() + .HasForeignKey("RAppUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RAppUser"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RUserBehaviourLog", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.UserOldContact", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.ChangeTracking.RChangeLog", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "RAppUser") + .WithMany() + .HasForeignKey("RAppUserId"); + + b.HasOne("RSecurityBackend.Models.Cloud.RWorkspace", "Workspace") + .WithMany() + .HasForeignKey("WorkspaceId"); + + b.Navigation("RAppUser"); + + b.Navigation("Workspace"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWSPermission", b => + { + b.HasOne("RSecurityBackend.Models.Cloud.RWSRole", null) + .WithMany("Permissions") + .HasForeignKey("RWSRoleId"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWSRole", b => + { + b.HasOne("RSecurityBackend.Models.Cloud.RWorkspace", "Workspace") + .WithMany() + .HasForeignKey("WorkspaceId"); + + b.Navigation("Workspace"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWSUser", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "RAppUser") + .WithMany() + .HasForeignKey("RAppUserId"); + + b.HasOne("RSecurityBackend.Models.Cloud.RWorkspace", null) + .WithMany("Members") + .HasForeignKey("RWorkspaceId"); + + b.Navigation("RAppUser"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWSUserRole", b => + { + b.HasOne("RSecurityBackend.Models.Cloud.RWSRole", "Role") + .WithMany() + .HasForeignKey("RoleId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.HasOne("RSecurityBackend.Models.Cloud.RWorkspace", "Workspace") + .WithMany() + .HasForeignKey("WorkspaceId"); + + b.Navigation("Role"); + + b.Navigation("User"); + + b.Navigation("Workspace"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.WorkspaceUserInvitation", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Cloud.RWorkspace", "Workspace") + .WithMany() + .HasForeignKey("WorkspaceId"); + + b.Navigation("User"); + + b.Navigation("Workspace"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Generic.Db.RGenericOption", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "RAppUser") + .WithMany() + .HasForeignKey("RAppUserId"); + + b.HasOne("RSecurityBackend.Models.Cloud.RWorkspace", "Workspace") + .WithMany() + .HasForeignKey("WorkspaceId"); + + b.Navigation("RAppUser"); + + b.Navigation("Workspace"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Notification.RUserNotification", b => + { + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RPictureFile", b => + { + b.HasOne("RMuseum.Models.Artifact.RArtifactItemRecord", null) + .WithMany("Images") + .HasForeignKey("RArtifactItemRecordId"); + }); + + modelBuilder.Entity("RMuseum.Models.Accounting.GanjoorExpense", b => + { + b.Navigation("DonationExpenditures"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RArtifactItemRecord", b => + { + b.Navigation("Images"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("RMuseum.Models.Artifact.RArtifactMasterRecord", b => + { + b.Navigation("Items"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorCentury", b => + { + b.Navigation("Poets"); + }); + + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPoemCorrection", b => + { + b.Navigation("GeoDateTags"); + + b.Navigation("VerseOrderText"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GanjoorAlbum", b => + { + b.Navigation("Tracks"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GanjoorSinger", b => + { + b.Navigation("Albums"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GolhaCollection", b => + { + b.Navigation("Programs"); + }); + + modelBuilder.Entity("RMuseum.Models.MusicCatalogue.GolhaProgram", b => + { + b.Navigation("Tracks"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.Book", b => + { + b.Navigation("Authors"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.PDFBook", b => + { + b.Navigation("Contributers"); + + b.Navigation("Pages"); + + b.Navigation("Tags"); + }); + + modelBuilder.Entity("RMuseum.Models.PDFLibrary.PDFPage", b => + { + b.Navigation("Tags"); + }); + + modelBuilder.Entity("RMuseum.Models.UploadSession.UploadSession", b => + { + b.Navigation("UploadedFiles"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Auth.Db.RAppRole", b => + { + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWSRole", b => + { + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("RSecurityBackend.Models.Cloud.RWorkspace", b => + { + b.Navigation("Members"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/RMuseum/Migrations/20260929104427_AddGanjoorPersonEditSuggestion.cs b/RMuseum/Migrations/20260929104427_AddGanjoorPersonEditSuggestion.cs new file mode 100644 index 00000000..5859fe6a --- /dev/null +++ b/RMuseum/Migrations/20260929104427_AddGanjoorPersonEditSuggestion.cs @@ -0,0 +1,105 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace RMuseum.Migrations +{ + /// + public partial class AddGanjoorPersonEditSuggestion : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "GanjoorPersonEditSuggestions", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + PersonId = table.Column(type: "int", nullable: false), + Date = table.Column(type: "datetime2", nullable: false), + UserId = table.Column(type: "uniqueidentifier", nullable: false), + SuggestedName = table.Column(type: "nvarchar(max)", nullable: true), + SuggestedDescription = table.Column(type: "nvarchar(max)", nullable: true), + SuggestedWikiUrl = table.Column(type: "nvarchar(max)", nullable: true), + SuggestedBirthYearInLHijri = table.Column(type: "int", nullable: false), + SuggestedDeathYearInLHijri = table.Column(type: "int", nullable: false), + SuggestedValidBirthDate = table.Column(type: "bit", nullable: false), + SuggestedValidDeathDate = table.Column(type: "bit", nullable: false), + SuggestedBirthLocationId = table.Column(type: "int", nullable: true), + SuggestedDeathLocationId = table.Column(type: "int", nullable: true), + SuggestedFamilyTreeCaption = table.Column(type: "nvarchar(max)", nullable: true), + SuggestionNote = table.Column(type: "nvarchar(max)", nullable: true), + Reviewed = table.Column(type: "bit", nullable: false), + Result = table.Column(type: "int", nullable: false), + ReviewDate = table.Column(type: "datetime2", nullable: false), + ReviewNote = table.Column(type: "nvarchar(max)", nullable: true), + ReviewerUserId = table.Column(type: "uniqueidentifier", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_GanjoorPersonEditSuggestions", x => x.Id); + table.ForeignKey( + name: "FK_GanjoorPersonEditSuggestions_AspNetUsers_ReviewerUserId", + column: x => x.ReviewerUserId, + principalTable: "AspNetUsers", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_GanjoorPersonEditSuggestions_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_GanjoorPersonEditSuggestions_GanjoorGeoLocations_SuggestedBirthLocationId", + column: x => x.SuggestedBirthLocationId, + principalTable: "GanjoorGeoLocations", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_GanjoorPersonEditSuggestions_GanjoorGeoLocations_SuggestedDeathLocationId", + column: x => x.SuggestedDeathLocationId, + principalTable: "GanjoorGeoLocations", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_GanjoorPersonEditSuggestions_GanjoorRelatedPersons_PersonId", + column: x => x.PersonId, + principalTable: "GanjoorRelatedPersons", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_GanjoorPersonEditSuggestions_PersonId", + table: "GanjoorPersonEditSuggestions", + column: "PersonId"); + + migrationBuilder.CreateIndex( + name: "IX_GanjoorPersonEditSuggestions_ReviewerUserId", + table: "GanjoorPersonEditSuggestions", + column: "ReviewerUserId"); + + migrationBuilder.CreateIndex( + name: "IX_GanjoorPersonEditSuggestions_SuggestedBirthLocationId", + table: "GanjoorPersonEditSuggestions", + column: "SuggestedBirthLocationId"); + + migrationBuilder.CreateIndex( + name: "IX_GanjoorPersonEditSuggestions_SuggestedDeathLocationId", + table: "GanjoorPersonEditSuggestions", + column: "SuggestedDeathLocationId"); + + migrationBuilder.CreateIndex( + name: "IX_GanjoorPersonEditSuggestions_UserId", + table: "GanjoorPersonEditSuggestions", + column: "UserId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "GanjoorPersonEditSuggestions"); + } + } +} diff --git a/RMuseum/Migrations/RMuseumDbContextModelSnapshot.cs b/RMuseum/Migrations/RMuseumDbContextModelSnapshot.cs index dbc68d62..9a150515 100644 --- a/RMuseum/Migrations/RMuseumDbContextModelSnapshot.cs +++ b/RMuseum/Migrations/RMuseumDbContextModelSnapshot.cs @@ -1428,6 +1428,86 @@ namespace RMuseum.Migrations b.ToTable("GanjoorPersonAffiliations"); }); + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonEditSuggestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("PersonId") + .HasColumnType("int"); + + b.Property("Result") + .HasColumnType("int"); + + b.Property("ReviewDate") + .HasColumnType("datetime2"); + + b.Property("ReviewNote") + .HasColumnType("nvarchar(max)"); + + b.Property("Reviewed") + .HasColumnType("bit"); + + b.Property("ReviewerUserId") + .HasColumnType("uniqueidentifier"); + + b.Property("SuggestedBirthLocationId") + .HasColumnType("int"); + + b.Property("SuggestedBirthYearInLHijri") + .HasColumnType("int"); + + b.Property("SuggestedDeathLocationId") + .HasColumnType("int"); + + b.Property("SuggestedDeathYearInLHijri") + .HasColumnType("int"); + + b.Property("SuggestedDescription") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestedFamilyTreeCaption") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestedName") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestedValidBirthDate") + .HasColumnType("bit"); + + b.Property("SuggestedValidDeathDate") + .HasColumnType("bit"); + + b.Property("SuggestedWikiUrl") + .HasColumnType("nvarchar(max)"); + + b.Property("SuggestionNote") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("PersonId"); + + b.HasIndex("ReviewerUserId"); + + b.HasIndex("SuggestedBirthLocationId"); + + b.HasIndex("SuggestedDeathLocationId"); + + b.HasIndex("UserId"); + + b.ToTable("GanjoorPersonEditSuggestions"); + }); + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonRelation", b => { b.Property("Id") @@ -5305,6 +5385,43 @@ namespace RMuseum.Migrations b.Navigation("Person2"); }); + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonEditSuggestion", b => + { + b.HasOne("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", "Person") + .WithMany() + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "ReviewerUser") + .WithMany() + .HasForeignKey("ReviewerUserId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "SuggestedBirthLocation") + .WithMany() + .HasForeignKey("SuggestedBirthLocationId"); + + b.HasOne("RMuseum.Models.Ganjoor.GanjoorGeoLocation", "SuggestedDeathLocation") + .WithMany() + .HasForeignKey("SuggestedDeathLocationId"); + + b.HasOne("RSecurityBackend.Models.Auth.Db.RAppUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Person"); + + b.Navigation("ReviewerUser"); + + b.Navigation("SuggestedBirthLocation"); + + b.Navigation("SuggestedDeathLocation"); + + b.Navigation("User"); + }); + modelBuilder.Entity("RMuseum.Models.Ganjoor.GanjoorPersonRelation", b => { b.HasOne("RMuseum.Models.Ganjoor.GanjoorRelatedPerson", "Person1") diff --git a/RMuseum/Models/Ganjoor/ViewModels/GanjoorFamilyTreeViewModel.cs b/RMuseum/Models/Ganjoor/ViewModels/GanjoorFamilyTreeViewModel.cs new file mode 100644 index 00000000..8d0e379e --- /dev/null +++ b/RMuseum/Models/Ganjoor/ViewModels/GanjoorFamilyTreeViewModel.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; + +namespace RMuseum.Models.Ganjoor.ViewModels +{ + /// + /// the whole connected kinship component reachable from one person, for the interactive chart at + /// /FamilyTree/{id} (client draws the layout; this just hands over every person and every edge in + /// that connected subgraph - see GanjoorRelatedPersonService.GetFamilyTreeAsync). Deliberately not + /// scoped to strict descendants of RootId: an ancestor several rows up, or a spouse's own side of + /// the family, is part of the same connected component and is included too, exactly like + /// akhakhafrasiyab.ir's chart isn't confined to the clicked node's own subtree. + /// + public class GanjoorFamilyTreeViewModel + { + /// + /// the person id the chart was requested for (not necessarily the topmost node once rendered - + /// the client walks Parent/Ancestor edges to find the actual top of each lineage in Persons) + /// + public int RootId { get; set; } + + /// + /// every person in the connected component, including RootId itself + /// + public List Persons { get; set; } + + /// + /// every kinship edge touching any person in Persons + /// + public List Relations { get; set; } + } + + /// + /// a GanjoorPersonRelation row stripped down to what the client-side layout needs (no + /// Person1/Person2 navigation - Persons above already carries full person data) + /// + public class GanjoorFamilyTreeEdge + { + public int Person1Id { get; set; } + public int Person2Id { get; set; } + public PersonRelationType RelationType { get; set; } + public int? DegreeHint { get; set; } + } +} diff --git a/RMuseum/RMuseum.xml b/RMuseum/RMuseum.xml index d42cfca9..69a8c713 100644 --- a/RMuseum/RMuseum.xml +++ b/RMuseum/RMuseum.xml @@ -2860,6 +2860,14 @@ + + + get the whole connected kinship component reachable from this person (ancestors, + descendants, spouses, siblings), for the interactive family-tree chart + + + + suggest an edit to an already-approved person's own fields - any logged-in user, same as @@ -4857,6 +4865,18 @@ + + + + + + + + + + + + donation expenditures @@ -12797,6 +12817,38 @@ destination poem first verse + + + the whole connected kinship component reachable from one person, for the interactive chart at + /FamilyTree/{id} (client draws the layout; this just hands over every person and every edge in + that connected subgraph - see GanjoorRelatedPersonService.GetFamilyTreeAsync). Deliberately not + scoped to strict descendants of RootId: an ancestor several rows up, or a spouse's own side of + the family, is part of the same connected component and is included too, exactly like + akhakhafrasiyab.ir's chart isn't confined to the clicked node's own subtree. + + + + + the person id the chart was requested for (not necessarily the topmost node once rendered - + the client walks Parent/Ancestor edges to find the actual top of each lineage in Persons) + + + + + every person in the connected component, including RootId itself + + + + + every kinship edge touching any person in Persons + + + + + a GanjoorPersonRelation row stripped down to what the client-side layout needs (no + Person1/Person2 navigation - Persons above already carries full person data) + + Rhyme Analysis Result @@ -17912,6 +17964,15 @@ + + + get the whole connected kinship component reachable from this person (ancestors, + descendants, spouses, siblings - whichever edges connect to it, transitively), for the + interactive family-tree chart at /FamilyTree/{id} + + + + submit a suggested edit to an already-approved person's own fields - goes into the @@ -21416,6 +21477,13 @@ + + + get the whole connected kinship component reachable from this person + + + + submit a suggested edit to an already-approved person's own fields diff --git a/RMuseum/Services/IGanjoorRelatedPersonService.cs b/RMuseum/Services/IGanjoorRelatedPersonService.cs index b7934e37..105a5134 100644 --- a/RMuseum/Services/IGanjoorRelatedPersonService.cs +++ b/RMuseum/Services/IGanjoorRelatedPersonService.cs @@ -53,6 +53,15 @@ namespace RMuseum.Services /// Task> GetPoemsByPersonAsync(int id); + /// + /// get the whole connected kinship component reachable from this person (ancestors, + /// descendants, spouses, siblings - whichever edges connect to it, transitively), for the + /// interactive family-tree chart at /FamilyTree/{id} + /// + /// + /// + Task> GetFamilyTreeAsync(int rootId); + /// /// submit a suggested edit to an already-approved person's own fields - goes into the /// pending queue, does not change the person itself until a moderator approves it diff --git a/RMuseum/Services/Implementation/GanjoorRelatedPersonService.cs b/RMuseum/Services/Implementation/GanjoorRelatedPersonService.cs index 3372b8b7..13813a35 100644 --- a/RMuseum/Services/Implementation/GanjoorRelatedPersonService.cs +++ b/RMuseum/Services/Implementation/GanjoorRelatedPersonService.cs @@ -172,6 +172,93 @@ namespace RMuseum.Services.Implementation } } + /// + /// get the whole connected kinship component reachable from this person + /// + /// + /// + public async Task> GetFamilyTreeAsync(int rootId) + { + try + { + var rootExists = await _context.GanjoorRelatedPersons.Where(p => p.Id == rootId).AnyAsync(); + if (!rootExists) + { + return new RServiceResult(null, "شخصیت پیدا نشد."); + } + + // kinship graph tends to be small (a few hundred rows at most for this kind of data), + // so it's simplest/cheapest to load the whole table and walk it in memory rather than + // issuing a recursive query + var allRelations = await _context.GanjoorPersonRelations.ToListAsync(); + + var edgesByPersonId = new Dictionary>(); + void IndexEdge(int personId, GanjoorPersonRelation edge) + { + if (!edgesByPersonId.TryGetValue(personId, out var list)) + { + list = new List(); + edgesByPersonId[personId] = list; + } + list.Add(edge); + } + foreach (var edge in allRelations) + { + IndexEdge(edge.Person1Id, edge); + IndexEdge(edge.Person2Id, edge); + } + + var visitedPersonIds = new HashSet() { rootId }; + var visitedRelationIds = new HashSet(); + var queue = new Queue(); + queue.Enqueue(rootId); + + while (queue.Count > 0) + { + var personId = queue.Dequeue(); + if (!edgesByPersonId.TryGetValue(personId, out var touchingEdges)) + continue; + + foreach (var edge in touchingEdges) + { + visitedRelationIds.Add(edge.Id); + var otherPersonId = edge.Person1Id == personId ? edge.Person2Id : edge.Person1Id; + if (visitedPersonIds.Add(otherPersonId)) + { + queue.Enqueue(otherPersonId); + } + } + } + + var persons = await _context.GanjoorRelatedPersons + .Where(p => visitedPersonIds.Contains(p.Id)) + .OrderBy(p => p.Id) + .ToListAsync(); + + var relations = allRelations + .Where(r => visitedRelationIds.Contains(r.Id)) + .Select(r => new GanjoorFamilyTreeEdge() + { + Person1Id = r.Person1Id, + Person2Id = r.Person2Id, + RelationType = r.RelationType, + DegreeHint = r.DegreeHint, + }) + .ToList(); + + return new RServiceResult(new GanjoorFamilyTreeViewModel() + { + RootId = rootId, + Persons = persons, + Relations = relations, + }); + } + catch (Exception exp) + { + return new RServiceResult(null, exp.ToString()); + } + } + /// /// submit a suggested edit to an already-approved person's own fields ///