initial commit
This commit is contained in:
41
App_Code/ContextExtensions.cs
Normal file
41
App_Code/ContextExtensions.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace Library;
|
||||
public static class ContextExtensions
|
||||
{
|
||||
public static void SetUserID( this HttpContext context , int id )
|
||||
{
|
||||
context.Items.Add( "CONTEXT_USER_ID" , id );
|
||||
}
|
||||
|
||||
public static int GetUserID( this HttpContext context )
|
||||
{
|
||||
if ( !context.Items.TryGetValue( "CONTEXT_USER_ID" , out object? value ) )
|
||||
return 0;
|
||||
|
||||
if ( value == null )
|
||||
return 0;
|
||||
|
||||
if ( value is int v )
|
||||
return v;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void SetSystemAdmin( this HttpContext context , bool is_admin )
|
||||
{
|
||||
context.Items.Add( "CONTEXT_IS_ADMIN" , is_admin );
|
||||
}
|
||||
|
||||
public static bool IsSystemAdmin( this HttpContext context )
|
||||
{
|
||||
if ( !context.Items.TryGetValue( "CONTEXT_IS_ADMIN" , out object? value ) )
|
||||
return false;
|
||||
|
||||
if ( value == null )
|
||||
return false;
|
||||
|
||||
if ( value is bool v )
|
||||
return v;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
94
App_Code/Controller/APIController.cs
Normal file
94
App_Code/Controller/APIController.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Library;
|
||||
|
||||
public class APIController : AbstractController
|
||||
{
|
||||
protected APIController( ILogger logger , IConfiguration configuration )
|
||||
: base( logger , configuration )
|
||||
{
|
||||
}
|
||||
|
||||
protected void AssertID( int value )
|
||||
{
|
||||
if ( value <= 0 )
|
||||
throw new APIErrorException( "Invalid id parameter" );
|
||||
}
|
||||
|
||||
protected void AssertParameter( int value , int min_value )
|
||||
{
|
||||
if ( value < min_value )
|
||||
throw new APIErrorException( "Invalid int parameter" );
|
||||
}
|
||||
|
||||
protected void AssertParameter( string? value , int min_length )
|
||||
{
|
||||
if ( !ValidateString( value , min_length ) )
|
||||
throw new APIErrorException( "Invalid string parameter" );
|
||||
}
|
||||
|
||||
protected void AssertURL( string? value , bool mandatory )
|
||||
{
|
||||
if ( !ValidateURL( value , mandatory ) )
|
||||
throw new APIErrorException( "Invalid url parameter" );
|
||||
}
|
||||
|
||||
protected void AssertEmail( string? value , bool mandatory )
|
||||
{
|
||||
if ( !ValidateEmail( value , mandatory ) )
|
||||
throw new APIErrorException( "Invalid email parameter" );
|
||||
}
|
||||
|
||||
protected override void OnInvalidLogin( )
|
||||
{
|
||||
throw new APIErrorException( "Access denied." );
|
||||
}
|
||||
|
||||
protected override void OnInvalidAdminLogin( )
|
||||
{
|
||||
throw new APIErrorException( "Access denied (admin)." );
|
||||
}
|
||||
|
||||
protected ContentResult Error( string message )
|
||||
{
|
||||
using MemoryStream stream = new( );
|
||||
|
||||
using Utf8JsonWriter writer = new( stream );
|
||||
writer.WriteStartObject( );
|
||||
writer.WriteBoolean( "Success" , false );
|
||||
writer.WriteString( "ErrorMessage" , message );
|
||||
writer.WriteEndObject( );
|
||||
writer.Dispose( );
|
||||
|
||||
return new ContentResult( )
|
||||
{
|
||||
ContentType = System.Net.Mime.MediaTypeNames.Application.Json ,
|
||||
Content = Encoding.UTF8.GetString( stream.ToArray( ) )
|
||||
};
|
||||
}
|
||||
|
||||
protected ContentResult Success( )
|
||||
{
|
||||
return Success( "true" );
|
||||
}
|
||||
|
||||
protected ContentResult Success( string data )
|
||||
{
|
||||
using MemoryStream stream = new( );
|
||||
|
||||
using Utf8JsonWriter writer = new( stream );
|
||||
writer.WriteStartObject( );
|
||||
writer.WriteBoolean( "Success" , true );
|
||||
writer.WriteString( "Result" , data );
|
||||
writer.WriteEndObject( );
|
||||
writer.Dispose( );
|
||||
|
||||
return new ContentResult( )
|
||||
{
|
||||
ContentType = System.Net.Mime.MediaTypeNames.Application.Json ,
|
||||
Content = Encoding.UTF8.GetString( stream.ToArray( ) )
|
||||
};
|
||||
}
|
||||
}
|
||||
202
App_Code/Controller/AbstractController.cs
Normal file
202
App_Code/Controller/AbstractController.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Library;
|
||||
|
||||
public abstract class AbstractController : Controller
|
||||
{
|
||||
private const string SESSION_COOKIE_NAME = "X-VTU";
|
||||
|
||||
private readonly ILogger m_Logger;
|
||||
private readonly IConfiguration m_Configuration;
|
||||
private readonly string m_DataDirectory = string.Empty;
|
||||
|
||||
protected AbstractController( ILogger logger , IConfiguration configuration )
|
||||
{
|
||||
m_Logger = logger;
|
||||
m_Configuration = configuration;
|
||||
m_DataDirectory = configuration.GetValue<string>( "DataDirectory" ) ?? string.Empty;
|
||||
}
|
||||
|
||||
protected string GetDataDirectory( )
|
||||
{
|
||||
return m_DataDirectory;
|
||||
}
|
||||
|
||||
protected void Trace( string function )
|
||||
{
|
||||
#pragma warning disable CA2254 // Template should be a static expression
|
||||
m_Logger.Log( LogLevel.Trace , function + " called" );
|
||||
#pragma warning restore CA2254 // Template should be a static expression
|
||||
}
|
||||
|
||||
private SqlConnection? m_DBConnection = null;
|
||||
protected SqlConnection GetDBConnection( )
|
||||
{
|
||||
if ( m_DBConnection == null )
|
||||
{
|
||||
try
|
||||
{
|
||||
m_DBConnection = new SqlConnection( m_Configuration.GetValue<string>( "ConnectionString" ) );
|
||||
m_DBConnection.Open( );
|
||||
HttpContext.Response.RegisterForDispose( m_DBConnection );
|
||||
}
|
||||
catch ( SqlException )
|
||||
{
|
||||
if ( m_DBConnection != null )
|
||||
{
|
||||
m_DBConnection.Dispose( );
|
||||
m_DBConnection = null;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return m_DBConnection;
|
||||
}
|
||||
|
||||
protected void SessionStart( string session_id )
|
||||
{
|
||||
CookieOptions cookieOptions = new( )
|
||||
{
|
||||
Secure = false, // only when HTTPS
|
||||
HttpOnly = true,
|
||||
IsEssential = true,
|
||||
};
|
||||
Response.Cookies.Append( SESSION_COOKIE_NAME , session_id , cookieOptions );
|
||||
}
|
||||
|
||||
protected void SessionCancel( )
|
||||
{
|
||||
Response.Cookies.Delete( SESSION_COOKIE_NAME );
|
||||
}
|
||||
|
||||
protected string? GetSessionKey( )
|
||||
{
|
||||
if ( !Request.Cookies.TryGetValue( SESSION_COOKIE_NAME , out string? session_id ) || string.IsNullOrEmpty( session_id ) )
|
||||
return null;
|
||||
return session_id;
|
||||
}
|
||||
|
||||
private UserData? m_CurrentUser = null;
|
||||
private bool m_bUserValidated = false;
|
||||
protected UserData? GetUserData( )
|
||||
{
|
||||
if ( m_bUserValidated )
|
||||
return m_CurrentUser;
|
||||
|
||||
m_bUserValidated = true;
|
||||
|
||||
if ( m_CurrentUser != null )
|
||||
return m_CurrentUser;
|
||||
|
||||
string? session_id = GetSessionKey( );
|
||||
if ( session_id == null )
|
||||
return null;
|
||||
|
||||
m_CurrentUser = UserData.FromSession( GetDBConnection( ) , session_id! );
|
||||
if ( m_CurrentUser == null )
|
||||
return null;
|
||||
|
||||
HttpContext.SetUserID( m_CurrentUser!.ID );
|
||||
HttpContext.Items.Add( "CONTEXT_IS_ADMIN" , m_CurrentUser?.IsAdmin ?? false );
|
||||
|
||||
return m_CurrentUser;
|
||||
}
|
||||
|
||||
protected SQLBuilder PrepareSQL( string query , string? order_by = null )
|
||||
{
|
||||
return new SQLBuilder( GetDBConnection( ) , query , order_by );
|
||||
}
|
||||
|
||||
protected void AssertLogin( string? id )
|
||||
{
|
||||
string? session_id = GetSessionKey( );
|
||||
if ( session_id != null )
|
||||
{
|
||||
string? sql =
|
||||
@"select rec.idgnm, gnm.idlis1, lis.ime, c.*
|
||||
from gnm_rec rec
|
||||
left join gnm on gnm.id = rec.idgnm
|
||||
left join lis on lis.id = gnm.idlis1
|
||||
left join tbl_cross c on
|
||||
c.id1 = (select top 1 iddom from livelog where id_session = @session_id)
|
||||
and c.id2 = gnm.idlis1
|
||||
where rec.uuid = @id
|
||||
and c.id is not null";
|
||||
SqlDataReader reader_x = PrepareSQL( sql )
|
||||
.AddParameter( "@id" , id )
|
||||
.AddParameter( "@session_id" , session_id )
|
||||
.ExecuteReader( );
|
||||
bool res_x = reader_x.Read( );
|
||||
reader_x.Close( );
|
||||
|
||||
if ( res_x == false )
|
||||
OnInvalidLogin( );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( id == null )
|
||||
{
|
||||
if ( GetUserData( ) == null )
|
||||
OnInvalidLogin( );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( GetUserData( ) != null )
|
||||
return;
|
||||
|
||||
SqlDataReader reader = PrepareSQL( @"SELECT gnm.access FROM gnm_rec left join gnm on gnm.id = gnm_rec.idgnm WHERE gnm.access is not null and gnm_rec.uuid = @uuid and gnm_rec.data_format = 'pdf'" )
|
||||
.AddParameter( "@uuid" , id )
|
||||
.ExecuteReader( );
|
||||
bool res = reader.Read( );
|
||||
reader.Close( );
|
||||
if ( res == true )
|
||||
OnInvalidLogin( );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void AssertAdmin( )
|
||||
{
|
||||
if ( GetUserData( ) == null || GetUserData( )!.IsAdmin == false )
|
||||
OnInvalidLogin( );
|
||||
}
|
||||
|
||||
protected abstract void OnInvalidLogin( );
|
||||
protected abstract void OnInvalidAdminLogin( );
|
||||
|
||||
protected bool ValidateString( string? parameter , int min_length )
|
||||
{
|
||||
int length = parameter?.Length ?? 0;
|
||||
return length >= min_length;
|
||||
}
|
||||
|
||||
private const string EMAIL_REGEX = @"^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$";
|
||||
protected bool ValidateEmail( string? email , bool required )
|
||||
{
|
||||
return ValidateRegex( EMAIL_REGEX , email , required );
|
||||
}
|
||||
|
||||
private const string URL_REGEX = @"(?i)(http(s)?:\/\/)?(\w{2,25}\.)+\w{3}([a-z0-9\-?=$-_.+!*()]+)(?i)";
|
||||
protected bool ValidateURL( string? email , bool required )
|
||||
{
|
||||
return ValidateRegex( URL_REGEX , email , required );
|
||||
}
|
||||
|
||||
protected bool ValidateRegex( string regex , string? value , bool is_required )
|
||||
{
|
||||
if ( value == null )
|
||||
return is_required == false;
|
||||
|
||||
try
|
||||
{
|
||||
return Regex.IsMatch( value! , regex , RegexOptions.IgnoreCase , TimeSpan.FromMilliseconds( 250 ) );
|
||||
}
|
||||
catch ( RegexMatchTimeoutException )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
App_Code/Controller/PageController.cs
Normal file
43
App_Code/Controller/PageController.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Library.Models;
|
||||
|
||||
namespace Library;
|
||||
|
||||
public class PageController : AbstractController
|
||||
{
|
||||
protected PageController( ILogger logger , IConfiguration configuration )
|
||||
: base( logger , configuration )
|
||||
{
|
||||
}
|
||||
|
||||
protected IActionResult View( BasePageModel page_model )
|
||||
{
|
||||
page_model.UserData = GetUserData( );
|
||||
return base.View( page_model );
|
||||
}
|
||||
|
||||
protected IActionResult View( string view_name , BasePageModel page_model)
|
||||
{
|
||||
page_model.UserData = GetUserData( );
|
||||
return base.View( view_name , page_model );
|
||||
}
|
||||
|
||||
protected override void OnInvalidLogin( )
|
||||
{
|
||||
throw new ErrorException( "Access denied." );
|
||||
}
|
||||
|
||||
protected override void OnInvalidAdminLogin( )
|
||||
{
|
||||
throw new ErrorException( "Access denied." );
|
||||
}
|
||||
|
||||
protected IActionResult RawText( string text )
|
||||
{
|
||||
return new ContentResult( )
|
||||
{
|
||||
ContentType = System.Net.Mime.MediaTypeNames.Text.Plain ,
|
||||
Content = text
|
||||
};
|
||||
}
|
||||
}
|
||||
16
App_Code/Exceptions/APIErrorException.cs
Normal file
16
App_Code/Exceptions/APIErrorException.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Library;
|
||||
|
||||
public class APIErrorException : Exception
|
||||
{
|
||||
private readonly string m_ErrorMessage;
|
||||
|
||||
public APIErrorException( string message )
|
||||
{
|
||||
m_ErrorMessage = message;
|
||||
}
|
||||
|
||||
public string ErrorMessage
|
||||
{
|
||||
get { return m_ErrorMessage; }
|
||||
}
|
||||
}
|
||||
16
App_Code/Exceptions/ErrorException.cs
Normal file
16
App_Code/Exceptions/ErrorException.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Library;
|
||||
|
||||
public class ErrorException : Exception
|
||||
{
|
||||
private readonly string m_ErrorMessage;
|
||||
|
||||
public ErrorException( string message )
|
||||
{
|
||||
m_ErrorMessage = message;
|
||||
}
|
||||
|
||||
public string ErrorMessage
|
||||
{
|
||||
get { return m_ErrorMessage; }
|
||||
}
|
||||
}
|
||||
72
App_Code/Exceptions/ExceptionMiddleware.cs
Normal file
72
App_Code/Exceptions/ExceptionMiddleware.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Library;
|
||||
|
||||
public class ExceptionMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public ExceptionMiddleware( RequestDelegate next )
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync( HttpContext httpContext )
|
||||
{
|
||||
try
|
||||
{
|
||||
await _next( httpContext );
|
||||
}
|
||||
catch ( RedirectException exception )
|
||||
{
|
||||
HandleExceptionAsync( httpContext , exception );
|
||||
}
|
||||
catch ( ErrorException exception )
|
||||
{
|
||||
await HandleErrorAsync( httpContext , exception );
|
||||
}
|
||||
catch ( APIErrorException exception )
|
||||
{
|
||||
await HandleApiErrorAsync( httpContext , exception );
|
||||
}
|
||||
catch ( Exception exception )
|
||||
{
|
||||
await HandleExceptionAsync( httpContext , exception );
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleExceptionAsync( HttpContext context , RedirectException exception )
|
||||
{
|
||||
context.Response.Redirect( exception.Destination );
|
||||
}
|
||||
|
||||
private static Task HandleErrorAsync( HttpContext context , ErrorException exception )
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
return context.Response.WriteAsync( exception.ErrorMessage );
|
||||
}
|
||||
private static Task HandleApiErrorAsync( HttpContext context , APIErrorException exception )
|
||||
{
|
||||
using MemoryStream stream = new( );
|
||||
|
||||
using Utf8JsonWriter writer = new( stream );
|
||||
writer.WriteStartObject( );
|
||||
writer.WriteBoolean( "Success" , false );
|
||||
writer.WriteString( "ErrorMessage" , exception.ErrorMessage );
|
||||
writer.WriteEndObject( );
|
||||
writer.Dispose( );
|
||||
|
||||
context.Response.ContentType = System.Net.Mime.MediaTypeNames.Application.Json;
|
||||
return context.Response.WriteAsync( Encoding.UTF8.GetString( stream.ToArray( ) ) );
|
||||
}
|
||||
|
||||
private static Task HandleExceptionAsync( HttpContext context , Exception exception )
|
||||
{
|
||||
context.Response.ContentType = System.Net.Mime.MediaTypeNames.Text.Plain;
|
||||
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
return context.Response.WriteAsync( exception.ToString( ) );
|
||||
}
|
||||
}
|
||||
16
App_Code/Exceptions/RedirectException.cs
Normal file
16
App_Code/Exceptions/RedirectException.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Library;
|
||||
|
||||
public class RedirectException : Exception
|
||||
{
|
||||
private readonly string m_Destination;
|
||||
|
||||
public RedirectException( string destination )
|
||||
{
|
||||
m_Destination = destination;
|
||||
}
|
||||
|
||||
public string Destination
|
||||
{
|
||||
get { return m_Destination; }
|
||||
}
|
||||
}
|
||||
21
App_Code/HtmlExtensions.cs
Normal file
21
App_Code/HtmlExtensions.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
namespace Library;
|
||||
|
||||
public static class HtmlExtensions
|
||||
{
|
||||
public static string IsNull( this IHtmlHelper htmlHelper , object? attempt , string fallback )
|
||||
{
|
||||
return htmlHelper.Encode( attempt?.ToString( ) ?? fallback );
|
||||
}
|
||||
|
||||
public static string IF( this IHtmlHelper htmlHelper , bool test , string value )
|
||||
{
|
||||
return htmlHelper.Encode( test ? value : "" );
|
||||
}
|
||||
|
||||
public static string IIF( this IHtmlHelper htmlHelper , bool test , string value_1 , string value_2 )
|
||||
{
|
||||
return htmlHelper.Encode( test ? value_1 : value_2 );
|
||||
}
|
||||
};
|
||||
226
App_Code/SQLBuilder.cs
Normal file
226
App_Code/SQLBuilder.cs
Normal file
@@ -0,0 +1,226 @@
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using System.Data.SqlTypes;
|
||||
|
||||
namespace Library;
|
||||
|
||||
public class SQLBuilder
|
||||
{
|
||||
private readonly SqlConnection m_DBConnection;
|
||||
private readonly string m_BaseQuery;
|
||||
private readonly string? m_OrderBy;
|
||||
private List<string>? m_Where;
|
||||
private Dictionary<string,object?>? m_Parameters;
|
||||
|
||||
private struct OutputParameter
|
||||
{
|
||||
public OutputParameter( string id , SqlDbType type )
|
||||
{
|
||||
m_ID = id;
|
||||
m_Parameter = new SqlParameter
|
||||
{
|
||||
ParameterName = id ,
|
||||
SqlDbType = type ,
|
||||
Direction = ParameterDirection.Output ,
|
||||
};
|
||||
}
|
||||
|
||||
public string ID
|
||||
{
|
||||
get { return m_ID; }
|
||||
}
|
||||
|
||||
public SqlParameter Parameter
|
||||
{
|
||||
get { return m_Parameter; }
|
||||
}
|
||||
|
||||
private readonly string m_ID;
|
||||
private readonly SqlParameter m_Parameter;
|
||||
}
|
||||
private List<OutputParameter>? m_OutputParameters;
|
||||
|
||||
private int m_ItemsPerPage = 0;
|
||||
private int m_CurrentPage = 0;
|
||||
|
||||
public SQLBuilder( SqlConnection conn , string query , string? order_by = null )
|
||||
{
|
||||
m_DBConnection = conn;
|
||||
m_BaseQuery = query;
|
||||
m_OrderBy = order_by;
|
||||
}
|
||||
|
||||
public SQLBuilder SetPaging( int page , int items_per_page )
|
||||
{
|
||||
m_ItemsPerPage = items_per_page;
|
||||
m_CurrentPage = page;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLBuilder AddWhere( string where )
|
||||
{
|
||||
if ( m_Where == null )
|
||||
m_Where = new( );
|
||||
m_Where.Add( where );
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLBuilder AddClause( string where , string parameter , object value )
|
||||
{
|
||||
AddWhere( where );
|
||||
AddParameter( parameter , value );
|
||||
return this;
|
||||
}
|
||||
|
||||
static private string StripVariable( string input )
|
||||
{
|
||||
StringBuilder result = new( );
|
||||
foreach ( char c in input )
|
||||
if ( char.IsLetterOrDigit( c ) )
|
||||
result.Append( c );
|
||||
return result.ToString( );
|
||||
}
|
||||
|
||||
public SQLBuilder AddLike( string column , string value )
|
||||
{
|
||||
if ( value == null || value.Length <= 0 )
|
||||
return this;
|
||||
|
||||
string[] parts = value.Split( ' ' , System.StringSplitOptions.RemoveEmptyEntries );
|
||||
if ( parts != null && parts.Length > 0 )
|
||||
{
|
||||
int part_index = 0;
|
||||
string variable_prefix = StripVariable( column );
|
||||
foreach ( string p in parts )
|
||||
{
|
||||
string variable = "@" + variable_prefix + (++part_index).ToString( ) + "@";
|
||||
AddClause( column + " LIKE " + variable , variable , "%" + p + "%" );
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLBuilder AddParameter( string name , object? value )
|
||||
{
|
||||
if ( m_Parameters == null )
|
||||
m_Parameters = new( );
|
||||
m_Parameters[name] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLBuilder AddOutputParameter( string name , SqlDbType type )
|
||||
{
|
||||
if ( m_OutputParameters == null )
|
||||
m_OutputParameters = new( );
|
||||
m_OutputParameters.Add( new OutputParameter( name , type ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
public object? GetOutputParameter( string name )
|
||||
{
|
||||
if ( m_OutputParameters == null )
|
||||
return null;
|
||||
|
||||
foreach ( OutputParameter p in m_OutputParameters )
|
||||
{
|
||||
if ( p.ID == name )
|
||||
return p.Parameter.Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SqlCommand PrepareCommand( )
|
||||
{
|
||||
string sql = m_BaseQuery;
|
||||
if ( m_Where != null && m_Where.Count > 0 )
|
||||
{
|
||||
sql += " WHERE ( " + m_Where[0] + " ) ";
|
||||
for ( int x = 1 ; x < m_Where.Count ; x++ )
|
||||
sql += " AND ( " + m_Where[x] + " ) ";
|
||||
}
|
||||
if ( m_OrderBy != null )
|
||||
sql += " ORDER BY " + m_OrderBy;
|
||||
|
||||
if ( m_ItemsPerPage > 0 )
|
||||
sql += " OFFSET " + ( m_CurrentPage * m_ItemsPerPage ).ToString( ) + " ROWS FETCH FIRST " + m_ItemsPerPage.ToString( ) + " ROWS ONLY";
|
||||
|
||||
SqlCommand command = new( sql , m_DBConnection );
|
||||
command.CommandType = CommandType.Text;
|
||||
if ( m_Parameters != null )
|
||||
{
|
||||
foreach ( var it in m_Parameters )
|
||||
{
|
||||
if ( it.Value != null )
|
||||
command.Parameters.AddWithValue( it.Key , it.Value! );
|
||||
else
|
||||
command.Parameters.AddWithValue( it.Key , System.DBNull.Value );
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_OutputParameters != null )
|
||||
{
|
||||
foreach ( var it in m_OutputParameters )
|
||||
command.Parameters.Add( it.Parameter );
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
public SqlDataReader ExecuteReader( )
|
||||
{
|
||||
return PrepareCommand( ).ExecuteReader( );
|
||||
}
|
||||
|
||||
public int ExecuteNonQuery( )
|
||||
{
|
||||
return PrepareCommand( ).ExecuteNonQuery( );
|
||||
}
|
||||
public int ExecuteAndReadInteger( int on_error_value )
|
||||
{
|
||||
using SqlDataReader reader = ExecuteReader( );
|
||||
if ( reader == null || !reader.Read( ) )
|
||||
return on_error_value;
|
||||
|
||||
SqlInt32 value = reader.GetSqlInt32( 0 );
|
||||
if ( value.IsNull )
|
||||
return on_error_value;
|
||||
|
||||
return value.Value;
|
||||
}
|
||||
|
||||
public int ReadSingleInteger( int on_error_value )
|
||||
{
|
||||
using SqlDataReader reader = ExecuteReader( );
|
||||
if ( reader == null || !reader.Read( ) )
|
||||
return on_error_value;
|
||||
|
||||
SqlInt32 value = reader.GetSqlInt32( 0 );
|
||||
if ( value.IsNull )
|
||||
return on_error_value;
|
||||
|
||||
return value.Value;
|
||||
}
|
||||
|
||||
public string? ReadSingleStringUnsafe( )
|
||||
{
|
||||
using SqlDataReader reader = ExecuteReader( );
|
||||
if ( reader == null || !reader.Read( ) )
|
||||
return null;
|
||||
|
||||
return reader.String( 0 );
|
||||
}
|
||||
|
||||
public string? ReadSingleString( )
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReadSingleStringUnsafe( );
|
||||
}
|
||||
catch ( Exception )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
App_Code/SQLExtensions.cs
Normal file
154
App_Code/SQLExtensions.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Data.SqlTypes;
|
||||
|
||||
namespace Library;
|
||||
|
||||
public static class SQLExtensions
|
||||
{
|
||||
public static string? String( this SqlDataReader reader , string column_id )
|
||||
{
|
||||
int column_index = reader.FindColumn( column_id );
|
||||
if ( column_index < 0 )
|
||||
return null;
|
||||
|
||||
return reader.String( column_index );
|
||||
}
|
||||
|
||||
public static string? String( this SqlDataReader reader , int column_index )
|
||||
{
|
||||
if ( reader.IsDBNull( column_index ) )
|
||||
return null;
|
||||
|
||||
string? o = reader[ column_index ].ToString( );
|
||||
if ( o == null )
|
||||
return null;
|
||||
|
||||
return o!;
|
||||
}
|
||||
|
||||
public static string StringSafe( this SqlDataReader reader , string column_id )
|
||||
{
|
||||
int column_index = reader.FindColumn( column_id );
|
||||
if ( column_index < 0 )
|
||||
return "";
|
||||
|
||||
return reader.StringSafe( column_index );
|
||||
}
|
||||
|
||||
public static string StringSafe( this SqlDataReader reader , int column_index )
|
||||
{
|
||||
if ( reader.IsDBNull( column_index ) )
|
||||
return "";
|
||||
|
||||
string? o = reader[ column_index ].ToString( );
|
||||
if ( o == null ) return "";
|
||||
|
||||
return o!;
|
||||
}
|
||||
|
||||
public static DateTime DateTime( this SqlDataReader reader , string column_id )
|
||||
{
|
||||
int column_index = reader.FindColumn( column_id );
|
||||
if ( column_index < 0 )
|
||||
return System.DateTime.MinValue;
|
||||
|
||||
return reader.DateTime( column_index );
|
||||
}
|
||||
|
||||
public static DateTime DateTime( this SqlDataReader reader , int column_index )
|
||||
{
|
||||
object data_value = reader[ column_index ];
|
||||
if ( data_value is DateTime date_time_result )
|
||||
return date_time_result;
|
||||
|
||||
return System.DateTime.MinValue;
|
||||
}
|
||||
|
||||
public static int Int( this SqlDataReader reader , string column_id , int fallback = 0 )
|
||||
{
|
||||
int column_index = reader.FindColumn( column_id );
|
||||
if ( column_index < 0 )
|
||||
return fallback;
|
||||
|
||||
return reader.Int( column_index , fallback );
|
||||
}
|
||||
|
||||
public static int Int( this SqlDataReader reader , int column_index , int fallback = 0 )
|
||||
{
|
||||
object data = reader[ column_index ];
|
||||
if ( data == null )
|
||||
return fallback;
|
||||
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32( data );
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if ( int.TryParse( data.ToString( ) , out int result ) )
|
||||
return result;
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
public static long Int64( this SqlDataReader reader , string column_id , long fallback )
|
||||
{
|
||||
int column_index = reader.FindColumn( column_id );
|
||||
if ( column_index < 0 )
|
||||
return fallback;
|
||||
|
||||
return reader.Int64( column_index , fallback );
|
||||
}
|
||||
|
||||
public static long Int64( this SqlDataReader reader , int column_index , long fallback )
|
||||
{
|
||||
object data = reader[ column_index ];
|
||||
if ( data == null )
|
||||
return fallback;
|
||||
|
||||
try
|
||||
{
|
||||
return Convert.ToInt64( data );
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if ( long.TryParse( data.ToString( ) , out long result ) )
|
||||
return result;
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
public static decimal Numeric( this SqlDataReader reader , string column_id , decimal fallback )
|
||||
{
|
||||
int column_index = reader.FindColumn( column_id );
|
||||
if ( column_index < 0 )
|
||||
return fallback;
|
||||
|
||||
return reader.Numeric( column_index , fallback );
|
||||
}
|
||||
|
||||
public static decimal Numeric( this SqlDataReader reader , int column_index , decimal fallback )
|
||||
{
|
||||
SqlDecimal data = reader.GetSqlDecimal( column_index );
|
||||
if ( data.IsNull )
|
||||
return 0;
|
||||
return data.Value;
|
||||
}
|
||||
|
||||
|
||||
public static int FindColumn( this SqlDataReader reader , string column_id )
|
||||
{
|
||||
try
|
||||
{
|
||||
return reader.GetOrdinal( column_id );
|
||||
}
|
||||
catch ( Exception )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
60
App_Code/ViewScriptTagHelper.cs
Normal file
60
App_Code/ViewScriptTagHelper.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace Library;
|
||||
|
||||
public class ViewScriptTagHelper : TagHelper
|
||||
{
|
||||
private readonly IWebHostEnvironment environment;
|
||||
private readonly IFileVersionProvider fileVersionProvider;
|
||||
private const string AppendVersionAttributeName = "append-version";
|
||||
|
||||
public ViewScriptTagHelper( IWebHostEnvironment environment , IFileVersionProvider fileVersionProvider )
|
||||
{
|
||||
this.environment = environment;
|
||||
this.fileVersionProvider = fileVersionProvider;
|
||||
}
|
||||
|
||||
[ViewContext]
|
||||
public ViewContext? ViewContext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value indicating if file version should be appended to src urls.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A query string "v" with the encoded content of the file is added.
|
||||
/// </remarks>
|
||||
[HtmlAttributeName( AppendVersionAttributeName )]
|
||||
public bool? AppendVersion { get; set; }
|
||||
|
||||
public override void Process( TagHelperContext context , TagHelperOutput output )
|
||||
{
|
||||
// remove the `page-script` tag if script doesn't exist
|
||||
output.TagName = null;
|
||||
output.TagMode = TagMode.StartTagAndEndTag;
|
||||
|
||||
var viewPath = ViewContext?.View.Path;
|
||||
var src = $"{viewPath}.js";
|
||||
|
||||
/* When the app is published, the framework automatically moves the script to the web root.
|
||||
So we should check both places, with the content root first for development */
|
||||
var fileInfo = environment.ContentRootFileProvider.GetFileInfo(src) ??
|
||||
environment.WebRootFileProvider.GetFileInfo(src);
|
||||
|
||||
if ( fileInfo is { Exists: true } )
|
||||
{
|
||||
// switch it to script now
|
||||
output.TagName = "script";
|
||||
output.Content = new DefaultTagHelperContent( );
|
||||
|
||||
if ( AppendVersion == true )
|
||||
{
|
||||
// people love their cache busting versions
|
||||
src = fileVersionProvider.AddFileVersionToPath( src , src );
|
||||
}
|
||||
|
||||
output.Attributes.Add( "src" , src );
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user