342 lines
14 KiB
C#
342 lines
14 KiB
C#
using System.Globalization;
|
|
using System.Security.Claims;
|
|
using Asp.Versioning;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using ServerCommon;
|
|
using ServerCommon.UGQ.Models;
|
|
using Swashbuckle.AspNetCore.Annotations;
|
|
using UGQApiServer.Controllers.Common;
|
|
using UGQApiServer.Converter;
|
|
using UGQApiServer.Models;
|
|
using UGQDataAccess.Repository.Models;
|
|
using UGQDataAccess.Service;
|
|
using UGQDatabase.Models;
|
|
using ServerBase;
|
|
|
|
|
|
namespace UGQApiServer.Controllers.Admin;
|
|
|
|
|
|
[Authorize]
|
|
[ApiController]
|
|
[ApiVersion("1.0")]
|
|
[ApiExplorerSettings(GroupName = "admin")]
|
|
[Route("api/v{version:apiVersion}/Admin/QuestEditor")]
|
|
[ControllerName("QuestEditor")]
|
|
[UGQAdminApi]
|
|
[Authorize(Roles = "Admin,Service")]
|
|
public class AdminQuestEditorController : ControllerBase
|
|
{
|
|
const int MAX_PAGE_SIZE = 100;
|
|
|
|
AccountService _accountService;
|
|
QuestEditorService _questEditorService;
|
|
|
|
MetaDataApi _metaDataApi;
|
|
QuestEditorApi _questEditorApi;
|
|
|
|
DynamoDbClient _dynamoDbClient;
|
|
|
|
public AdminQuestEditorController(
|
|
AccountService accountService,
|
|
QuestEditorService questEditorService, MetaDataApi metaDataApi, QuestEditorApi questEditorApi, DynamoDbClient dynamoDbClient)
|
|
{
|
|
_accountService = accountService;
|
|
_questEditorService = questEditorService;
|
|
_metaDataApi = metaDataApi;
|
|
_questEditorApi = questEditorApi;
|
|
_dynamoDbClient = dynamoDbClient;
|
|
}
|
|
|
|
string? adminUsernameFromToken()
|
|
{
|
|
return User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 생성
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 빈 슬롯에 퀘스트 추가하는 경우에 호출
|
|
/// </remarks>
|
|
[HttpPost]
|
|
[Route("quest")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(UGQContent))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> addQuest([FromQuery] string userGuid, [FromBody] UGQSaveQuestModel saveQuestModel)
|
|
{
|
|
string? adminUsername = adminUsernameFromToken();
|
|
if(adminUsername == null)
|
|
return Results.Unauthorized();
|
|
|
|
return await _questEditorApi.addQuest(userGuid, saveQuestModel, adminUsername);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 내용 가져오기
|
|
/// </summary>
|
|
/// <param name="questContentId">UGQSummary의 QuestContentId 값으로 api 호출</param>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
[HttpGet]
|
|
[Route("quest/{questContentId}")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(UGQContent))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> getQuest(string questContentId, [FromQuery] string userGuid)
|
|
{
|
|
return await _questEditorApi.getQuest(userGuid, questContentId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 편집 가능한 경우 퀘스트 내용 가져오기
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// GET api와는 다르게 편집 불가능한 state인 경우에는 실패 리턴
|
|
/// </remarks>
|
|
/// <param name="questContentId">UGQSummary의 QuestContentId 값으로 api 호출</param>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
[HttpPost]
|
|
[Route("quest/{questContentId}/edit")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(UGQContent))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> editQuest(string questContentId, [FromQuery] string userGuid)
|
|
{
|
|
return await _questEditorApi.editQuest(userGuid, questContentId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 내용 업데이트
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Task의 DialogId는 업데이트하지 않음.
|
|
/// 편집 불가능 state인 경우 에러 리턴
|
|
/// </remarks>
|
|
/// <param name="questContentId">GET 또는 edit 에서 얻은 questContentId 사용</param>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
/// <param name="saveQuestModel">웹에서 입력한 값</param>
|
|
[HttpPut]
|
|
[Route("quest/{questContentId}")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(UGQContent))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> saveQuest(string questContentId, [FromQuery] string userGuid, [FromBody] UGQSaveQuestModel saveQuestModel)
|
|
{
|
|
return await _questEditorApi.saveQuest(userGuid, questContentId, saveQuestModel);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 삭제
|
|
/// </summary>
|
|
/// <param name="questContentId">GET또는 edit 에서 얻은 questContentId 사용</param>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
[HttpDelete]
|
|
[Route("quest/{questContentId}")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK)]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> deleteQuest(string questContentId, [FromQuery] string userGuid)
|
|
{
|
|
return await _questEditorApi.deleteQuest(userGuid, questContentId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 이미지 업로드
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 세부사항은 정리 예정
|
|
/// </remarks>
|
|
/// <param name="questContentId">GET 또는 edit 에서 얻은 questContentId 사용</param>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
/// <param name="titleImageId">기본 이미지 인덱스</param>
|
|
/// <param name="bannerImageId">기본 이미지 인덱스</param>
|
|
/// <param name="title">업로드 파일</param>
|
|
/// <param name="banner">업로드 파일</param>
|
|
[HttpPost]
|
|
[Route("quest-image/{questContentId}")]
|
|
[Produces("application/json")]
|
|
public async Task<IResult> uploadQuestImage(string questContentId, [FromQuery] string userGuid, [FromQuery] int? titleImageId, [FromQuery] int? bannerImageId, IFormFile? title, IFormFile? banner)
|
|
{
|
|
return await _questEditorApi.uploadQuestImage(userGuid, questContentId, titleImageId ?? 0, bannerImageId ?? 0, title, banner);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 타이틀 이미지 업로드
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 세부사항은 정리 예정
|
|
/// </remarks>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
/// <param name="questContentId">GET 또는 edit 에서 얻은 questContentId 사용</param>
|
|
/// <param name="titleImageId">기본 이미지 인덱스</param>
|
|
/// <param name="title">업로드 파일</param>
|
|
[HttpPost]
|
|
[Route("quest-title-image/{questContentId}")]
|
|
[Produces("application/json")]
|
|
public async Task<IResult> uploadQuestTitleImage(string questContentId, [FromQuery] string userGuid, [FromQuery] int? titleImageId, IFormFile? title)
|
|
{
|
|
return await _questEditorApi.uploadQuestImage(userGuid, questContentId, titleImageId ?? 0, 0, title, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 배너 이미지 업로드
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 세부사항은 정리 예정
|
|
/// </remarks>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
/// <param name="questContentId">GET 또는 edit 에서 얻은 questContentId 사용</param>
|
|
/// <param name="bannerImageId">기본 이미지 인덱스</param>
|
|
/// <param name="banner">업로드 파일</param>
|
|
[HttpPost]
|
|
[Route("quest-banner-image/{questContentId}")]
|
|
[Produces("application/json")]
|
|
public async Task<IResult> uploadQuestBannerImage(string questContentId, [FromQuery] string userGuid, [FromQuery] int? bannerImageId, IFormFile? banner)
|
|
{
|
|
return await _questEditorApi.uploadQuestImage(userGuid, questContentId, 0, bannerImageId ?? 0, null, banner);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 퀘스트 다이얼로그 가져오기
|
|
/// </summary>
|
|
/// <param name="questContentId">GET 또는 edit 에서 얻은 questContentId 사용</param>
|
|
/// <param name="dialogId">UGQContent.Tasks에 있는 DialogId 사용</param>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
[HttpGet]
|
|
[Route("quest-dialog/{questContentId}/{dialogId}")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(UGQDialog))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> getQuestDialog(string questContentId, string dialogId, [FromQuery] string userGuid)
|
|
{
|
|
return await _questEditorApi.getQuestDialog(userGuid, questContentId, dialogId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 다이얼로그 새로 생성
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Dialog 를 추가하고, UGQContent.Tasks의 DialogId를 저장
|
|
/// </remarks>
|
|
/// <param name="questContentId">GET 또는 edit 에서 얻은 questContentId 사용</param>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
/// <param name="taskIndex">몇번째 Task에 추가되는 다이얼로그인지. 0부터 시작</param>
|
|
/// <param name="questDialog">questDialog</param>
|
|
[HttpPost]
|
|
[Route("quest-dialog/{questContentId}")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(UGQAddQuestDialogResponse))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> addQuestDialog(string questContentId, [FromQuery] string userGuid, [FromQuery] int taskIndex, [FromBody] UGQSaveDialogModel questDialog)
|
|
{
|
|
return await _questEditorApi.addQuestDialog(userGuid, questContentId, taskIndex, questDialog);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 다이얼로그 업데이트
|
|
/// </summary>
|
|
/// <param name="questContentId">GET 또는 edit 에서 얻은 questContentId 사용</param>
|
|
/// <param name="dialogId">UGQContent.Tasks에 있는 DialogId 사용</param>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
/// /// <param name="questDialog">questDialog</param>
|
|
[HttpPut]
|
|
[Route("quest-dialog/{questContentId}/{dialogId}")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(UGQDialog))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> saveQuestDialog(string questContentId, string dialogId, [FromQuery] string userGuid, [FromBody] UGQSaveDialogModel questDialog)
|
|
{
|
|
return await _questEditorApi.saveQuestDialog(userGuid, questContentId, dialogId, questDialog);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 state 변경
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Test 로 변경 실패 시 ValidationErrorResponse로 응답
|
|
/// </remarks>
|
|
/// <param name="questContentId">GET또는 edit 에서 얻은 questContentId 사용</param>
|
|
/// <param name="userGuid">유저 Guid</param>
|
|
/// <param name="state">UGQState</param>
|
|
[HttpPatch]
|
|
[Route("quest-state/{questContentId}")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(UGQContent))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ValidationErrorResponse))]
|
|
public async Task<IResult> changeQuestState(string questContentId, [FromQuery] string userGuid, [FromQuery] QuestContentState state)
|
|
{
|
|
string? adminUsername = adminUsernameFromToken();
|
|
if (adminUsername == null)
|
|
return Results.Unauthorized();
|
|
|
|
return await _questEditorApi.changeQuestState(userGuid, questContentId, state, adminUsername);
|
|
}
|
|
|
|
[HttpGet]
|
|
[Route("creator-point-history")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(UGQCreatorPointHistoryResult))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> getCreatorPointHistory([FromQuery] string userGuid, [FromQuery] int pageNumber, [FromQuery] int pageSize, [FromQuery] CreatorPointHistoryKind kind, DateTimeOffset startDate, DateTimeOffset endDate)
|
|
{
|
|
return await _questEditorApi.getCreatorPointHistory(userGuid, pageNumber, pageSize, kind, startDate, endDate);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 모든 퀘스트 보기
|
|
/// </summary>
|
|
[HttpGet]
|
|
[Route("all-quests")]
|
|
[Produces("application/json")]
|
|
public async Task<IResult> getAllQuests([FromQuery] QuestContentState state, [FromQuery] int pageNumber, [FromQuery] int pageSize, [FromQuery] string? searchText)
|
|
{
|
|
pageSize = Math.Clamp(pageSize, 1, MAX_PAGE_SIZE);
|
|
|
|
var result = await _questEditorService.getAllQuests(pageNumber, pageSize, state, searchText);
|
|
|
|
long allCount = await _questEditorService.getAllCount();
|
|
|
|
LangEnum langEnum = Culture.ToLangEnum(CultureInfo.CurrentCulture.Name);
|
|
return Results.Ok(new UQGAllQuestResponse
|
|
{
|
|
TotalCount = allCount,
|
|
PageNumber = result.PageNumber,
|
|
PageSize = result.PageSize,
|
|
TotalPages = result.TotalPages,
|
|
Summaries = result.Items.Select(x => x.ToDTO(langEnum)).ToList()
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 계정의 모든 퀘스트 보기
|
|
/// </summary>
|
|
[HttpGet]
|
|
[Route("account-quest")]
|
|
[Produces("application/json")]
|
|
[SwaggerResponse(StatusCodes.Status200OK, Type = typeof(List<UGQSummary>))]
|
|
[SwaggerResponse(StatusCodes.Status400BadRequest, Type = typeof(ApiErrorResponse))]
|
|
public async Task<IResult> getQuests([FromQuery] int pageNumber, [FromQuery] int pageSize, [FromQuery] string userGuid, [FromQuery] QuestContentState state, [FromQuery] string? searchText)
|
|
{
|
|
pageSize = Math.Clamp(pageSize, 1, MAX_PAGE_SIZE);
|
|
|
|
List<QuestContentEntity> all = await _questEditorService.getAll(userGuid);
|
|
|
|
var result = await _questEditorService.getSummaries(pageNumber, pageSize, userGuid, state, searchText);
|
|
|
|
LangEnum langEnum = Culture.ToLangEnum(CultureInfo.CurrentCulture.Name);
|
|
return Results.Ok(new UGQSummaryResponse
|
|
{
|
|
TotalCount = all.Count,
|
|
PageNumber = result.PageNumber,
|
|
PageSize = result.PageSize,
|
|
TotalPages = result.TotalPages,
|
|
Summaries = result.Items.Select(x => x.ToDTO(langEnum)).ToList(),
|
|
});
|
|
}
|
|
|
|
}
|