initial commit

This commit is contained in:
2026-08-04 14:41:21 +03:00
parent 3cb8fcde60
commit 1a1d6186d8
101 changed files with 23239 additions and 0 deletions

180
Api/RepositoryApi.cs Normal file
View File

@@ -0,0 +1,180 @@
using BitMiracle.LibTiff.Classic;
using Microsoft.AspNetCore.Mvc;
using SkiaSharp;
using System.Buffers.Text;
using Microsoft.Data.SqlClient;
using System.IO;
namespace Library.Api;
[Route( "Api/Repository/[action]/{id?}" )]
public class RepositoryApi : APIController
{
public RepositoryApi( ILogger<UserApi> logger , IConfiguration configuration )
: base( logger , configuration )
{
}
[HttpPost]
[DisableRequestSizeLimit]
public IActionResult UploadCoverImage( int id , List<IFormFile>? file )
{
Trace( "/Api/Repository/UploadCoverImage" );
if ( file == null || file.Count <= 0 )
return Error( "Missing file" );
using SKBitmap? bitmap = PreprocessImage( file[0] );
if ( bitmap == null )
return Error( "Invalid image" );
SqlDataReader reader = PrepareSQL(@"update gnm set uuid = REPLACE(NEWID( ),'-',''),data_format='jpg' OUTPUT INSERTED.uuid WHERE id = @id")
.AddParameter( "@id" , id )
.ExecuteReader( );
if ( !reader.Read( ) )
return Error( "No such book!" );
string? new_uuid = reader.String( 0 );
if ( string.IsNullOrEmpty( new_uuid ) )
return Error( "No such book!" );
string original = GetDataDirectory( ) + new_uuid + ".jpg";
using SKData bitmap_data = bitmap.Encode( SKEncodedImageFormat.Jpeg , 80 );
byte [] bitmap_data_array = bitmap_data.ToArray( );
System.IO.File.WriteAllBytes( original , bitmap_data_array );
return Success( new_uuid );
}
[HttpPost]
[DisableRequestSizeLimit]
public IActionResult UploadPDFAttachment( int id , List<IFormFile>? file )
{
Trace( "/Api/Repository/UploadPDFAttachment" );
if ( file == null || file.Count <= 0 )
return Error( "Missing file" );
byte [] ? pdf_data_array = PreprocessPDF( file[0] );
if ( pdf_data_array == null )
return Error( "Invalid file" );
SqlDataReader reader = PrepareSQL(@"update gnm_rec set uuid = REPLACE(NEWID( ),'-',''),data_format='pdf' OUTPUT INSERTED.uuid WHERE id = @id")
.AddParameter( "@id" , id )
.ExecuteReader( );
if ( !reader.Read( ) )
return Error( "No such attachment!" );
string? new_uuid = reader.String( 0 );
if ( string.IsNullOrEmpty( new_uuid ) )
return Error( "No such attachment!" );
string original = GetDataDirectory( ) + new_uuid + ".pdf";
System.IO.File.WriteAllBytes( original , pdf_data_array );
return Success( new_uuid );
}
[HttpPost]
[DisableRequestSizeLimit]
public IActionResult UploadImageAttachment( int id , List<IFormFile>? file )
{
Trace( "/Api/Repository/UploadImageAttachment" );
if ( file == null || file.Count <= 0 )
return Error( "Missing file" );
using SKBitmap? bitmap = PreprocessImage( file[0] );
if ( bitmap == null )
return Error( "Invalid image" );
SqlDataReader reader = PrepareSQL(@"update gnm_rec set uuid = REPLACE(NEWID( ),'-',''),data_format='jpg' OUTPUT INSERTED.uuid WHERE id = @id")
.AddParameter( "@id" , id )
.ExecuteReader( );
if ( !reader.Read( ) )
return Error( "No such attachment!" );
string? new_uuid = reader.String( 0 );
if ( string.IsNullOrEmpty( new_uuid ) )
return Error( "No such attachment!" );
string original = GetDataDirectory( ) + new_uuid + ".jpg";
using SKData bitmap_data = bitmap.Encode( SKEncodedImageFormat.Jpeg , 80 );
byte [] bitmap_data_array = bitmap_data.ToArray( );
System.IO.File.WriteAllBytes( original , bitmap_data_array );
return Success( new_uuid );
}
private static SKBitmap? PreprocessImage( IFormFile form_file )
{
SKBitmap? bitmap = SKBitmap.Decode( form_file.OpenReadStream( ) );
if ( bitmap == null )
{
bitmap = ConvertTiffToSKBitmap( form_file.OpenReadStream( ) );
if ( bitmap == null )
return null;
}
if ( bitmap!.IsEmpty || bitmap.IsNull || bitmap.Width < 16 || bitmap.Height < 16 )
return null;
return bitmap;
}
private static byte[]? PreprocessPDF( IFormFile form_file )
{
using MemoryStream file_contents = new( );
form_file.CopyTo( file_contents );
byte[] file_bytes = file_contents.ToArray( );
if ( file_bytes.Length < 10 )
return null;
if ( file_bytes[0] != (byte)'%' || file_bytes[1] != (byte)'P' || file_bytes[2] != 'D' || file_bytes[3] != 'F' )
return null;
return file_bytes;
}
public static SKBitmap? ConvertTiffToSKBitmap( Stream tifImage )
{
SKColor[] pixels;
int width, height;
// open a Tiff stored in the memory stream, and grab its pixels
using ( Tiff tifImg = Tiff.ClientOpen( "in-memory" , "r" , tifImage , new TiffStream( ) ) )
{
FieldValue[] value = tifImg.GetField(TiffTag.IMAGEWIDTH);
width = value[0].ToInt( );
value = tifImg.GetField( TiffTag.IMAGELENGTH );
height = value[0].ToInt( );
// Read the image into the memory buffer
int[] raster = new int[width * height];
if ( !tifImg.ReadRGBAImageOriented( width , height , raster , Orientation.TOPLEFT ) )
{
// Not a valid TIF image.
}
// store the pixels
pixels = new SKColor[width * height];
for ( int y = 0 ; y < height ; y++ )
{
for ( int x = 0 ; x < width ; x++ )
{
int arrayOffset = y * width + x;
int rgba = raster[arrayOffset];
pixels[arrayOffset] = new SKColor( (byte)Tiff.GetR( rgba ) , (byte)Tiff.GetG( rgba ) , (byte)Tiff.GetB( rgba ) , (byte)Tiff.GetA( rgba ) );
}
}
}
return new SKBitmap( width , height ) {
Pixels = pixels
};
}
}

