Compare commits
2 Commits
1bb0012c40
...
665595b8b4
Author | SHA1 | Date | |
---|---|---|---|
|
665595b8b4 | ||
|
29550401fd |
@@ -1,4 +1,5 @@
|
|||||||
using DysonNetwork.Develop.Identity;
|
using DysonNetwork.Develop.Identity;
|
||||||
|
using DysonNetwork.Develop.Project;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Design;
|
using Microsoft.EntityFrameworkCore.Design;
|
||||||
|
|
||||||
@@ -11,6 +12,8 @@ public class AppDatabase(
|
|||||||
{
|
{
|
||||||
public DbSet<Developer> Developers { get; set; } = null!;
|
public DbSet<Developer> Developers { get; set; } = null!;
|
||||||
|
|
||||||
|
public DbSet<DevProject> DevProjects { get; set; } = null!;
|
||||||
|
|
||||||
public DbSet<CustomApp> CustomApps { get; set; } = null!;
|
public DbSet<CustomApp> CustomApps { get; set; } = null!;
|
||||||
public DbSet<CustomAppSecret> CustomAppSecrets { get; set; } = null!;
|
public DbSet<CustomAppSecret> CustomAppSecrets { get; set; } = null!;
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using DysonNetwork.Develop.Project;
|
||||||
using DysonNetwork.Shared.Data;
|
using DysonNetwork.Shared.Data;
|
||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
using Google.Protobuf;
|
using Google.Protobuf;
|
||||||
@@ -37,8 +38,11 @@ public class CustomApp : ModelBase, IIdentifiedResource
|
|||||||
|
|
||||||
[JsonIgnore] public ICollection<CustomAppSecret> Secrets { get; set; } = new List<CustomAppSecret>();
|
[JsonIgnore] public ICollection<CustomAppSecret> Secrets { get; set; } = new List<CustomAppSecret>();
|
||||||
|
|
||||||
public Guid DeveloperId { get; set; }
|
public Guid ProjectId { get; set; }
|
||||||
public Developer Developer { get; set; } = null!;
|
public DevProject Project { get; set; } = null!;
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public Developer Developer => Project.Developer;
|
||||||
|
|
||||||
[NotMapped] public string ResourceIdentifier => "custom-app:" + Id;
|
[NotMapped] public string ResourceIdentifier => "custom-app:" + Id;
|
||||||
|
|
||||||
@@ -72,7 +76,7 @@ public class CustomApp : ModelBase, IIdentifiedResource
|
|||||||
RequirePkce = OauthConfig.RequirePkce,
|
RequirePkce = OauthConfig.RequirePkce,
|
||||||
AllowOfflineAccess = OauthConfig.AllowOfflineAccess
|
AllowOfflineAccess = OauthConfig.AllowOfflineAccess
|
||||||
},
|
},
|
||||||
DeveloperId = DeveloperId.ToString(),
|
ProjectId = ProjectId.ToString(),
|
||||||
CreatedAt = CreatedAt.ToTimestamp(),
|
CreatedAt = CreatedAt.ToTimestamp(),
|
||||||
UpdatedAt = UpdatedAt.ToTimestamp()
|
UpdatedAt = UpdatedAt.ToTimestamp()
|
||||||
};
|
};
|
||||||
@@ -92,7 +96,7 @@ public class CustomApp : ModelBase, IIdentifiedResource
|
|||||||
Shared.Proto.CustomAppStatus.Suspended => CustomAppStatus.Suspended,
|
Shared.Proto.CustomAppStatus.Suspended => CustomAppStatus.Suspended,
|
||||||
_ => CustomAppStatus.Developing
|
_ => CustomAppStatus.Developing
|
||||||
};
|
};
|
||||||
DeveloperId = string.IsNullOrEmpty(p.DeveloperId) ? Guid.Empty : Guid.Parse(p.DeveloperId);
|
ProjectId = string.IsNullOrEmpty(p.ProjectId) ? Guid.Empty : Guid.Parse(p.ProjectId);
|
||||||
CreatedAt = p.CreatedAt.ToInstant();
|
CreatedAt = p.CreatedAt.ToInstant();
|
||||||
UpdatedAt = p.UpdatedAt.ToInstant();
|
UpdatedAt = p.UpdatedAt.ToInstant();
|
||||||
if (p.Picture.Length > 0) Picture = System.Text.Json.JsonSerializer.Deserialize<CloudFileReferenceObject>(p.Picture.ToStringUtf8());
|
if (p.Picture.Length > 0) Picture = System.Text.Json.JsonSerializer.Deserialize<CloudFileReferenceObject>(p.Picture.ToStringUtf8());
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using DysonNetwork.Develop.Project;
|
||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
@@ -6,8 +7,8 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace DysonNetwork.Develop.Identity;
|
namespace DysonNetwork.Develop.Identity;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("/api/developers/{pubName}/apps")]
|
[Route("/api/developers/{pubName}/projects/{projectId:guid}/apps")]
|
||||||
public class CustomAppController(CustomAppService customApps, DeveloperService ds) : ControllerBase
|
public class CustomAppController(CustomAppService customApps, DeveloperService ds, DevProjectService projectService) : ControllerBase
|
||||||
{
|
{
|
||||||
public record CustomAppRequest(
|
public record CustomAppRequest(
|
||||||
[MaxLength(1024)] string? Slug,
|
[MaxLength(1024)] string? Slug,
|
||||||
@@ -21,21 +22,28 @@ public class CustomAppController(CustomAppService customApps, DeveloperService d
|
|||||||
);
|
);
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> ListApps([FromRoute] string pubName)
|
public async Task<IActionResult> ListApps([FromRoute] string pubName, [FromRoute] Guid projectId)
|
||||||
{
|
{
|
||||||
var developer = await ds.GetDeveloperByName(pubName);
|
var developer = await ds.GetDeveloperByName(pubName);
|
||||||
if (developer is null) return NotFound();
|
if (developer is null) return NotFound();
|
||||||
var apps = await customApps.GetAppsByPublisherAsync(developer.Id);
|
|
||||||
|
var project = await projectService.GetProjectAsync(projectId, developer.Id);
|
||||||
|
if (project is null) return NotFound();
|
||||||
|
|
||||||
|
var apps = await customApps.GetAppsByProjectAsync(projectId);
|
||||||
return Ok(apps);
|
return Ok(apps);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id:guid}")]
|
[HttpGet("{appId:guid}")]
|
||||||
public async Task<IActionResult> GetApp([FromRoute] string pubName, Guid id)
|
public async Task<IActionResult> GetApp([FromRoute] string pubName, [FromRoute] Guid projectId, [FromRoute] Guid appId)
|
||||||
{
|
{
|
||||||
var developer = await ds.GetDeveloperByName(pubName);
|
var developer = await ds.GetDeveloperByName(pubName);
|
||||||
if (developer is null) return NotFound();
|
if (developer is null) return NotFound();
|
||||||
|
|
||||||
|
var project = await projectService.GetProjectAsync(projectId, developer.Id);
|
||||||
|
if (project is null) return NotFound();
|
||||||
|
|
||||||
var app = await customApps.GetAppAsync(id, developerId: developer.Id);
|
var app = await customApps.GetAppAsync(appId, projectId);
|
||||||
if (app == null)
|
if (app == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
@@ -44,23 +52,40 @@ public class CustomAppController(CustomAppService customApps, DeveloperService d
|
|||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<IActionResult> CreateApp([FromRoute] string pubName, [FromBody] CustomAppRequest request)
|
public async Task<IActionResult> CreateApp(
|
||||||
|
[FromRoute] string pubName,
|
||||||
|
[FromRoute] Guid projectId,
|
||||||
|
[FromBody] CustomAppRequest request)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var developer = await ds.GetDeveloperByName(pubName);
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
if (developer is null || developer.Id != accountId)
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
var project = await projectService.GetProjectAsync(projectId, developer.Id);
|
||||||
|
if (project is null)
|
||||||
|
return NotFound("Project not found or you don't have access");
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(request.Name) || string.IsNullOrWhiteSpace(request.Slug))
|
if (string.IsNullOrWhiteSpace(request.Name) || string.IsNullOrWhiteSpace(request.Slug))
|
||||||
return BadRequest("Name and slug are required");
|
return BadRequest("Name and slug are required");
|
||||||
|
|
||||||
var developer = await ds.GetDeveloperByName(pubName);
|
|
||||||
if (developer is null) return NotFound();
|
|
||||||
|
|
||||||
if (!await ds.IsMemberWithRole(developer.PublisherId, Guid.Parse(currentUser.Id), PublisherMemberRole.Editor))
|
if (!await ds.IsMemberWithRole(developer.PublisherId, Guid.Parse(currentUser.Id), PublisherMemberRole.Editor))
|
||||||
return StatusCode(403, "You must be an editor of the developer to create a custom app");
|
return StatusCode(403, "You must be an editor of the developer to create a custom app");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var app = await customApps.CreateAppAsync(developer, request);
|
var app = await customApps.CreateAppAsync(projectId, request);
|
||||||
return Ok(app);
|
if (app == null)
|
||||||
|
return BadRequest("Failed to create app");
|
||||||
|
|
||||||
|
return CreatedAtAction(
|
||||||
|
nameof(GetApp),
|
||||||
|
new { pubName, projectId, appId = app.Id },
|
||||||
|
app
|
||||||
|
);
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex)
|
catch (InvalidOperationException ex)
|
||||||
{
|
{
|
||||||
@@ -68,23 +93,30 @@ public class CustomAppController(CustomAppService customApps, DeveloperService d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPatch("{id:guid}")]
|
[HttpPatch("{appId:guid}")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<IActionResult> UpdateApp(
|
public async Task<IActionResult> UpdateApp(
|
||||||
[FromRoute] string pubName,
|
[FromRoute] string pubName,
|
||||||
[FromRoute] Guid id,
|
[FromRoute] Guid projectId,
|
||||||
|
[FromRoute] Guid appId,
|
||||||
[FromBody] CustomAppRequest request
|
[FromBody] CustomAppRequest request
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
var developer = await ds.GetDeveloperByName(pubName);
|
var developer = await ds.GetDeveloperByName(pubName);
|
||||||
if (developer is null) return NotFound();
|
if (developer is null)
|
||||||
|
return NotFound("Developer not found");
|
||||||
|
|
||||||
if (!await ds.IsMemberWithRole(developer.PublisherId, Guid.Parse(currentUser.Id), PublisherMemberRole.Editor))
|
if (!await ds.IsMemberWithRole(developer.PublisherId, Guid.Parse(currentUser.Id), PublisherMemberRole.Editor))
|
||||||
return StatusCode(403, "You must be an editor of the developer to update a custom app");
|
return StatusCode(403, "You must be an editor of the developer to update a custom app");
|
||||||
|
|
||||||
|
var project = await projectService.GetProjectAsync(projectId, developer.Id);
|
||||||
|
if (project is null)
|
||||||
|
return NotFound("Project not found or you don't have access");
|
||||||
|
|
||||||
var app = await customApps.GetAppAsync(id, developerId: developer.Id);
|
var app = await customApps.GetAppAsync(appId, projectId);
|
||||||
if (app == null)
|
if (app == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
@@ -99,28 +131,36 @@ public class CustomAppController(CustomAppService customApps, DeveloperService d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete("{id:guid}")]
|
[HttpDelete("{appId:guid}")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
public async Task<IActionResult> DeleteApp(
|
public async Task<IActionResult> DeleteApp(
|
||||||
[FromRoute] string pubName,
|
[FromRoute] string pubName,
|
||||||
[FromRoute] Guid id
|
[FromRoute] Guid projectId,
|
||||||
|
[FromRoute] Guid appId
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
var developer = await ds.GetDeveloperByName(pubName);
|
var developer = await ds.GetDeveloperByName(pubName);
|
||||||
if (developer is null) return NotFound();
|
if (developer is null)
|
||||||
|
return NotFound("Developer not found");
|
||||||
|
|
||||||
if (!await ds.IsMemberWithRole(developer.PublisherId, Guid.Parse(currentUser.Id), PublisherMemberRole.Editor))
|
if (!await ds.IsMemberWithRole(developer.PublisherId, Guid.Parse(currentUser.Id), PublisherMemberRole.Editor))
|
||||||
return StatusCode(403, "You must be an editor of the developer to delete a custom app");
|
return StatusCode(403, "You must be an editor of the developer to delete a custom app");
|
||||||
|
|
||||||
|
var project = await projectService.GetProjectAsync(projectId, developer.Id);
|
||||||
|
if (project is null)
|
||||||
|
return NotFound("Project not found or you don't have access");
|
||||||
|
|
||||||
var app = await customApps.GetAppAsync(id, developerId: developer.Id);
|
var app = await customApps.GetAppAsync(appId, projectId);
|
||||||
if (app == null)
|
if (app == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
var result = await customApps.DeleteAppAsync(id);
|
var result = await customApps.DeleteAppAsync(appId);
|
||||||
if (!result)
|
if (!result)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,3 +1,4 @@
|
|||||||
|
using DysonNetwork.Develop.Project;
|
||||||
using DysonNetwork.Shared.Data;
|
using DysonNetwork.Shared.Data;
|
||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -11,10 +12,17 @@ public class CustomAppService(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
public async Task<CustomApp?> CreateAppAsync(
|
public async Task<CustomApp?> CreateAppAsync(
|
||||||
Developer pub,
|
Guid projectId,
|
||||||
CustomAppController.CustomAppRequest request
|
CustomAppController.CustomAppRequest request
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
var project = await db.DevProjects
|
||||||
|
.Include(p => p.Developer)
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == projectId);
|
||||||
|
|
||||||
|
if (project == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
var app = new CustomApp
|
var app = new CustomApp
|
||||||
{
|
{
|
||||||
Slug = request.Slug!,
|
Slug = request.Slug!,
|
||||||
@@ -23,7 +31,7 @@ public class CustomAppService(
|
|||||||
Status = request.Status ?? CustomAppStatus.Developing,
|
Status = request.Status ?? CustomAppStatus.Developing,
|
||||||
Links = request.Links,
|
Links = request.Links,
|
||||||
OauthConfig = request.OauthConfig,
|
OauthConfig = request.OauthConfig,
|
||||||
DeveloperId = pub.Id
|
ProjectId = projectId
|
||||||
};
|
};
|
||||||
|
|
||||||
if (request.PictureId is not null)
|
if (request.PictureId is not null)
|
||||||
@@ -74,17 +82,23 @@ public class CustomAppService(
|
|||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CustomApp?> GetAppAsync(Guid id, Guid? developerId = null)
|
public async Task<CustomApp?> GetAppAsync(Guid id, Guid? projectId = null)
|
||||||
{
|
{
|
||||||
var query = db.CustomApps.Where(a => a.Id == id).AsQueryable();
|
var query = db.CustomApps.AsQueryable();
|
||||||
if (developerId.HasValue)
|
|
||||||
query = query.Where(a => a.DeveloperId == developerId.Value);
|
if (projectId.HasValue)
|
||||||
return await query.FirstOrDefaultAsync();
|
{
|
||||||
|
query = query.Where(a => a.ProjectId == projectId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await query.FirstOrDefaultAsync(a => a.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<CustomApp>> GetAppsByPublisherAsync(Guid publisherId)
|
public async Task<List<CustomApp>> GetAppsByProjectAsync(Guid projectId)
|
||||||
{
|
{
|
||||||
return await db.CustomApps.Where(a => a.DeveloperId == publisherId).ToListAsync();
|
return await db.CustomApps
|
||||||
|
.Where(a => a.ProjectId == projectId)
|
||||||
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CustomApp?> UpdateAppAsync(CustomApp app, CustomAppController.CustomAppRequest request)
|
public async Task<CustomApp?> UpdateAppAsync(CustomApp app, CustomAppController.CustomAppRequest request)
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using DysonNetwork.Develop.Project;
|
||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
using DysonNetwork.Shared.Data;
|
using DysonNetwork.Shared.Data;
|
||||||
using VerificationMark = DysonNetwork.Shared.Data.VerificationMark;
|
using VerificationMark = DysonNetwork.Shared.Data.VerificationMark;
|
||||||
@@ -10,6 +11,8 @@ public class Developer
|
|||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
public Guid PublisherId { get; set; }
|
public Guid PublisherId { get; set; }
|
||||||
|
|
||||||
|
public List<DevProject> Projects { get; set; } = [];
|
||||||
|
|
||||||
[NotMapped] public PublisherInfo? Publisher { get; set; }
|
[NotMapped] public PublisherInfo? Publisher { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,7 +33,8 @@ public class DeveloperController(
|
|||||||
|
|
||||||
// Get custom apps count
|
// Get custom apps count
|
||||||
var customAppsCount = await db.CustomApps
|
var customAppsCount = await db.CustomApps
|
||||||
.Where(a => a.DeveloperId == developer.Id)
|
.Include(a => a.Project)
|
||||||
|
.Where(a => a.Project.DeveloperId == developer.Id)
|
||||||
.CountAsync();
|
.CountAsync();
|
||||||
|
|
||||||
var stats = new DeveloperStats
|
var stats = new DeveloperStats
|
||||||
|
270
DysonNetwork.Develop/Migrations/20250818124844_AddDevProject.Designer.cs
generated
Normal file
270
DysonNetwork.Develop/Migrations/20250818124844_AddDevProject.Designer.cs
generated
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using DysonNetwork.Develop;
|
||||||
|
using DysonNetwork.Develop.Identity;
|
||||||
|
using DysonNetwork.Shared.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using NodaTime;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace DysonNetwork.Develop.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(AppDatabase))]
|
||||||
|
[Migration("20250818124844_AddDevProject")]
|
||||||
|
partial class AddDevProject
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.7")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomApp", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<CloudFileReferenceObject>("Background")
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("background");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("character varying(4096)")
|
||||||
|
.HasColumnName("description");
|
||||||
|
|
||||||
|
b.Property<CustomAppLinks>("Links")
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("links");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<CustomAppOauthConfig>("OauthConfig")
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("oauth_config");
|
||||||
|
|
||||||
|
b.Property<CloudFileReferenceObject>("Picture")
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("picture");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("project_id");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("slug");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("status");
|
||||||
|
|
||||||
|
b.Property<Instant>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
|
b.Property<VerificationMark>("Verification")
|
||||||
|
.HasColumnType("jsonb")
|
||||||
|
.HasColumnName("verification");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_custom_apps");
|
||||||
|
|
||||||
|
b.HasIndex("ProjectId")
|
||||||
|
.HasDatabaseName("ix_custom_apps_project_id");
|
||||||
|
|
||||||
|
b.ToTable("custom_apps", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomAppSecret", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<Guid>("AppId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("app_id");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("character varying(4096)")
|
||||||
|
.HasColumnName("description");
|
||||||
|
|
||||||
|
b.Property<Instant?>("ExpiredAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("expired_at");
|
||||||
|
|
||||||
|
b.Property<bool>("IsOidc")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("is_oidc");
|
||||||
|
|
||||||
|
b.Property<string>("Secret")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("secret");
|
||||||
|
|
||||||
|
b.Property<Instant>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_custom_app_secrets");
|
||||||
|
|
||||||
|
b.HasIndex("AppId")
|
||||||
|
.HasDatabaseName("ix_custom_app_secrets_app_id");
|
||||||
|
|
||||||
|
b.ToTable("custom_app_secrets", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.Developer", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<Guid>("PublisherId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("publisher_id");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_developers");
|
||||||
|
|
||||||
|
b.ToTable("developers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Project.DevProject", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("character varying(4096)")
|
||||||
|
.HasColumnName("description");
|
||||||
|
|
||||||
|
b.Property<Guid>("DeveloperId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("developer_id");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("slug");
|
||||||
|
|
||||||
|
b.Property<Instant>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_dev_projects");
|
||||||
|
|
||||||
|
b.HasIndex("DeveloperId")
|
||||||
|
.HasDatabaseName("ix_dev_projects_developer_id");
|
||||||
|
|
||||||
|
b.ToTable("dev_projects", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomApp", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DysonNetwork.Develop.Project.DevProject", "Project")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProjectId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_custom_apps_dev_projects_project_id");
|
||||||
|
|
||||||
|
b.Navigation("Project");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomAppSecret", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DysonNetwork.Develop.Identity.CustomApp", "App")
|
||||||
|
.WithMany("Secrets")
|
||||||
|
.HasForeignKey("AppId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_custom_app_secrets_custom_apps_app_id");
|
||||||
|
|
||||||
|
b.Navigation("App");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Project.DevProject", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DysonNetwork.Develop.Identity.Developer", "Developer")
|
||||||
|
.WithMany("Projects")
|
||||||
|
.HasForeignKey("DeveloperId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_dev_projects_developers_developer_id");
|
||||||
|
|
||||||
|
b.Navigation("Developer");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomApp", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Secrets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.Developer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Projects");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,96 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using NodaTime;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace DysonNetwork.Develop.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddDevProject : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "fk_custom_apps_developers_developer_id",
|
||||||
|
table: "custom_apps");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "developer_id",
|
||||||
|
table: "custom_apps",
|
||||||
|
newName: "project_id");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "ix_custom_apps_developer_id",
|
||||||
|
table: "custom_apps",
|
||||||
|
newName: "ix_custom_apps_project_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "dev_projects",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
slug = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
name = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: false),
|
||||||
|
description = table.Column<string>(type: "character varying(4096)", maxLength: 4096, nullable: false),
|
||||||
|
developer_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
created_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_at = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
||||||
|
deleted_at = table.Column<Instant>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_dev_projects", x => x.id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_dev_projects_developers_developer_id",
|
||||||
|
column: x => x.developer_id,
|
||||||
|
principalTable: "developers",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_dev_projects_developer_id",
|
||||||
|
table: "dev_projects",
|
||||||
|
column: "developer_id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "fk_custom_apps_dev_projects_project_id",
|
||||||
|
table: "custom_apps",
|
||||||
|
column: "project_id",
|
||||||
|
principalTable: "dev_projects",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "fk_custom_apps_dev_projects_project_id",
|
||||||
|
table: "custom_apps");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "dev_projects");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "project_id",
|
||||||
|
table: "custom_apps",
|
||||||
|
newName: "developer_id");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "ix_custom_apps_project_id",
|
||||||
|
table: "custom_apps",
|
||||||
|
newName: "ix_custom_apps_developer_id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "fk_custom_apps_developers_developer_id",
|
||||||
|
table: "custom_apps",
|
||||||
|
column: "developer_id",
|
||||||
|
principalTable: "developers",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -49,10 +49,6 @@ namespace DysonNetwork.Develop.Migrations
|
|||||||
.HasColumnType("character varying(4096)")
|
.HasColumnType("character varying(4096)")
|
||||||
.HasColumnName("description");
|
.HasColumnName("description");
|
||||||
|
|
||||||
b.Property<Guid>("DeveloperId")
|
|
||||||
.HasColumnType("uuid")
|
|
||||||
.HasColumnName("developer_id");
|
|
||||||
|
|
||||||
b.Property<CustomAppLinks>("Links")
|
b.Property<CustomAppLinks>("Links")
|
||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasColumnName("links");
|
.HasColumnName("links");
|
||||||
@@ -71,6 +67,10 @@ namespace DysonNetwork.Develop.Migrations
|
|||||||
.HasColumnType("jsonb")
|
.HasColumnType("jsonb")
|
||||||
.HasColumnName("picture");
|
.HasColumnName("picture");
|
||||||
|
|
||||||
|
b.Property<Guid>("ProjectId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("project_id");
|
||||||
|
|
||||||
b.Property<string>("Slug")
|
b.Property<string>("Slug")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(1024)
|
.HasMaxLength(1024)
|
||||||
@@ -92,8 +92,8 @@ namespace DysonNetwork.Develop.Migrations
|
|||||||
b.HasKey("Id")
|
b.HasKey("Id")
|
||||||
.HasName("pk_custom_apps");
|
.HasName("pk_custom_apps");
|
||||||
|
|
||||||
b.HasIndex("DeveloperId")
|
b.HasIndex("ProjectId")
|
||||||
.HasDatabaseName("ix_custom_apps_developer_id");
|
.HasDatabaseName("ix_custom_apps_project_id");
|
||||||
|
|
||||||
b.ToTable("custom_apps", (string)null);
|
b.ToTable("custom_apps", (string)null);
|
||||||
});
|
});
|
||||||
@@ -166,16 +166,66 @@ namespace DysonNetwork.Develop.Migrations
|
|||||||
b.ToTable("developers", (string)null);
|
b.ToTable("developers", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Project.DevProject", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<Instant>("CreatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_at");
|
||||||
|
|
||||||
|
b.Property<Instant?>("DeletedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("deleted_at");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(4096)
|
||||||
|
.HasColumnType("character varying(4096)")
|
||||||
|
.HasColumnName("description");
|
||||||
|
|
||||||
|
b.Property<Guid>("DeveloperId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("developer_id");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("character varying(1024)")
|
||||||
|
.HasColumnName("slug");
|
||||||
|
|
||||||
|
b.Property<Instant>("UpdatedAt")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("updated_at");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_dev_projects");
|
||||||
|
|
||||||
|
b.HasIndex("DeveloperId")
|
||||||
|
.HasDatabaseName("ix_dev_projects_developer_id");
|
||||||
|
|
||||||
|
b.ToTable("dev_projects", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomApp", b =>
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomApp", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("DysonNetwork.Develop.Identity.Developer", "Developer")
|
b.HasOne("DysonNetwork.Develop.Project.DevProject", "Project")
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey("DeveloperId")
|
.HasForeignKey("ProjectId")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasConstraintName("fk_custom_apps_developers_developer_id");
|
.HasConstraintName("fk_custom_apps_dev_projects_project_id");
|
||||||
|
|
||||||
b.Navigation("Developer");
|
b.Navigation("Project");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomAppSecret", b =>
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomAppSecret", b =>
|
||||||
@@ -190,10 +240,27 @@ namespace DysonNetwork.Develop.Migrations
|
|||||||
b.Navigation("App");
|
b.Navigation("App");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Project.DevProject", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("DysonNetwork.Develop.Identity.Developer", "Developer")
|
||||||
|
.WithMany("Projects")
|
||||||
|
.HasForeignKey("DeveloperId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_dev_projects_developers_developer_id");
|
||||||
|
|
||||||
|
b.Navigation("Developer");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomApp", b =>
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.CustomApp", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Secrets");
|
b.Navigation("Secrets");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("DysonNetwork.Develop.Identity.Developer", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Projects");
|
||||||
|
});
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
DysonNetwork.Develop/Project/DevProject.cs
Normal file
16
DysonNetwork.Develop/Project/DevProject.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using DysonNetwork.Develop.Identity;
|
||||||
|
using DysonNetwork.Shared.Data;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Develop.Project;
|
||||||
|
|
||||||
|
public class DevProject : ModelBase
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
|
[MaxLength(1024)] public string Slug { get; set; } = string.Empty;
|
||||||
|
[MaxLength(1024)] public string Name { get; set; } = string.Empty;
|
||||||
|
[MaxLength(4096)] public string Description { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public Developer Developer { get; set; } = null!;
|
||||||
|
public Guid DeveloperId { get; set; }
|
||||||
|
}
|
107
DysonNetwork.Develop/Project/DevProjectController.cs
Normal file
107
DysonNetwork.Develop/Project/DevProjectController.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using DysonNetwork.Develop.Identity;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using DysonNetwork.Shared.Proto;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Develop.Project;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("/api/developers/{pubName}/projects")]
|
||||||
|
public class DevProjectController(DevProjectService projectService, DeveloperService developerService) : ControllerBase
|
||||||
|
{
|
||||||
|
public record DevProjectRequest(
|
||||||
|
[MaxLength(1024)] string? Slug,
|
||||||
|
[MaxLength(1024)] string? Name,
|
||||||
|
[MaxLength(4096)] string? Description
|
||||||
|
);
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> ListProjects([FromRoute] string pubName)
|
||||||
|
{
|
||||||
|
var developer = await developerService.GetDeveloperByName(pubName);
|
||||||
|
if (developer is null) return NotFound();
|
||||||
|
|
||||||
|
var projects = await projectService.GetProjectsByDeveloperAsync(developer.Id);
|
||||||
|
return Ok(projects);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{id:guid}")]
|
||||||
|
public async Task<IActionResult> GetProject([FromRoute] string pubName, Guid id)
|
||||||
|
{
|
||||||
|
var developer = await developerService.GetDeveloperByName(pubName);
|
||||||
|
if (developer is null) return NotFound();
|
||||||
|
|
||||||
|
var project = await projectService.GetProjectAsync(id, developer.Id);
|
||||||
|
if (project is null) return NotFound();
|
||||||
|
|
||||||
|
return Ok(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> CreateProject([FromRoute] string pubName, [FromBody] DevProjectRequest request)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var developer = await developerService.GetDeveloperByName(pubName);
|
||||||
|
if (developer is null)
|
||||||
|
return NotFound("Developer not found");
|
||||||
|
|
||||||
|
if (!await developerService.IsMemberWithRole(developer.PublisherId, Guid.Parse(currentUser.Id), PublisherMemberRole.Editor))
|
||||||
|
return StatusCode(403, "You must be an editor of the developer to create a project");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(request.Slug) || string.IsNullOrWhiteSpace(request.Name))
|
||||||
|
return BadRequest("Slug and Name are required");
|
||||||
|
|
||||||
|
var project = await projectService.CreateProjectAsync(developer, request);
|
||||||
|
return CreatedAtAction(
|
||||||
|
nameof(GetProject),
|
||||||
|
new { pubName, id = project.Id },
|
||||||
|
project
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{id:guid}")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> UpdateProject(
|
||||||
|
[FromRoute] string pubName,
|
||||||
|
[FromRoute] Guid id,
|
||||||
|
[FromBody] DevProjectRequest request
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var developer = await developerService.GetDeveloperByName(pubName);
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
if (developer is null || developer.Id != accountId)
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
var project = await projectService.UpdateProjectAsync(id, developer.Id, request);
|
||||||
|
if (project is null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return Ok(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id:guid}")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> DeleteProject([FromRoute] string pubName, [FromRoute] Guid id)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var developer = await developerService.GetDeveloperByName(pubName);
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
if (developer is null || developer.Id != accountId)
|
||||||
|
return Forbid();
|
||||||
|
|
||||||
|
var success = await projectService.DeleteProjectAsync(id, developer.Id);
|
||||||
|
if (!success)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
}
|
77
DysonNetwork.Develop/Project/DevProjectService.cs
Normal file
77
DysonNetwork.Develop/Project/DevProjectService.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using DysonNetwork.Develop.Identity;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using DysonNetwork.Shared.Proto;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Develop.Project;
|
||||||
|
|
||||||
|
public class DevProjectService(
|
||||||
|
AppDatabase db,
|
||||||
|
FileReferenceService.FileReferenceServiceClient fileRefs,
|
||||||
|
FileService.FileServiceClient files
|
||||||
|
)
|
||||||
|
{
|
||||||
|
public async Task<DevProject> CreateProjectAsync(
|
||||||
|
Developer developer,
|
||||||
|
DevProjectController.DevProjectRequest request
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var project = new DevProject
|
||||||
|
{
|
||||||
|
Slug = request.Slug!,
|
||||||
|
Name = request.Name!,
|
||||||
|
Description = request.Description ?? string.Empty,
|
||||||
|
DeveloperId = developer.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
db.DevProjects.Add(project);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<DevProject?> GetProjectAsync(Guid id, Guid? developerId = null)
|
||||||
|
{
|
||||||
|
var query = db.DevProjects.AsQueryable();
|
||||||
|
|
||||||
|
if (developerId.HasValue)
|
||||||
|
{
|
||||||
|
query = query.Where(p => p.DeveloperId == developerId.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await query.FirstOrDefaultAsync(p => p.Id == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<DevProject>> GetProjectsByDeveloperAsync(Guid developerId)
|
||||||
|
{
|
||||||
|
return await db.DevProjects
|
||||||
|
.Where(p => p.DeveloperId == developerId)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<DevProject?> UpdateProjectAsync(
|
||||||
|
Guid id,
|
||||||
|
Guid developerId,
|
||||||
|
DevProjectController.DevProjectRequest request
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var project = await GetProjectAsync(id, developerId);
|
||||||
|
if (project == null) return null;
|
||||||
|
|
||||||
|
if (request.Slug != null) project.Slug = request.Slug;
|
||||||
|
if (request.Name != null) project.Name = request.Name;
|
||||||
|
if (request.Description != null) project.Description = request.Description;
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> DeleteProjectAsync(Guid id, Guid developerId)
|
||||||
|
{
|
||||||
|
var project = await GetProjectAsync(id, developerId);
|
||||||
|
if (project == null) return false;
|
||||||
|
|
||||||
|
db.DevProjects.Remove(project);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@@ -4,6 +4,7 @@ using NodaTime;
|
|||||||
using NodaTime.Serialization.SystemTextJson;
|
using NodaTime.Serialization.SystemTextJson;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using DysonNetwork.Develop.Identity;
|
using DysonNetwork.Develop.Identity;
|
||||||
|
using DysonNetwork.Develop.Project;
|
||||||
using DysonNetwork.Shared.Cache;
|
using DysonNetwork.Shared.Cache;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ public static class ServiceCollectionExtensions
|
|||||||
|
|
||||||
services.AddScoped<DeveloperService>();
|
services.AddScoped<DeveloperService>();
|
||||||
services.AddScoped<CustomAppService>();
|
services.AddScoped<CustomAppService>();
|
||||||
|
services.AddScoped<DevProjectService>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ using System.Net.Security;
|
|||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using DysonNetwork.Shared.Registry;
|
using DysonNetwork.Shared.Registry;
|
||||||
using Yarp.ReverseProxy.Configuration;
|
using Yarp.ReverseProxy.Configuration;
|
||||||
|
using Yarp.ReverseProxy.Transforms;
|
||||||
|
|
||||||
namespace DysonNetwork.Gateway.Startup;
|
namespace DysonNetwork.Gateway.Startup;
|
||||||
|
|
||||||
@@ -15,11 +16,15 @@ public static class ServiceCollectionExtensions
|
|||||||
.AddReverseProxy()
|
.AddReverseProxy()
|
||||||
.ConfigureHttpClient((context, handler) =>
|
.ConfigureHttpClient((context, handler) =>
|
||||||
{
|
{
|
||||||
var caCert = X509CertificateLoader.LoadCertificateFromFile(configuration["CaCert"]!);
|
// var caCert = X509CertificateLoader.LoadCertificateFromFile(configuration["CaCert"]!);
|
||||||
handler.SslOptions = new SslClientAuthenticationOptions
|
handler.SslOptions = new SslClientAuthenticationOptions
|
||||||
{
|
{
|
||||||
RemoteCertificateValidationCallback = (sender, cert, chain, errors) => true
|
RemoteCertificateValidationCallback = (sender, cert, chain, errors) => true
|
||||||
};
|
};
|
||||||
|
})
|
||||||
|
.AddTransforms(context =>
|
||||||
|
{
|
||||||
|
context.AddForwarded();
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddRegistryService(configuration, addForwarder: false);
|
services.AddRegistryService(configuration, addForwarder: false);
|
||||||
|
@@ -39,7 +39,7 @@ enum CustomAppStatus {
|
|||||||
bytes links = 9;
|
bytes links = 9;
|
||||||
CustomAppOauthConfig oauth_config = 13;
|
CustomAppOauthConfig oauth_config = 13;
|
||||||
|
|
||||||
string developer_id = 10;
|
string project_id = 10;
|
||||||
|
|
||||||
google.protobuf.Timestamp created_at = 11;
|
google.protobuf.Timestamp created_at = 11;
|
||||||
google.protobuf.Timestamp updated_at = 12;
|
google.protobuf.Timestamp updated_at = 12;
|
||||||
|
@@ -57,6 +57,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFileResult_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0b5acdd962e549369896cece0026e556214600_003F8c_003F9f6e3f4f_003FFileResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFileResult_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0b5acdd962e549369896cece0026e556214600_003F8c_003F9f6e3f4f_003FFileResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFirebaseSender_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6aadc2cf048f477d8636fb2def7b73648200_003F5c_003F1f5bca3f_003FFirebaseSender_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFirebaseSender_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6aadc2cf048f477d8636fb2def7b73648200_003F5c_003F1f5bca3f_003FFirebaseSender_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AForwardedHeaders_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcfe5737f9bb84738979cbfedd11822a8ea00_003F50_003F9a335f87_003FForwardedHeaders_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AForwardedHeaders_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcfe5737f9bb84738979cbfedd11822a8ea00_003F50_003F9a335f87_003FForwardedHeaders_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AForwardedTransformExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003F03_003F36e779df_003FForwardedTransformExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpContext_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc181aff8c6ec418494a7efcfec578fc154e00_003Fd0_003Fcc905531_003FHttpContext_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpContext_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fc181aff8c6ec418494a7efcfec578fc154e00_003Fd0_003Fcc905531_003FHttpContext_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpRequestHeaders_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb904f9896c4049fabd596decf1be9c381dc400_003F32_003F906beb77_003FHttpRequestHeaders_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpRequestHeaders_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb904f9896c4049fabd596decf1be9c381dc400_003F32_003F906beb77_003FHttpRequestHeaders_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpStatusCode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb3f2e07d4b3f4b42a41fbcf3137e534f3be00_003Fe2_003F215f9441_003FHttpStatusCode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpStatusCode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb3f2e07d4b3f4b42a41fbcf3137e534f3be00_003Fe2_003F215f9441_003FHttpStatusCode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
@@ -120,6 +121,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARequestTransform_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003Fa2_003Fe06c3ffa_003FRequestTransform_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARequestTransform_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003Fa2_003Fe06c3ffa_003FRequestTransform_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResizeOptions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fef3339e864a448e2b1ec6fa7bbf4c6661fee00_003F48_003F0209e410_003FResizeOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResizeOptions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fef3339e864a448e2b1ec6fa7bbf4c6661fee00_003F48_003F0209e410_003FResizeOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResourceManagerStringLocalizerFactory_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb62f365d06c44ad695ff75960cdf97a2a800_003Fe4_003Ff6ba93b7_003FResourceManagerStringLocalizerFactory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResourceManagerStringLocalizerFactory_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb62f365d06c44ad695ff75960cdf97a2a800_003Fe4_003Ff6ba93b7_003FResourceManagerStringLocalizerFactory_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReverseProxyIEndpointRouteBuilderExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003Fa1_003F34726adb_003FReverseProxyIEndpointRouteBuilderExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReverseProxyServiceCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003F13_003F8595a157_003FReverseProxyServiceCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReverseProxyServiceCollectionExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003F13_003F8595a157_003FReverseProxyServiceCollectionExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARouteConfig_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003F84_003F98414804_003FRouteConfig_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARouteConfig_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fbf3f51607a3e4e76b5b91640cd7409195c430_003F84_003F98414804_003FRouteConfig_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARSA_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fee4f989f6b8042b59b2654fdc188e287243600_003F8b_003F44e5f855_003FRSA_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARSA_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fee4f989f6b8042b59b2654fdc188e287243600_003F8b_003F44e5f855_003FRSA_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
Reference in New Issue
Block a user