using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using AX.FireTrainingSys.DTOs; using AX.FireTrainingSys.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Mapster; namespace AX.FireTrainingSys.Controllers.V1 { /// /// 课件库控制器。 /// [Produces("application/json")] [Route("api/[controller]")] [ApiVersion("1.0")] //[Authorize(Roles = "Profile")] [ApiController] public class CoursewaresController : ControllerBase { private readonly DriveDbContext dbContext; public CoursewaresController(DriveDbContext dbContext) { this.dbContext = dbContext; } /// /// 获得课件列表。 /// /// /// [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status200OK)] [HttpGet] public async Task>> Get([FromQuery] CoursewareQueryOptions options) { if (options.PageNumber == null) options.PageNumber = 1; if (options.PageSize == null) options.PageSize = 10; var username = HttpContext.User.FindFirstValue(JwtClaimTypes.Subject); var queryable = dbContext.Coursewares .Include(e => e.User) .Include(e => e.BuildingTypes) .AsNoTracking(); if (options.Others != null) queryable = queryable.Where(e => options.Others.Value ? e.UserId != username : e.UserId == username); if (options.IsPublic != null) queryable = queryable.Where(e => e.IsPublic == options.IsPublic.Value); if (options.Name != null) queryable = queryable.Where(e => e.Name.Contains(options.Name)); if (options.ModifiedTime != null) { var modifiedTime = options.ModifiedTime.Value.UtcDateTime; queryable = queryable.Where(e => e.ModifiedTime >= modifiedTime); } if (options.BuildingType != null) queryable = queryable.Where(e => e.BuildingTypes.Any(c => c.BuildingTypeId == options.BuildingType)); if (!string.IsNullOrEmpty(options.CompanyName)) queryable = queryable.Where(e => e.CompanyName.Contains(options.CompanyName)); var count = await queryable.CountAsync(); queryable = queryable.OrderByDescending(e => e.ModifiedTime); if (options.PageNumber > 1) queryable = queryable.Skip((options.PageNumber.Value - 1) * options.PageSize.Value - 1); queryable = queryable.Take(options.PageSize.Value); var list = await queryable.Select(e => e.ToDTO()) .ToListAsync(); var result = new Page { PageNumber = (int)options.PageNumber, PageSize = (int)options.PageSize, TotalPages = (int)Math.Ceiling((double)count / (int)options.PageSize), TotalCount = count, Items = list }; return Ok(result); } /// /// 新建一个课件。 /// /// 单位/场景名称 /// /// [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status201Created)] [HttpPost] public async Task> Post([FromQuery] string companyName, [FromBody] CoursewareInfo info) { if (string.IsNullOrEmpty(info.Name)) return BadRequest(nameof(info.Name)); if (info.BuildingTypes == null || info.BuildingTypes.Length == 0) return BadRequest(nameof(info.BuildingTypes)); var username = HttpContext.User.FindFirstValue(JwtClaimTypes.Subject); var realname = HttpContext.User.FindFirstValue(JwtClaimTypes.Name); using (var transaction = dbContext.Database.BeginTransaction()) { var model = info.ToModel(username); dbContext.Coursewares.Add(model); var buildingTypes = info.Create(model.Id); dbContext.Set().AddRange(buildingTypes); await dbContext.SaveChangesAsync(); info.Id = model.Id; info.Creator = realname; info.ModifiedTime = model.ModifiedTime.ToLocalTime(); info.Referenced = false; //从模板数据库中初始化课件数据 await dbContext.Database.ExecuteSqlInterpolatedAsync($@" INSERT INTO BuildingAdjoins (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateBuildingAdjoins WHERE CompanyName == {companyName}; INSERT INTO BuildingBasicInfos (CoursewareId, Content) SELECT {info.Id}, Content FROM TemplateBuildingBasicInfos WHERE CompanyName == {companyName}; INSERT INTO BuildingFeatures (CoursewareId, Content) SELECT {info.Id}, Content FROM TemplateBuildingFeatures WHERE CompanyName == {companyName}; INSERT INTO Exits (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateExits WHERE CompanyName == {companyName}; INSERT INTO FireControlRooms (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateFireControlRooms WHERE CompanyName == {companyName}; INSERT INTO FireLifts (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateFireLifts WHERE CompanyName == {companyName}; INSERT INTO FireWaterMonitors (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateFireWaterMonitors WHERE CompanyName == {companyName}; INSERT INTO FoamHydrants (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateFoamHydrants WHERE CompanyName == {companyName}; INSERT INTO FoamPumpRooms (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateFoamPumpRooms WHERE CompanyName == {companyName}; INSERT INTO ImageMarkers (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateImageMarkers WHERE CompanyName == {companyName}; INSERT INTO ImportantLocations (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateImportantLocations WHERE CompanyName == {companyName}; INSERT INTO MunicipalFireHydrants (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateMunicipalFireHydrants WHERE CompanyName == {companyName}; INSERT INTO NoParkingAreas (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateNoParkingAreas WHERE CompanyName == {companyName}; INSERT INTO OutdoorFireHydrants (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateOutdoorFireHydrants WHERE CompanyName == {companyName}; INSERT INTO ProtectedStairways (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateProtectedStairways WHERE CompanyName == {companyName}; INSERT INTO PumpRooms (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplatePumpRooms WHERE CompanyName == {companyName}; INSERT INTO SiameseConnections (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateSiameseConnections WHERE CompanyName == {companyName}; INSERT INTO StorageTanks (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateStorageTanks WHERE CompanyName == {companyName}; INSERT INTO WaterTanks (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM TemplateWaterTanks WHERE CompanyName == {companyName}; INSERT INTO Organizations(CoursewareId, Id, Name, Level, [Order], X, Y, Z, ParentId) SELECT {info.Id}, Id, Name, Level, [Order], X, Y, Z, ParentId FROM TemplateOrganizations; INSERT INTO FireForces(CoursewareId, Id, Type, Content, OrganizationId) SELECT {info.Id}, Id, Type, Content, OrganizationId FROM TemplateFireForces; "); transaction.Commit(); return CreatedAtAction(nameof(Post), info); } } /// /// 另存为一个课件。 /// /// 课件编号 /// [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status201Created)] [HttpPost("[action]")] public async Task> SaveAs([FromQuery] string coursewareId) { if (string.IsNullOrEmpty(coursewareId)) return BadRequest(coursewareId); var m = await dbContext.Coursewares .Include(e => e.BuildingTypes) .Include(e => e.User) .AsNoTracking() .Where(e => e.Id == coursewareId) .FirstOrDefaultAsync(); if (m == null) return NotFound(coursewareId); var info = m.ToDTO(); var username = HttpContext.User.FindFirstValue(JwtClaimTypes.Subject); using (var transaction = dbContext.Database.BeginTransaction()) { var model = info.ToModel(username); dbContext.Coursewares.Add(model); var buildingTypes = info.Create(model.Id); dbContext.Set().AddRange(buildingTypes); await dbContext.SaveChangesAsync(); info.Id = model.Id; info.Creator = username; info.ModifiedTime = model.ModifiedTime.ToLocalTime(); info.Referenced = false; //从相关数据库中初始化课件数据 await dbContext.Database.ExecuteSqlInterpolatedAsync($@" INSERT INTO BuildingAdjoins (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM BuildingAdjoins WHERE CoursewareId == {coursewareId}; INSERT INTO BuildingBasicInfos (CoursewareId, Content) SELECT {info.Id}, Content FROM BuildingBasicInfos WHERE CoursewareId == {coursewareId}; INSERT INTO BuildingFeatures (CoursewareId, Content) SELECT {info.Id}, Content FROM BuildingFeatures WHERE CoursewareId == {coursewareId}; INSERT INTO Exits (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM Exits WHERE CoursewareId == {coursewareId}; INSERT INTO FireControlRooms (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM FireControlRooms WHERE CoursewareId == {coursewareId}; INSERT INTO FireLifts (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM FireLifts WHERE CoursewareId == {coursewareId}; INSERT INTO FireWaterMonitors (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM FireWaterMonitors WHERE CoursewareId == {coursewareId}; INSERT INTO FoamHydrants (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM FoamHydrants WHERE CoursewareId == {coursewareId}; INSERT INTO FoamPumpRooms (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM FoamPumpRooms WHERE CoursewareId == {coursewareId}; INSERT INTO ImageMarkers (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM ImageMarkers WHERE CoursewareId == {coursewareId}; INSERT INTO ImportantLocations (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM ImportantLocations WHERE CoursewareId == {coursewareId}; INSERT INTO MunicipalFireHydrants (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM MunicipalFireHydrants WHERE CoursewareId == {coursewareId}; INSERT INTO NoParkingAreas (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM NoParkingAreas WHERE CoursewareId == {coursewareId}; INSERT INTO OutdoorFireHydrants (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM OutdoorFireHydrants WHERE CoursewareId == {coursewareId}; INSERT INTO ProtectedStairways (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM ProtectedStairways WHERE CoursewareId == {coursewareId}; INSERT INTO PumpRooms (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM PumpRooms WHERE CoursewareId == {coursewareId}; INSERT INTO SiameseConnections (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM SiameseConnections WHERE CoursewareId == {coursewareId}; INSERT INTO StorageTanks (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM StorageTanks WHERE CoursewareId == {coursewareId}; INSERT INTO WaterTanks (CoursewareId, Id, Content) SELECT {info.Id}, Id, Content FROM WaterTanks WHERE CoursewareId == {coursewareId}; INSERT INTO Organizations(CoursewareId, Id, Name, Level, [Order], X, Y, Z, ParentId) SELECT {info.Id}, Id, Name, Level, [Order], X, Y, Z, ParentId FROM Organizations WHERE CoursewareId == {coursewareId}; INSERT INTO FireForces(CoursewareId, Id, Type, Content, OrganizationId) SELECT {info.Id}, Id, Type, Content, OrganizationId FROM FireForces WHERE CoursewareId == {coursewareId}; "); transaction.Commit(); return CreatedAtAction(nameof(Post), info); } } /// /// 修改指定的课件信息。 /// /// /// /// //[ProducesResponseType(ErrorCodes.E620)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status204NoContent)] [HttpPut("{id}")] public async Task Put(string id, [FromBody] CoursewareInfo info) { if (id != info.Id) return BadRequest(id); var username = HttpContext.User.FindFirstValue(JwtClaimTypes.Subject); var model = await dbContext.Coursewares .Include(e => e.BuildingTypes) .FirstOrDefaultAsync(e => e.Id == id); if (model == null) return NotFound(); // 不能修改他人课件 if (model.UserId != username) return Forbid(); // 不能撤销已被引用的公开课件 if (model.IsPublic && model.Referenced > 0 && info.IsPublic != null && info.IsPublic == false) return this.ErrorCode(ErrorCodes.E620); info.MapTo(model); var currItems = model.BuildingTypes; var newItems = info.Create(model.Id); var removedItems = currItems.Except(newItems); var addedItems = newItems.Except(currItems); dbContext.Set().RemoveRange(removedItems); dbContext.Set().AddRange(addedItems); await dbContext.SaveChangesAsync(); return NoContent(); } /// /// 删除指定的课件信息。 /// /// /// //[ProducesResponseType(ErrorCodes.E621)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status204NoContent)] [HttpDelete("{id}")] public async Task Delete(string id) { var username = HttpContext.User.FindFirstValue(JwtClaimTypes.Subject); var model = await dbContext.Coursewares.FindAsync(id); if (model == null) return NotFound(); // 不能删除他人课件 if (model.UserId != username) return Forbid(); // 不能删除已被引用的公开课件 if (model.IsPublic && model.Referenced > 0) return this.ErrorCode(ErrorCodes.E621); model.Deleted = true; model.Name = model.Name + "-" + ObjectId.NewId().ToString(); await dbContext.SaveChangesAsync(); return NoContent(); } } internal static class CoursewareExtensions { public static Courseware ToModel(this CoursewareInfo dto, string creator) { var model = dto.Adapt(); model.UserId = creator; return model; } public static CoursewareInfo ToDTO(this Courseware model) { var buildingTypes = new int[model.BuildingTypes.Count]; var i = 0; foreach (var type in model.BuildingTypes) buildingTypes[i++] = type.BuildingTypeId; var dto = model.Adapt(); dto.BuildingTypes = buildingTypes; return dto; } public static void MapTo(this CoursewareInfo dto, Courseware model) { dto.Adapt(model); model.ModifiedTime = DateTime.UtcNow; } public static IEnumerable Create(this CoursewareInfo dto, string id) { var buildingTypes = new List(dto.BuildingTypes.Length); for (var i = 0; i < dto.BuildingTypes.Length; ++i) { var buildingType = new CoursewareBuildingType { CoursewareId = id, BuildingTypeId = dto.BuildingTypes[i] }; buildingTypes.Add(buildingType); } return buildingTypes; } } }