276
Api/UploadApi.cs Normal file
View File

@@ -0,0 +1,276 @@
using BitMiracle.LibTiff.Classic;
using Microsoft.AspNetCore.Mvc;
using SkiaSharp;
using Microsoft.Data.SqlClient;
namespace Library.Api;
[Route( "Api/Upload/[action]/{id?}" )]
public class UploadApi : APIController
{
private readonly string m_TempDirectory;
public UploadApi( ILogger<UserApi> logger , IConfiguration configuration )
: base( logger , configuration )
{
m_TempDirectory = configuration.GetValue<string>( "TempDirectory" ) ?? string.Empty;
}
[HttpPost]
public IActionResult StartUpload( )
{
Trace( "/Api/Repository/StartUpload" );
string session = Guid.NewGuid( ).ToString( ).Replace( "-" , null );
using FileStream stream = new( m_TempDirectory + session! , FileMode.CreateNew , FileAccess.Write , FileShare.None );
return Success( session! );
}
[HttpPost]
public IActionResult UploadChunk( string? session , string? payload , long offset )
{
if ( session == null )
return Error( "Invalid call. (session)" );
if ( !ValidateOffset( session , offset ) )
return Error( "Invalid call. (Bad offset)" );
byte[]? bytes = Base64DecodeSafe( payload );
if ( bytes == null )
return Error( "Invalid call. (Bad payload)" );
using FileStream stream = new( m_TempDirectory + session! , FileMode.Append , FileAccess.Write , FileShare.None );
stream.Write( bytes , 0 , bytes.Length );
return Success( "OK" );
}
private static byte[]? PreprocessMP4( string form_file )
{
byte[] file_bytes = System.IO.File.ReadAllBytes( form_file );
if ( file_bytes.Length < 100 )
return null;
return file_bytes;
}
[HttpPost]
public IActionResult SaveMP4Attachment( string? session , long offset , int id )
{
if ( session == null )
return Error( "Invalid call. (Invalid parameters)" );
/* if ( !ValidateOffset( session , offset ) )
return Error( "Invalid call. (Bad offset)" );
*/
byte [] ? pdf_data_array = PreprocessMP4( m_TempDirectory + session! );
if ( pdf_data_array == null )
return Error( "Invalid file" );
SqlDataReader reader = PrepareSQL(@"update gnm_rec set uuid = REPLACE(NEWID( ),'-',''),data_format='mp4' OUTPUT INSERTED.uuid WHERE id = @id")
.AddParameter( "@id" , id )
.ExecuteReader( );
if ( !reader.Read( ) )
return Error( "No such attachment!" );
string? new_uuid = reader.String( 0 );
if ( string.IsNullOrEmpty( new_uuid ) )
return Error( "No such attachment!" );
string original = GetDataDirectory( ) + new_uuid + ".mp4";
System.IO.File.WriteAllBytes( original , pdf_data_array );
return Success( new_uuid );
}
[HttpPost]
public IActionResult SaveCoverImage( string? session , long offset , int id )
{
if ( session == null )
return Error( "Invalid call. (Invalid parameters)" );
if ( !ValidateOffset( session , offset ) )
return Error( "Invalid call. (Bad offset)" );
using SKBitmap? bitmap = PreprocessImage( m_TempDirectory + session! );
if ( bitmap == null )
return Error( "Invalid image" );
SqlDataReader reader = PrepareSQL(@"update gnm set uuid = REPLACE(NEWID( ),'-',''),data_format='jpg' OUTPUT INSERTED.uuid WHERE id = @id")
.AddParameter( "@id" , id )
.ExecuteReader( );
if ( !reader.Read( ) )
return Error( "No such book!" );
string? new_uuid = reader.String( 0 );
if ( string.IsNullOrEmpty( new_uuid ) )
return Error( "No such book!" );
string original = GetDataDirectory( ) + new_uuid + ".jpg";
using SKData bitmap_data = bitmap.Encode( SKEncodedImageFormat.Jpeg , 80 );
byte [] bitmap_data_array = bitmap_data.ToArray( );
System.IO.File.WriteAllBytes( original , bitmap_data_array );
return Success( new_uuid );
}
[HttpPost]
public IActionResult SavePDFAttachment( string? session , long offset , int id )
{
if ( session == null )
return Error( "Invalid call. (Invalid parameters)" );
if ( !ValidateOffset( session , offset ) )
return Error( "Invalid call. (Bad offset)" );
byte [] ? pdf_data_array = PreprocessPDF( m_TempDirectory + session! );
if ( pdf_data_array == null )
return Error( "Invalid file" );
SqlDataReader reader = PrepareSQL(@"update gnm_rec set uuid = REPLACE(NEWID( ),'-',''),data_format='pdf' OUTPUT INSERTED.uuid WHERE id = @id")
.AddParameter( "@id" , id )
.ExecuteReader( );
if ( !reader.Read( ) )
return Error( "No such attachment!" );
string? new_uuid = reader.String( 0 );
if ( string.IsNullOrEmpty( new_uuid ) )
return Error( "No such attachment!" );
string original = GetDataDirectory( ) + new_uuid + ".pdf";
System.IO.File.WriteAllBytes( original , pdf_data_array );
return Success( new_uuid );
}
[HttpPost]
public IActionResult SaveImageAttachment( string? session , long offset , int id )
{
if ( session == null )
return Error( "Invalid call. (Invalid parameters)" );
if ( !ValidateOffset( session , offset ) )
return Error( "Invalid call. (Bad offset)" );
using SKBitmap? bitmap = PreprocessImage( m_TempDirectory + session! );
if ( bitmap == null )
return Error( "Invalid image" );
SqlDataReader reader = PrepareSQL(@"update gnm_rec set uuid = REPLACE(NEWID( ),'-',''),data_format='jpg' OUTPUT INSERTED.uuid WHERE id = @id")
.AddParameter( "@id" , id )
.ExecuteReader( );
if ( !reader.Read( ) )
return Error( "No such attachment!" );
string? new_uuid = reader.String( 0 );
if ( string.IsNullOrEmpty( new_uuid ) )
return Error( "No such attachment!" );
string original = GetDataDirectory( ) + new_uuid + ".jpg";
using SKData bitmap_data = bitmap.Encode( SKEncodedImageFormat.Jpeg , 80 );
byte [] bitmap_data_array = bitmap_data.ToArray( );
System.IO.File.WriteAllBytes( original , bitmap_data_array );
return Success( new_uuid );
}
private static byte[]? Base64DecodeSafe( string? b )
{
if ( b == null )
return null;
try
{
return Convert.FromBase64String( b! );
}
catch ( Exception )
{
}
return null;
}
private bool ValidateOffset( string session , long expected )
{
try
{
FileInfo fi = new( m_TempDirectory + session );
return fi.Length == expected;
}
catch ( Exception )
{
}
return false;
}
private static SKBitmap? PreprocessImage( string local_file )
{
SKBitmap? bitmap = SKBitmap.Decode( local_file );
if ( bitmap == null )
{
bitmap = ConvertTiffToSKBitmap( local_file );
if ( bitmap == null )
return null;
}
if ( bitmap!.IsEmpty || bitmap.IsNull || bitmap.Width < 16 || bitmap.Height < 16 )
return null;
return bitmap;
}
private static SKBitmap? ConvertTiffToSKBitmap( string local_file )
{
SKColor[] pixels;
int width, height;
// open a Tiff stored in the memory stream, and grab its pixels
using ( Tiff tifImg = Tiff.ClientOpen( local_file , "r" , null , new TiffStream( ) ) )
{
FieldValue[] value = tifImg.GetField(TiffTag.IMAGEWIDTH);
width = value[0].ToInt( );
value = tifImg.GetField( TiffTag.IMAGELENGTH );
height = value[0].ToInt( );
// Read the image into the memory buffer
int[] raster = new int[width * height];
if ( !tifImg.ReadRGBAImageOriented( width , height , raster , Orientation.TOPLEFT ) )
{
// Not a valid TIF image.
}
// store the pixels
pixels = new SKColor[width * height];
for ( int y = 0 ; y < height ; y++ )
{
for ( int x = 0 ; x < width ; x++ )
{
int arrayOffset = y * width + x;
int rgba = raster[arrayOffset];
pixels[arrayOffset] = new SKColor( (byte)Tiff.GetR( rgba ) , (byte)Tiff.GetG( rgba ) , (byte)Tiff.GetB( rgba ) , (byte)Tiff.GetA( rgba ) );
}
}
}
return new SKBitmap( width , height )
{
Pixels = pixels
};
}
private static byte[]? PreprocessPDF( string form_file )
{
byte[] file_bytes = System.IO.File.ReadAllBytes( form_file );
if ( file_bytes.Length < 10 )
return null;
if ( file_bytes[0] != (byte)'%' || file_bytes[1] != (byte)'P' || file_bytes[2] != 'D' || file_bytes[3] != 'F' )
return null;
return file_bytes;
}
}

