2023-10-18 04:55:10 +00:00
|
|
|
// using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
|
|
|
using System.Security.Claims;
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
|
|
|
using PhoneToolMX.Models;
|
|
|
|
using System.Net.NetworkInformation;
|
|
|
|
|
|
|
|
// ReSharper disable CheckNamespace
|
|
|
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
|
|
|
|
|
|
|
namespace PhoneToolMX.Data {
|
|
|
|
public class PTMXContext : DbContext
|
|
|
|
{
|
|
|
|
public DbSet<Phone> Phones { get; set; }
|
|
|
|
public DbSet<PhoneModel> PhoneModels { get; set; }
|
|
|
|
public DbSet<Extension> Extensions { get; set; }
|
|
|
|
public DbSet<CustomData> CustomData { get; set; }
|
|
|
|
public DbSet<User> Users { get; set; }
|
|
|
|
|
|
|
|
public PTMXContext(DbContextOptions<PTMXContext> options) : base(options)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#region Public helpers
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Adds an <see cref="IOwnedModel"/> entity to the database, marking the given <see cref="User"/> as its owner.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="owner">The <see cref="User"/> that owns this entity.</param>
|
|
|
|
/// <param name="entity">The entity to be created.</param>
|
|
|
|
/// <typeparam name="TEntity">A model conforming to <see cref="IOwnedModel"/>.</typeparam>
|
|
|
|
/// <returns>The entity entry for the created entity.</returns>
|
|
|
|
public async Task<EntityEntry<TEntity>> AddOwnable<TEntity>(User owner, TEntity entity) where TEntity: OwnedBase
|
|
|
|
{
|
|
|
|
var set = Set<TEntity>();
|
|
|
|
entity.Owners ??= new List<User>();
|
|
|
|
entity.Owners.Add(owner);
|
|
|
|
var entry = await AddAsync(entity);
|
|
|
|
return entry;
|
|
|
|
}
|
2023-10-20 21:32:56 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a DbSet with all required relationships
|
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TEntity">IOwnedModel</typeparam>
|
|
|
|
/// <returns>DbSet<TEntity></returns>
|
|
|
|
private IQueryable<TEntity> GetFullSet<TEntity>() where TEntity: class, IModel
|
|
|
|
{
|
|
|
|
var set = Set<TEntity>().AsQueryable();
|
|
|
|
return typeof(TEntity).GetProperties()
|
|
|
|
.Where(p => p.GetCustomAttributes(typeof(AlwaysIncludeAttribute), true)
|
|
|
|
.Length != 0)
|
|
|
|
.Aggregate(set, (current, prop) => current.Include(prop.Name));
|
|
|
|
}
|
2023-10-18 04:55:10 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets all entities of a certain model owned by the <see cref="User"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="owner">The <see cref="User"/> object to be considered the owner.</param>
|
|
|
|
/// <typeparam name="TEntity">A model conforming to <see cref="IOwnedModel"/></typeparam>
|
|
|
|
/// <returns>All entities of the model owned by the given user</returns>
|
|
|
|
public ICollection<TEntity> GetOwned<TEntity>(User owner) where TEntity : class, IOwnedModel
|
|
|
|
{
|
|
|
|
if (owner == null) return null;
|
2023-10-20 21:32:56 +00:00
|
|
|
var entity = GetFullSet<TEntity>().Where(x => x.Owners.Any(o => o.Id == owner.Id));
|
2023-10-18 04:55:10 +00:00
|
|
|
// eager load all w/ AlwaysInclude
|
|
|
|
return entity.ToList();
|
|
|
|
}
|
2023-10-20 21:32:56 +00:00
|
|
|
|
2023-10-18 04:55:10 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets a model entity by its Id
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="id">Id of the model, or null if you're like that</param>
|
|
|
|
/// <typeparam name="TEntity">A model confirming to <see cref="IModel"/> that has a given DbSet</typeparam>
|
|
|
|
/// <returns>The model defined by the Id, or null if none exist.</returns>
|
|
|
|
/// <remarks>If null is provided as the id, null will be returned. <c>id</c> is nullable solely for compatibility.
|
|
|
|
/// </remarks>
|
|
|
|
public TEntity GetEntityById<TEntity>(int? id) where TEntity : class, IModel
|
|
|
|
{
|
2023-10-20 21:32:56 +00:00
|
|
|
return id == null ? null : GetFullSet<TEntity>().FirstOrDefault(o => o.Id == id);
|
2023-10-18 04:55:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
|
|
{
|
|
|
|
// Core of PTMX: Phones and extensions
|
|
|
|
var ext = modelBuilder.Entity<Extension>();
|
|
|
|
ext.HasKey(x => x.Id);
|
|
|
|
ext.Property(x => x.Id).UseIdentityColumn();
|
|
|
|
ext.Property(x => x.ExtId).HasComputedColumnSql("\"Id\" + 1000", stored: true);
|
2023-10-20 21:32:56 +00:00
|
|
|
// Randomly generates a 24-char password
|
2023-10-20 19:57:22 +00:00
|
|
|
ext
|
|
|
|
.Property(p => p.Password)
|
|
|
|
.HasDefaultValueSql("encode(gen_random_bytes(18), 'base64')");
|
2023-10-18 04:55:10 +00:00
|
|
|
|
|
|
|
var phone = modelBuilder.Entity<Phone>();
|
|
|
|
phone
|
|
|
|
.HasMany(p => p.Extensions)
|
|
|
|
.WithMany(x => x.Phones);
|
|
|
|
phone.HasKey(p => p.Id);
|
|
|
|
phone.Property(p => p.Id).UseIdentityColumn();
|
2023-10-20 21:32:56 +00:00
|
|
|
phone.HasOne(p => p.PrimaryExtension).WithMany();
|
2023-10-18 04:55:10 +00:00
|
|
|
|
|
|
|
// Wallpapers, ringtones, etc
|
|
|
|
var cd = modelBuilder.Entity<CustomData>();
|
|
|
|
cd.HasKey(c => c.Id);
|
|
|
|
cd.Property(c => c.Id).UseIdentityColumn();
|
|
|
|
|
|
|
|
// Phone models, for custom tests
|
|
|
|
var pm = modelBuilder.Entity<PhoneModel>();
|
|
|
|
pm.HasKey(p => p.Id);
|
|
|
|
pm.Property(p => p.Id).UseIdentityColumn();
|
|
|
|
pm.HasData(new PhoneModel
|
|
|
|
{
|
|
|
|
Id = 0,
|
|
|
|
ModelName = "Polycom VVX300/310",
|
|
|
|
MaxExtensions = 6,
|
|
|
|
PreVvxPolycom = false,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Authz/RBAC
|
|
|
|
var userEnt = modelBuilder.Entity<User>();
|
|
|
|
userEnt
|
|
|
|
.HasMany(u => u.Phones)
|
|
|
|
.WithMany(p => p.Owners);
|
|
|
|
userEnt
|
|
|
|
.HasMany(u => u.Extensions)
|
|
|
|
.WithMany(x => x.Owners);
|
|
|
|
userEnt
|
|
|
|
.HasKey(u => u.Id);
|
|
|
|
|
|
|
|
modelBuilder.Entity<Role>()
|
|
|
|
.HasKey(r => r.Id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|