using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using System.Globalization;
using System.IO;
using System.Text;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using AyaNova.Models;
using AyaNova.Api.ControllerHelpers;
using AyaNova.Util;
using AyaNova.Biz;
namespace AyaNova.Api.Controllers
{
///
/// Import AyaNova 7 data controller
///
[ApiController]
[ApiVersion("8.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[Produces("application/json")]
[Authorize]
public class ImportAyaNova7Controller : ControllerBase
{
private readonly AyContext ct;
private readonly ILogger log;
private readonly ApiServerState serverState;
///
///
///
///
///
///
public ImportAyaNova7Controller(AyContext dbcontext, ILogger logger, ApiServerState apiServerState)
{
ct = dbcontext;
log = logger;
serverState = apiServerState;
}
///
/// Upload AyaNova 7 import file
///
/// NameValue list of filenames and id's
[HttpPost]
[DisableFormValueModelBinding]
[RequestSizeLimit(10737418241)]//10737418240 = 10gb https://github.com/aspnet/Announcements/issues/267
public async Task Upload()
{
//Open or opsOnly and user is opsadminfull
if (!serverState.IsOpenOrOpsOnly || (serverState.IsOpsOnly && !Authorized.HasAnyRole(HttpContext.Items, AuthorizationRoles.OpsAdminFull)))
{
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
}
if (!Authorized.HasCreateRole(HttpContext.Items, AyaType.AyaNova7Import))
{
return StatusCode(403, new ApiNotAuthorizedResponse());
}
var returnList = new List();
try
{
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
{
return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, "FileUploadAttempt", $"Expected a multipart request, but got {Request.ContentType}"));
}
var uploadFormData = await ApiUploadProcessor.ProcessUtilityFileUpload(HttpContext);
bool badRequest = false;
string errorMessage = string.Empty;
//are these the right files?
if (uploadFormData.UploadedFiles.Count > 0)
{
foreach (UploadedFileInfo a in uploadFormData.UploadedFiles)
{
//should look like this: ayanova.data.dump.2018-04-2--12-30-57.zip
string lwr = a.OriginalFileName.ToLowerInvariant();
if (!(lwr.StartsWith("ayanova.data.dump") && lwr.EndsWith(".zip")))
{
badRequest = true;
errorMessage = $"File uploaded \"{lwr}\" does not appear to be an AyaNova 7 data dump file. The name should start with \"ayanova.data.dump\" have a date in the middle and end with \".zip\". Upload process is terminated without saving.";
}
}
}
if (badRequest)
{
//delete temp files
if (uploadFormData.UploadedFiles.Count > 0)
{
foreach (UploadedFileInfo a in uploadFormData.UploadedFiles)
{
System.IO.File.Delete(a.InitialUploadedPathName);
}
}
//return bad request
return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_INVALID_VALUE, null, errorMessage));
}
//We have our files and a confirmed AyObject, ready to attach and save permanently
if (uploadFormData.UploadedFiles.Count > 0)
{
foreach (UploadedFileInfo a in uploadFormData.UploadedFiles)
{
returnList.Add(a.OriginalFileName);
}
}
}
catch (InvalidDataException ex)
{
return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, "FileUploadAttempt", ex.Message));
}
//Return the list of attachment ids and filenames
return Ok(ApiOkResponse.Response(returnList, true));
}
///
/// Delete import file
///
///
/// Ok
[HttpDelete("{filename}")]
public ActionResult Delete([FromRoute] string filename)
{
//Open or opsOnly and user is opsadminfull
if (!serverState.IsOpenOrOpsOnly || (serverState.IsOpsOnly && !Authorized.HasAnyRole(HttpContext.Items, AuthorizationRoles.OpsAdminFull)))
{
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
}
if (!ModelState.IsValid)
{
return BadRequest(new ApiErrorResponse(ModelState));
}
if (!Authorized.HasDeleteRole(HttpContext.Items, AyaType.AyaNova7Import))
{
return StatusCode(403, new ApiNotAuthorizedResponse());
}
//do the delete
//this handles removing the file if there are no efs left and also the db record for the attachment
FileUtil.DeleteUtilityFile(filename);
return NoContent();
}
///
/// Get AyaNova 7 data dump uploaded files list
///
/// List of uploaded data dump files
[HttpGet]
public ActionResult List()
{
//Open or opsOnly and user is opsadminfull
if (!serverState.IsOpenOrOpsOnly || (serverState.IsOpsOnly && !Authorized.HasAnyRole(HttpContext.Items, AuthorizationRoles.OpsAdminFull)))
{
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
}
if (!Authorized.HasReadFullRole(HttpContext.Items, AyaType.AyaNova7Import))
{
return StatusCode(403, new ApiNotAuthorizedResponse());
}
if (!ModelState.IsValid)
{
return BadRequest(new ApiErrorResponse(ModelState));
}
//dump file name example: ayanova.data.dump.XXX.zip
List l = FileUtil.UtilityFileList("ayanova.data.dump.*.zip");
return Ok(ApiOkResponse.Response(l, true));
}
///
/// *ERASE DATABASE and start import of previously uploaded import file
/// **This will permanently erase all current data in database without further warning as the first step in the import process**
///
///
/// Ok
[HttpPost("EraseDatabaseAndStartImport/{filename}")]
public ActionResult EraseDatabaseAndStartImport([FromRoute] string filename)
{
//Open or opsOnly and user is opsadminfull
if (!serverState.IsOpenOrOpsOnly || (serverState.IsOpsOnly && !Authorized.HasAnyRole(HttpContext.Items, AuthorizationRoles.OpsAdminFull)))
{
return StatusCode(503, new ApiErrorResponse(ApiErrorCode.API_CLOSED, null, serverState.Reason));
}
if (!ModelState.IsValid)
{
return BadRequest(new ApiErrorResponse(ModelState));
}
//UPDATE: I think it should be ok so commenting this out for now pending something coming up in testing
// //LOOKAT: I decided not to allow trial to import v7 data.
// //This was a snap decision, I didn't think about it much other than
// //I'm concerned right now as of April 17 2018 during development that
// //a trial user will import their old AyaNova data and then ... well somehow continue to use it I guess,
// //maybe it's a non-issue as a trial will only work so long anyway
// #if (!DEBUG)
// if (AyaNova.Core.License.LicenseIsTrial)
// {
// return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, null, "Current license is a trial license key. Only a licensed database can be used with import."));
// }
// #endif
//Create, in that they are creating new data in AyaNova
if (!Authorized.HasCreateRole(HttpContext.Items, AyaType.AyaNova7Import))
{
return StatusCode(403, new ApiNotAuthorizedResponse());
}
//does the file even exist?
if (!FileUtil.UtilityFileExists(filename))
{
return NotFound(new ApiErrorResponse(ApiErrorCode.NOT_FOUND, "filename", "File not found, ensure the name via the GET route endpoint list of previously uploaded import files"));
}
//Create the job here
dynamic jobInfo = new JObject();
jobInfo.ImportFileName = filename;
OpsJob j = new OpsJob();
j.Name = $"Import AyaNova7 data (import file \"{filename}\"";
j.JobType = JobType.ImportV7Data;
//j.O wnerId = UserIdFromContext.Id(HttpContext.Items);
j.JobInfo = jobInfo.ToString();
JobsBiz.AddJob(j, ct);
return Accepted(new { JobId = j.GId });//202 accepted
}
////////////////////////////////////////////////////////////////////////////////////
}//eoc
}//eons