178
Api/UserApi.cs Normal file
View File

@@ -0,0 +1,178 @@
using Microsoft.AspNetCore.Mvc;
namespace Library.Api;
[Route( "Api/User/[action]/{id?}" )]
public class UserApi : APIController
{
public UserApi( ILogger<UserApi> logger , IConfiguration configuration )
: base( logger , configuration )
{
}
[HttpPost]
public IActionResult Login( string username , string password )
{
Trace( "/UserAPI/Login" );
string? session_id = PrepareSQL( "EXECUTE [usp_user_login] @user , @pass" )
.AddParameter( "@user" , username )
.AddParameter( "@pass" , password )
.ReadSingleString( );
if ( string.IsNullOrWhiteSpace( session_id ) )
return Error( "Невалидно потребителско име/парола" );
SessionStart( session_id );
return Success( session_id );
}
[HttpPost]
public IActionResult EditDetails( int id , string? name , string? email )
{
Trace( "/UserAPI/EditDetails" );
AssertID( id );
AssertParameter( name , 2 );
AssertEmail( email , false );
AssertLogin( null );
if ( id != GetUserData( )!.ID && !GetUserData( )!.IsAdmin )
return Error( "Access denied" );
if ( email == null )
{
PrepareSQL( "UPDATE [dom] SET [ime]=@name WHERE id=@id" )
.AddParameter( "@name" , name )
.AddParameter( "@id" , id )
.ExecuteNonQuery( );
}
else
{
PrepareSQL( "UPDATE [dom] SET [ime]=@name,[mail]=@email WHERE id=@id" )
.AddParameter( "@name" , name )
.AddParameter( "@email" , email )
.AddParameter( "@id" , id )
.ExecuteNonQuery( );
}
return Success( );
}
[HttpPost]
public IActionResult EditPassword( int id , string? password )
{
Trace( "/UserAPI/EditPassword" );
AssertID( id );
AssertParameter( password , 5 );
AssertLogin( null );
if ( id != GetUserData( )!.ID && !GetUserData( )!.IsAdmin )
return Error( "Access denied" );
PrepareSQL( "UPDATE [dom] SET [prl] = @new_pass WHERE id=@id" )
.AddParameter( "@new_pass" , password )
.AddParameter( "@id" , id )
.ExecuteNonQuery( );
return Success( );
}
[HttpGet]
public IActionResult Activate( int id )
{
Trace( "/UserAPI/Activate" );
AssertID( id );
AssertAdmin( );
PrepareSQL( "UPDATE [dom] SET [is_active]=1 WHERE id=@id" )
.AddParameter( "@id" , id )
.ExecuteNonQuery( );
return Success( );
}
[HttpGet]
public IActionResult Deactivate( int id )
{
Trace( "/UserAPI/Deactivate" );
AssertID( id );
AssertAdmin( );
if ( id == GetUserData( )!.ID )
return Error( "Не може да деактивирате себе си!" );
PrepareSQL( "UPDATE [dom] SET [is_active]=0 WHERE id=@id" )
.AddParameter( "@id" , id )
.ExecuteNonQuery( );
return Success( );
}
[HttpPost]
public IActionResult Register( string? username , string? password , string? name )
{
Trace( "/UserAPI/Register" );
AssertEmail( username , true );
AssertParameter( password , 5 );
AssertParameter( name , 2 );
string? new_user_id = PrepareSQL( "INSERT INTO [dom] ([mail],[prl],[ime]) OUTPUT INSERTED.id VALUES (@user,@pass,@name)" )
.AddParameter( "@user" , username )
.AddParameter( "@pass" , password )
.AddParameter( "@name" , name )
.ReadSingleString( );
if ( new_user_id == null )
return Error( "Емайл адреса вече е регистриран" );
string? session_id = PrepareSQL( "EXECUTE [usp_user_login] @user , @pass" )
.AddParameter( "@user" , username )
.AddParameter( "@pass" , password )
.ReadSingleString( );
if ( session_id == null )
return Error( "Емайл адреса вече е регистриран" );
SessionStart( session_id );
return Success( session_id );
}
[HttpPost]
public IActionResult Forgot( string ? username )
{
Trace( "/UserAPI/Forgot" );
AssertEmail( username , true );
string? password = PrepareSQL( "SELECT [prl] FROM [dom] WHERE [mail]=@user" )
.AddParameter( "@user" , username )
.ReadSingleString( );
if ( string.IsNullOrWhiteSpace( password ) )
return Error( "Невалидно потребителско име" );
return Error( "Тук се очаква да се изпрати код за ресет на мейла. Засега ето това е паролата: " + password );
}
[HttpGet]
public IActionResult Logout( )
{
Trace( "/UserAPI/Logout" );
if ( GetUserData( ) != null )
{
PrepareSQL( "EXECUTE [usp_user_logout] @session_id" )
.AddParameter( "@session_id" , GetUserData( )!.SessionID )
.ExecuteNonQuery( );
}
SessionCancel( );
return Success( "1" );
}
}