788 lines · 33.1 KB · C#
RawDownload
//******************************************************************************************************//  ModelController.cs - Gbtc////  Copyright © 2021, Grid Protection Alliance.  All Rights Reserved.////  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See//  the NOTICE file distributed with this work for additional information regarding copyright ownership.//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this//  file except in compliance with the License. You may obtain a copy of the License at:////      http://opensource.org/licenses/MIT////  Unless agreed to in writing, the subject software distributed under the License is distributed on an//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the//  License for the specific language governing permissions and limitations.////  Code Modification History://  ----------------------------------------------------------------------------------------------------//  10/04/2019 - Billy Ernest//       Generated original version of source code.//  05/25/2021 - C. Lackner//       Added Additional Fields Search Query and moved to GSF////****************************************************************************************************** using System;using System.Collections.Generic;using System.Data;using System.Linq;using System.Reflection;using System.Security.Claims;using System.Web.Http;using GSF.Data;using GSF.Data.Model;using Newtonsoft.Json;using Newtonsoft.Json.Linq; #pragma warning disable CS1591 // TODO: Fix missing XML comments for publicly visible types and members namespace GSF.Web.Model{    /// <summary>    /// Base Class for A Webcontroller that provides common Model endpoints such as Edit, Delete, Search.    /// </summary>    /// <typeparam name="T">The corresponding Model.</typeparam>    public class ModelController<T> : ApiController where T : class, new()    {        #region [ Members ]         /// <summary>        /// Class Providing Search Parameters for the Search Endpoints        /// </summary>        public class Search        {            public string FieldName { get; set; }            public string SearchText { get; set; }            public string Operator { get; set; }            public string Type { get; set; }            public bool isPivotColumn { get; set; } = false;        }         public class PostData        {            public IEnumerable<Search> Searches { get; set; }            public string OrderBy { get; set; }            public bool Ascending { get; set; }        }        #endregion         #region [ Constructor ]         /// <summary>        /// Creates a new <see cref="ModelController{T}"/>        /// </summary>        public ModelController()        {            PrimaryKeyField = typeof(T).GetProperties().FirstOrDefault(p => p.GetCustomAttributes<PrimaryKeyAttribute>().Any())?.Name ?? "ID";             ParentKey = typeof(T).GetProperties().FirstOrDefault(p => p.GetCustomAttributes<ParentKeyAttribute>().Any())?.Name ?? "";            Connection = typeof(T).GetCustomAttribute<SettingsCategoryAttribute>()?.SettingsCategory ?? "systemSettings";             PropertyInfo pi = typeof(T).GetProperties().FirstOrDefault(p => p.GetCustomAttributes<DefaultSortOrderAttribute>().Any());            DefaultSortOrderAttribute dsoa = pi?.GetCustomAttribute<DefaultSortOrderAttribute>();            if (dsoa != null)                DefaultSort = $"{pi.Name} {(dsoa.Ascending ? "ASC" : "DESC")}";             if (User.GetType() == typeof(ClaimsPrincipal))            {                SecurityType = "Claims";                 IEnumerable<ClaimAttribute> claimAttributes = typeof(T).GetCustomAttributes<ClaimAttribute>();                 foreach (ClaimAttribute claimAttribute in claimAttributes)                {                    if (Claims.ContainsKey(claimAttribute.Verb))                        Claims[claimAttribute.Verb].Add(claimAttribute.Claim);                    else                        Claims.Add(claimAttribute.Verb, new List<Claim>() { claimAttribute.Claim });                }                 if (!Claims.ContainsKey("POST"))                    Claims.Add("POST", new List<Claim>() { new Claim("Role", "Administrator") });                if (!Claims.ContainsKey("PATCH"))                    Claims.Add("PATCH", new List<Claim>() { new Claim("Role", "Administrator") });                if (!Claims.ContainsKey("DELETE"))                    Claims.Add("DELETE", new List<Claim>() { new Claim("Role", "Administrator") });             }            else            {                 SecurityType = "Roles";                PostRoles = typeof(T).GetCustomAttribute<PostRolesAttribute>()?.Roles ?? "Administrator";                GetRoles = typeof(T).GetCustomAttribute<GetRolesAttribute>()?.Roles ?? "";                PatchRoles = typeof(T).GetCustomAttribute<PatchRolesAttribute>()?.Roles ?? "Administrator";                DeleteRoles = typeof(T).GetCustomAttribute<DeleteRolesAttribute>()?.Roles ?? "Administrator";            }            CustomView = typeof(T).GetCustomAttribute<CustomViewAttribute>()?.CustomView ?? "";            ViewOnly = typeof(T).GetCustomAttribute<ViewOnlyAttribute>()?.ViewOnly ?? false;            AllowSearch = typeof(T).GetCustomAttribute<AllowSearchAttribute>()?.AllowSearch ?? false;             SearchSettings = typeof(T).GetCustomAttribute<AdditionalFieldSearchAttribute>();            Take = typeof(T).GetCustomAttribute<ReturnLimitAttribute>()?.Limit ?? null;             // Custom View Models are ViewOnly.            ViewOnly = ViewOnly || CustomView != String.Empty;         }         #endregion         #region [ Properties ]        protected bool ViewOnly { get; } = false;        protected bool AllowSearch { get; } = false;        protected string CustomView { get; } = "";        protected string PrimaryKeyField { get; set; } = "ID";        protected string ParentKey { get; set; } = "";        protected string Connection { get; } = "systemSettings";        protected string DefaultSort { get; } = null;        protected string GetRoles { get; } = "";        protected string PostRoles { get; } = "Administrator";        protected string PatchRoles { get; } = "Administrator";        protected string DeleteRoles { get; } = "Administrator";        private int? Take { get; } = null;        private string SecurityType = "";         protected Dictionary<string, List<Claim>> Claims { get; } = new Dictionary<string, List<Claim>>();         protected AdditionalFieldSearchAttribute SearchSettings { get; } = null;        #endregion         #region [ Http Methods ]        /// <summary>        /// Used to get an empty record        /// </summary>        /// <returns>An empty record</returns>        [HttpGet, Route("New")]        public virtual IHttpActionResult GetNew()        {            if (ViewOnly)                return Unauthorized();             if (GetAuthCheck())            {                using (AdoDataConnection connection = new AdoDataConnection(Connection))                {                     try                    {                        return Ok(new TableOperations<T>(connection).NewRecord());                    }                    catch (Exception ex)                    {                        return InternalServerError(ex);                    }                }            }            else            {                return Unauthorized();            }         }         /// <summary>        /// Gets all records from associated table, filtered to parent key ID if provided        /// </summary>        /// <param name="parentID">Parent ID to be used if Table has a set Parent Key</param>        /// <returns><see cref="IHttpActionResult"/> containing <see cref="IEnumerable{T}"/> or <see cref="Exception"/></returns>        [HttpGet, Route("{parentID?}")]        public virtual IHttpActionResult Get(string parentID = null)        {            if (GetAuthCheck())            {                 try                {                    IEnumerable<T> result;                    if (ParentKey != string.Empty && parentID != null)                    {                        PropertyInfo parentKey = typeof(T).GetProperty(ParentKey);                        if (parentKey.PropertyType == typeof(int))                            result = QueryRecordsWhere(ParentKey + " = {0}", int.Parse(parentID));                        else if (parentKey.PropertyType == typeof(Guid))                            result = QueryRecordsWhere(ParentKey + " = {0}", Guid.Parse(parentID));                        else                            result = QueryRecordsWhere(ParentKey + " = {0}", parentID);                    }                    else                        result = QueryRecords();                     return Ok(result);                }                catch (Exception ex)                {                    return InternalServerError(ex);                }             }            else            {                return Unauthorized();            }         }         /// <summary>        /// Gets record from associated table with a primary key matching the <paramref name="id"/> provided.        /// </summary>        /// <param name="id">ID to be used</param>        /// <returns><see cref="IHttpActionResult"/> containing <typeparamref name="T"/> or <see cref="Exception"/></returns>        [HttpGet, Route("One/{id}")]        public virtual IHttpActionResult GetOne(string id)        {            if (GetAuthCheck())            {                 try                {                    T result = null;                    PropertyInfo primaryKey = typeof(T).GetProperty(PrimaryKeyField);                    if (primaryKey.PropertyType == typeof(int))                        result = QueryRecordWhere(PrimaryKeyField + " = {0}", int.Parse(id));                    else if (primaryKey.PropertyType == typeof(Guid))                        result = QueryRecordWhere(PrimaryKeyField + " = {0}", Guid.Parse(id));                    else                        result = QueryRecordWhere(PrimaryKeyField + " = {0}", id);                     if (result == null)                    {                        string tableName = TableOperations<T>.GetTableName();                        return BadRequest(string.Format(PrimaryKeyField + " provided does not exist in '{0}'.", tableName));                    }                    else                        return Ok(result);                }                catch (Exception ex)                {                    return InternalServerError(ex);                }             }            else            {                return Unauthorized();            }         }         /// <summary>        /// Gets a sorted list of <typeparamref name="T"/>.        /// </summary>        /// <param name="sort"> the Field to be sorted by.</param>        /// <param name="ascending"> parameter to indicate whether the list is in ascending order.</param>        /// <returns><see cref="IHttpActionResult"/> containing <see cref="IEnumerable{T}"/> or <see cref="Exception"/></returns>        [HttpGet, Route("{sort}/{ascending:int}")]        public virtual IHttpActionResult Get(string sort, int ascending)        {            if (GetAuthCheck())            {                 try                {                    IEnumerable<T> result = QueryRecords();                     return Ok(JsonConvert.SerializeObject(result));                }                catch (Exception ex)                {                    return InternalServerError(ex);                }             }            else            {                return Unauthorized();            }         }         /// <summary>        /// Gets all records from associated table, filtered to parent key ID if provided, sorted by the provided Field.        /// </summary>        /// <param name="parentID">Parent ID to be used if Table has a set Parent Key</param>        /// <param name="sort"> the Field to be sorted by.</param>        /// <param name="ascending"> parameter to indicate whether the list is in ascending order.</param>        /// <returns><see cref="IHttpActionResult"/> containing <see cref="IEnumerable{T}"/> or <see cref="Exception"/></returns>        [HttpGet, Route("{parentID}/{sort}/{ascending:int}")]        public virtual IHttpActionResult Get(string parentID, string sort, int ascending)        {            if (GetAuthCheck())            {                  try                {                    IEnumerable<T> result;                    if (ParentKey != string.Empty && parentID != null)                    {                        PropertyInfo parentKey = typeof(T).GetProperty(ParentKey);                        if (parentKey.PropertyType == typeof(int))                            result = QueryRecordsWhere(ParentKey + " = {0}", int.Parse(parentID));                        else if (parentKey.PropertyType == typeof(Guid))                            result = QueryRecordsWhere(ParentKey + " = {0}", Guid.Parse(parentID));                        else                            result = QueryRecordsWhere(ParentKey + " = {0}", parentID);                    }                    else                        result = QueryRecords();                     return Ok(JsonConvert.SerializeObject(result));                }                catch (Exception ex)                {                    return InternalServerError(ex);                }             }            else            {                return Unauthorized();            }         }          /// <summary>        /// Adds a new Record.        /// </summary>        /// <param name="record"> The <typeparamref name="T"/> record to be added.</param>        /// <returns><see cref="IHttpActionResult"/> containing the added record or <see cref="Exception"/> </returns>        [HttpPost, Route("Add")]        public virtual IHttpActionResult Post([FromBody] JObject record)        {            try            {                if (PostAuthCheck() && !ViewOnly)                {                    using (AdoDataConnection connection = new AdoDataConnection(Connection))                    {                         T newRecord = record.ToObject<T>();                        int result = new TableOperations<T>(connection).AddNewRecord(newRecord);                                                return Ok(result);                    }                }                else                {                    return Unauthorized();                }             }            catch (Exception ex)            {                return InternalServerError(ex);            }        }         /// <summary>        /// Updates an existing Record.        /// </summary>        /// <param name="record"> The <typeparamref name="T"/> record to be updated.</param>        /// <returns><see cref="IHttpActionResult"/> containing the updated record or <see cref="Exception"/> </returns>         [HttpPatch, Route("Update")]        public virtual IHttpActionResult Patch([FromBody] T record)        {            try            {                if (PatchAuthCheck() && !ViewOnly)                {                     using (AdoDataConnection connection = new AdoDataConnection(Connection))                    {                        int result = new TableOperations<T>(connection).AddNewOrUpdateRecord(record);                         if (PrimaryKeyField != string.Empty)                        {                            T newRecord = record;                            PropertyInfo prop = typeof(T).GetProperty(PrimaryKeyField);                            if (prop != null)                            {                                object uniqueKey = prop.GetValue(newRecord);                                newRecord = new TableOperations<T>(connection).QueryRecordWhere(PrimaryKeyField + " = {0}", uniqueKey);                                return Ok(newRecord);                            }                         }                        return Ok(result);                    }                }                else                {                    return Unauthorized();                }              }            catch (Exception ex)            {                return InternalServerError(ex);            }        }         /// <summary>        /// Deletes an existing Record.        /// </summary>        /// <param name="record"> The <typeparamref name="T"/> record to be deleted.</param>        /// <returns><see cref="IHttpActionResult"/> containing the number of records deleted or <see cref="Exception"/> </returns>         [HttpDelete, Route("Delete")]        public virtual IHttpActionResult Delete(T record)        {            try            {                if (DeleteAuthCheck() && !ViewOnly)                {                     using (AdoDataConnection connection = new AdoDataConnection(Connection))                    {                        string tableName = new TableOperations<T>(connection).TableName;                         PropertyInfo idProp = typeof(T).GetProperty(PrimaryKeyField);                        if (idProp.PropertyType == typeof(int))                        {                            int id = (int)idProp.GetValue(record);                            int result = connection.ExecuteNonQuery($"EXEC UniversalCascadeDelete {tableName}, '{PrimaryKeyField} = {id}'");                            return Ok(result);                         }                        else if (idProp.PropertyType == typeof(Guid))                        {                            Guid id = (Guid)idProp.GetValue(record);                            int result = connection.ExecuteNonQuery($"EXEC UniversalCascadeDelete {tableName}, '{PrimaryKeyField} = ''{id}'''");                            return Ok(result);                         }                        else if (idProp.PropertyType == typeof(string))                        {                            string id = (string)idProp.GetValue(record);                            int result = connection.ExecuteNonQuery($"EXEC UniversalCascadeDelete {tableName}, '{PrimaryKeyField} = ''{id}'''");                            return Ok(result);                         }                        else                        {                            int result = new TableOperations<T>(connection).DeleteRecord(record);                            return Ok(result);                        }                    }                }                else                {                    return Unauthorized();                }             }            catch (Exception ex)            {                return InternalServerError(ex);            }        }         /// <summary>        /// Gets all records from associated table, filtered and sorted as defined in <paramref name="postData"/>.        /// </summary>        /// <param name="postData"><see cref="PostData"/> containing the search and sort parameters</param>       /// <returns><see cref="IHttpActionResult"/> containing <see cref="IEnumerable{T}"/> or <see cref="Exception"/></returns>         [HttpPost, Route("SearchableList")]        public virtual IHttpActionResult GetSearchableList([FromBody] PostData postData)        {            if (GetAuthCheck() && !AllowSearch)                return Unauthorized();             try            {                DataTable table = GetSearchResults(postData);                return Ok(JsonConvert.SerializeObject(table));

Lines 1–500 of 788.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t