Bläddra i källkod

添加项目文件。

黄贺彬 6 år sedan
förälder
incheckning
e4995d2dab
100 ändrade filer med 51126 tillägg och 0 borttagningar
  1. 29 0
      HaBookCms.Admin/Controllers/HomeController.cs
  2. 52 0
      HaBookCms.Admin/Controllers/Sys/UsersController.cs
  3. 23 0
      HaBookCms.Admin/HaBookCms.Admin.csproj
  4. 38 0
      HaBookCms.Admin/Log4net.config
  5. 11 0
      HaBookCms.Admin/Models/ErrorViewModel.cs
  6. 24 0
      HaBookCms.Admin/Program.cs
  7. 27 0
      HaBookCms.Admin/Properties/launchSettings.json
  8. 235 0
      HaBookCms.Admin/Startup.cs
  9. 8 0
      HaBookCms.Admin/Views/Home/Index.cshtml
  10. 6 0
      HaBookCms.Admin/Views/Home/Privacy.cshtml
  11. 25 0
      HaBookCms.Admin/Views/Shared/Error.cshtml
  12. 25 0
      HaBookCms.Admin/Views/Shared/_CookieConsentPartial.cshtml
  13. 77 0
      HaBookCms.Admin/Views/Shared/_Layout.cshtml
  14. 18 0
      HaBookCms.Admin/Views/Shared/_ValidationScriptsPartial.cshtml
  15. 3 0
      HaBookCms.Admin/Views/_ViewImports.cshtml
  16. 3 0
      HaBookCms.Admin/Views/_ViewStart.cshtml
  17. 9 0
      HaBookCms.Admin/appsettings.Development.json
  18. 40 0
      HaBookCms.Admin/appsettings.json
  19. 56 0
      HaBookCms.Admin/wwwroot/css/site.css
  20. BIN
      HaBookCms.Admin/wwwroot/favicon.ico
  21. 4 0
      HaBookCms.Admin/wwwroot/js/site.js
  22. 22 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/LICENSE
  23. 1912 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css
  24. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map
  25. 7 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css
  26. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map
  27. 331 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css
  28. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map
  29. 8 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css
  30. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map
  31. 9030 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap.css
  32. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map
  33. 7 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css
  34. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map
  35. 6461 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js
  36. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map
  37. 7 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js
  38. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map
  39. 3944 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.js
  40. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map
  41. 7 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js
  42. 1 0
      HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map
  43. 12 0
      HaBookCms.Admin/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt
  44. 432 0
      HaBookCms.Admin/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js
  45. 5 0
      HaBookCms.Admin/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js
  46. 22 0
      HaBookCms.Admin/wwwroot/lib/jquery-validation/LICENSE.md
  47. 1158 0
      HaBookCms.Admin/wwwroot/lib/jquery-validation/dist/additional-methods.js
  48. 4 0
      HaBookCms.Admin/wwwroot/lib/jquery-validation/dist/additional-methods.min.js
  49. 1601 0
      HaBookCms.Admin/wwwroot/lib/jquery-validation/dist/jquery.validate.js
  50. 4 0
      HaBookCms.Admin/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js
  51. 36 0
      HaBookCms.Admin/wwwroot/lib/jquery/LICENSE.txt
  52. 10364 0
      HaBookCms.Admin/wwwroot/lib/jquery/dist/jquery.js
  53. 2 0
      HaBookCms.Admin/wwwroot/lib/jquery/dist/jquery.min.js
  54. 1 0
      HaBookCms.Admin/wwwroot/lib/jquery/dist/jquery.min.map
  55. 8 0
      HaBookCms.AzureCosmos/Class1.cs
  56. 7 0
      HaBookCms.AzureCosmos/HaBookCms.AzureCosmos.csproj
  57. 8 0
      HaBookCms.AzureStorage/Class1.cs
  58. 7 0
      HaBookCms.AzureStorage/HaBookCms.AzureStorage.csproj
  59. 218 0
      HaBookCms.Common/CryptHelper/AESCrypt.cs
  60. 338 0
      HaBookCms.Common/CryptHelper/AESEncrypt.cs
  61. 97 0
      HaBookCms.Common/CryptHelper/DESCrypt.cs
  62. 49 0
      HaBookCms.Common/CryptHelper/Md5Crypt.cs
  63. 64 0
      HaBookCms.Common/CryptHelper/RSACrypt.cs
  64. 753 0
      HaBookCms.Common/FileHelper/FileHelper.cs
  65. 552 0
      HaBookCms.Common/FileHelper/FileHelperCore.cs
  66. 23 0
      HaBookCms.Common/HaBookCms.Common.csproj
  67. 154 0
      HaBookCms.Common/LogHelper/ILoggerHelper.cs
  68. 284 0
      HaBookCms.Common/LogHelper/LogHelper.cs
  69. 738 0
      HaBookCms.Common/Utils.cs
  70. 29 0
      HaBookCms.Contest/Controllers/HomeController.cs
  71. 14 0
      HaBookCms.Contest/HaBookCms.Contest.csproj
  72. 11 0
      HaBookCms.Contest/Models/ErrorViewModel.cs
  73. 24 0
      HaBookCms.Contest/Program.cs
  74. 27 0
      HaBookCms.Contest/Properties/launchSettings.json
  75. 64 0
      HaBookCms.Contest/Startup.cs
  76. 8 0
      HaBookCms.Contest/Views/Home/Index.cshtml
  77. 6 0
      HaBookCms.Contest/Views/Home/Privacy.cshtml
  78. 25 0
      HaBookCms.Contest/Views/Shared/Error.cshtml
  79. 25 0
      HaBookCms.Contest/Views/Shared/_CookieConsentPartial.cshtml
  80. 77 0
      HaBookCms.Contest/Views/Shared/_Layout.cshtml
  81. 18 0
      HaBookCms.Contest/Views/Shared/_ValidationScriptsPartial.cshtml
  82. 3 0
      HaBookCms.Contest/Views/_ViewImports.cshtml
  83. 3 0
      HaBookCms.Contest/Views/_ViewStart.cshtml
  84. 9 0
      HaBookCms.Contest/appsettings.Development.json
  85. 8 0
      HaBookCms.Contest/appsettings.json
  86. 56 0
      HaBookCms.Contest/wwwroot/css/site.css
  87. BIN
      HaBookCms.Contest/wwwroot/favicon.ico
  88. 4 0
      HaBookCms.Contest/wwwroot/js/site.js
  89. 22 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/LICENSE
  90. 1912 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css
  91. 1 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map
  92. 7 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css
  93. 1 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map
  94. 331 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css
  95. 1 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map
  96. 8 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css
  97. 1 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map
  98. 9030 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap.css
  99. 1 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map
  100. 0 0
      HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css

+ 29 - 0
HaBookCms.Admin/Controllers/HomeController.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using HaBookCms.Admin.Models;
+
+namespace HaBookCms.Admin.Controllers
+{
+    public class HomeController : Controller
+    {
+        public IActionResult Index()
+        {
+            return View();
+        }
+
+        public IActionResult Privacy()
+        {
+            return View();
+        }
+
+        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
+        public IActionResult Error()
+        {
+            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
+        }
+    }
+}

+ 52 - 0
HaBookCms.Admin/Controllers/Sys/UsersController.cs

@@ -0,0 +1,52 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace HaBookCms.Admin.Controllers.Sys
+{
+    /// <summary>
+    /// Blog控制器所有接口
+    /// </summary>
+    [Authorize(Policy = "RequireAdmin")]
+    [Produces("application/json")]
+    [Route("api/Users")]
+    public class UsersController :Controller
+    {   // GET: api/Blog/5
+        /// <summary>
+        /// 获取详情
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("ccc")]
+        public async Task<object> Get(int id)
+        {
+
+            Console.WriteLine("11");
+            return Ok(new
+            {
+                success = true,
+                data = "aaa"
+            });
+        }
+        // GET: api/Blog/5
+        /// <summary>
+        /// 获取详情
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("checkLogin")]
+        [AllowAnonymous]
+        public async Task<object> checkLogin()
+        {
+
+            return Ok(new
+            {
+                success = true,
+                data = "bbb"
+            });
+        }
+    }
+}

+ 23 - 0
HaBookCms.Admin/HaBookCms.Admin.csproj

@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
+    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
+  </PropertyGroup>
+
+
+  <ItemGroup>
+    <PackageReference Include="log4net" Version="2.0.8" />
+    <PackageReference Include="Microsoft.AspNetCore.App" />
+    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
+  </ItemGroup>
+
+
+  <ItemGroup>
+    <ProjectReference Include="..\HaBookCms.Common\HaBookCms.Common.csproj" />
+    <ProjectReference Include="..\HaBookCms.ContextConfig\HaBookCms.ContextConfig.csproj" />
+    <ProjectReference Include="..\HaBookCms.Extensions\HaBookCms.Extensions.csproj" />
+    <ProjectReference Include="..\HaBookCms.RedisStorage\HaBookCms.RedisStorage.csproj" />
+  </ItemGroup>
+
+</Project>

+ 38 - 0
HaBookCms.Admin/Log4net.config

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <configSections>
+    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
+  </configSections>
+
+  <log4net>
+    <!-- 将日志以回滚文件的形式写到文件中 -->
+    <!-- 按日期切分日志文件,并将日期作为日志文件的名字 -->
+    <appender name="RollingFileAppenderNameByDate" type="log4net.Appender.RollingFileAppender">
+      <!-- 日志文件存放位置,可以为绝对路径也可以为相对路径 -->
+      <file value="C:\Logs\" />
+      <!-- 将日志信息追加到已有的日志文件中-->
+      <appendToFile value="true" />
+      <!-- 最小锁定模式,以允许多个进程可以写入同一个文件 -->
+      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
+      <!-- 指定按日期切分日志文件 -->
+      <rollingStyle value="Date" />
+      <!-- 日志文件的命名规则 -->
+      <datePattern value="&quot;UtilLogs_&quot;yyyyMMdd&quot;.log&quot;" />
+      <!-- 当将日期作为日志文件的名字时,必须将staticLogFileName的值设置为false -->
+      <staticLogFileName value="false" />
+
+      <layout type="log4net.Layout.PatternLayout">
+        <conversionPattern value="【异常时间】:%date %newline%message%newline--------------------------------------------------------------------%newline" />
+      </layout>
+    </appender>
+
+    <root>
+      <!-- 控制级别,由低到高:ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF -->
+      <!-- 比如定义级别为INFO,则INFO级别向下的级别,比如DEBUG日志将不会被记录 -->
+      <!-- 如果没有定义LEVEL的值,则缺省为DEBUG -->
+      <level value="ALL" />
+      <!-- 按日期切分日志文件,并将日期作为日志文件的名字 -->
+      <appender-ref ref="RollingFileAppenderNameByDate" />
+    </root>
+  </log4net>
+</configuration>

+ 11 - 0
HaBookCms.Admin/Models/ErrorViewModel.cs

@@ -0,0 +1,11 @@
+using System;
+
+namespace HaBookCms.Admin.Models
+{
+    public class ErrorViewModel
+    {
+        public string RequestId { get; set; }
+
+        public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
+    }
+}

+ 24 - 0
HaBookCms.Admin/Program.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace HaBookCms.Admin
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateWebHostBuilder(args).Build().Run();
+        }
+
+        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
+            WebHost.CreateDefaultBuilder(args)
+                .UseStartup<Startup>();
+    }
+}

+ 27 - 0
HaBookCms.Admin/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false, 
+    "anonymousAuthentication": true, 
+    "iisExpress": {
+      "applicationUrl": "http://localhost:63969",
+      "sslPort": 44347
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "HaBookCms.Admin": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "https://localhost:5001;http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 235 - 0
HaBookCms.Admin/Startup.cs

@@ -0,0 +1,235 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Claims;
+using System.Text;
+using System.Text.Encodings.Web;
+using System.Text.Unicode;
+using HaBookCms.Common.LogHelper;
+using HaBookCms.ContextConfig.Exceptions;
+using HaBookCms.Extensions.Jwt;
+using HaBookCms.Extensions.Jwt.Model;
+using HaBookCms.RedisStorage.Cache;
+using log4net;
+using log4net.Config;
+using log4net.Repository;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.HttpOverrides;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.IdentityModel.Tokens;
+
+namespace HaBookCms.Admin
+{
+    public class Startup
+    {
+        /// <summary>
+        /// log4net 仓储库
+        /// </summary>
+        public static ILoggerRepository repository { get; set; }
+
+        public Startup(IConfiguration configuration, IHostingEnvironment env)
+        {
+            Configuration = configuration;
+            var builder = new ConfigurationBuilder()
+                .SetBasePath(env.ContentRootPath)
+                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
+            this.Configuration = builder.Build();
+            //log4net
+            repository = LogManager.CreateRepository("HaBookCms");
+            //指定配置文件
+            XmlConfigurator.Configure(repository, new FileInfo("Log4net.config"));
+            BaseConfigModel.SetBaseConfig(Configuration, env.ContentRootPath, env.WebRootPath);
+        }
+
+        public IConfiguration Configuration { get; }
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.Configure<CookiePolicyOptions>(options =>
+            {
+                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
+                options.CheckConsentNeeded = context => true;
+                options.MinimumSameSitePolicy = SameSiteMode.None;
+            });
+           
+            
+            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
+            //解决视图输出内容中文编码问题
+            services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));
+            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
+            #region 认证
+            JwtAuthConfigModel jwtConfig = new JwtAuthConfigModel();
+            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
+            //.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o =>
+            // {
+            //     o.LoginPath = new PathString("/api/Users/checkLogin");
+            // })
+             .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o =>
+             {
+               
+                 o.TokenValidationParameters = new TokenValidationParameters
+                 {
+                     ValidIssuer = jwtConfig.Issuer,
+                     ValidAudience = jwtConfig.Audience,
+                     IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig.JWTSecretKey)),
+
+                     /***********************************TokenValidationParameters的参数默认值***********************************/
+                     RequireSignedTokens = true,
+                     // SaveSigninToken = false,
+                     // ValidateActor = false,
+                     // 将下面两个参数设置为false,可以不验证Issuer和Audience,但是不建议这样做。
+                     ValidateAudience = true,
+                     ValidateIssuer = true,
+                     ValidateIssuerSigningKey = true,
+                     // 是否要求Token的Claims中必须包含 Expires
+                     RequireExpirationTime = true,
+                     // 允许的服务器时间偏移量
+                     // ClockSkew = TimeSpan.FromSeconds(300),
+                     ClockSkew = TimeSpan.Zero,
+                     // 是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
+                     ValidateLifetime = true
+                 };
+             });
+            #endregion
+            var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig.JWTSecretKey)), SecurityAlgorithms.HmacSha256);
+            // 如果要数据库动态绑定,这里先留个空,后边处理器里动态赋值
+            var permission = new List<Permission>();
+
+            // 角色与接口的权限要求参数
+            var permissionRequirement = new PermissionRequirement(
+                "/api/denied",// 拒绝授权的跳转地址(目前无用)
+                permission,
+                ClaimTypes.Role,//基于角色的授权
+               jwtConfig.Issuer,//发行人
+               jwtConfig.Audience,//听众
+                signingCredentials,//签名凭据
+                expiration: TimeSpan.FromSeconds(60 * 2)//接口的过期时间
+                );
+
+            #region 授权
+            services.AddAuthorization(options =>
+            {
+                options.AddPolicy("RequireApp", policy => policy.RequireRole("App").Build());
+                options.AddPolicy("RequireAdmin", policy => policy.RequireRole("Admin").Build());
+                options.AddPolicy("RequireAdminOrApp", policy => policy.RequireRole("Admin,App").Build());
+                // 自定义权限要求
+                options.AddPolicy("Permission",
+                         policy => policy.Requirements.Add(permissionRequirement));
+            });
+            #endregion
+
+          
+
+            //log日志注入
+            services.AddSingleton<ILoggerHelper, LogHelper>();
+
+
+            #region 缓存 读取配置是否使用哪种缓存模式
+            services.AddMemoryCache();
+            if (Convert.ToBoolean(Configuration["Cache:IsUseRedis"]))
+            {
+                services.AddSingleton<ICacheService, RedisCacheService>();
+            }
+            else
+            {
+                services.AddSingleton<ICacheService, MemoryCacheService>();
+            }
+            #endregion
+
+            #region 缓存 RedisCache
+            //将Redis分布式缓存服务添加到服务中
+            services.AddDistributedRedisCache(options =>
+            {
+                //用于连接Redis的配置 
+                options.Configuration = "localhost";// Configuration.GetConnectionString("RedisConnectionString");
+                //Redis实例名RedisDistributedCache
+                options.InstanceName = "RedisInstance";
+            });
+            #endregion
+
+            #region CORS
+            services.AddCors(c =>
+            {
+                c.AddPolicy("Any", policy =>
+                {
+                    policy.AllowAnyOrigin()
+                    .AllowAnyMethod()
+                    .AllowAnyHeader()
+                    .AllowCredentials();
+                });
+
+                c.AddPolicy("Limit", policy =>
+                {
+                    policy
+                    .WithOrigins("localhost:4909")
+                    .WithMethods("get", "post", "put", "delete")
+                    //.WithHeaders("Authorization");
+                    .AllowAnyHeader();
+                });
+            });
+            #endregion
+
+            #region 性能 压缩
+            services.AddResponseCompression();
+            #endregion
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+        {
+            if (env.IsDevelopment())
+            {
+                app.UseDeveloperExceptionPage();
+            }
+            else
+            {
+                app.UseExceptionHandler("/Home/Error");
+                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+                app.UseHsts();
+            }
+            #region 解决Ubuntu Nginx 代理不能获取IP问题
+            app.UseForwardedHeaders(new ForwardedHeadersOptions
+            {
+                ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
+            });
+            #endregion
+            app.UseHttpsRedirection();
+            app.UseStaticFiles(new StaticFileOptions
+            {
+                ServeUnknownFileTypes = true
+                //ContentTypeProvider = new FileExtensionContentTypeProvider(new Dictionary<string, string>
+                //{
+                //  { ".apk","application/vnd.android.package-archive"},
+                //  { ".nupkg","application/zip"}
+                //})  //支持特殊文件下载处理
+            });
+            //自定义异常处理
+            app.UseMiddleware<ExceptionFilter>();
+            //认证
+            app.UseAuthentication();
+            //授权
+            app.UseMiddleware<JwtAuthorizationFilter>();
+
+            //性能压缩
+            app.UseResponseCompression();
+
+
+            app.UseCookiePolicy();
+
+            app.UseMvc(routes =>
+            {
+                routes.MapRoute(
+                    name: "default",
+                    template: "{controller=Home}/{action=Index}/{id?}");
+            });
+        }
+    }
+}

+ 8 - 0
HaBookCms.Admin/Views/Home/Index.cshtml

@@ -0,0 +1,8 @@
+@{
+    ViewData["Title"] = "Home Page";
+}
+
+<div class="text-center">
+    <h1 class="display-4">Welcome</h1>
+    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
+</div>

+ 6 - 0
HaBookCms.Admin/Views/Home/Privacy.cshtml

@@ -0,0 +1,6 @@
+@{
+    ViewData["Title"] = "Privacy Policy";
+}
+<h1>@ViewData["Title"]</h1>
+
+<p>Use this page to detail your site's privacy policy.</p>

+ 25 - 0
HaBookCms.Admin/Views/Shared/Error.cshtml

@@ -0,0 +1,25 @@
+@model ErrorViewModel
+@{
+    ViewData["Title"] = "Error";
+}
+
+<h1 class="text-danger">Error.</h1>
+<h2 class="text-danger">An error occurred while processing your request.</h2>
+
+@if (Model.ShowRequestId)
+{
+    <p>
+        <strong>Request ID:</strong> <code>@Model.RequestId</code>
+    </p>
+}
+
+<h3>Development Mode</h3>
+<p>
+    Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
+</p>
+<p>
+    <strong>The Development environment shouldn't be enabled for deployed applications.</strong>
+    It can result in displaying sensitive information from exceptions to end users.
+    For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
+    and restarting the app.
+</p>

+ 25 - 0
HaBookCms.Admin/Views/Shared/_CookieConsentPartial.cshtml

@@ -0,0 +1,25 @@
+@using Microsoft.AspNetCore.Http.Features
+
+@{
+    var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
+    var showBanner = !consentFeature?.CanTrack ?? false;
+    var cookieString = consentFeature?.CreateConsentCookie();
+}
+
+@if (showBanner)
+{
+    <div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
+        Use this space to summarize your privacy and cookie use policy. <a asp-area="" asp-controller="Home" asp-action="Privacy">Learn More</a>.
+        <button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
+            <span aria-hidden="true">Accept</span>
+        </button>
+    </div>
+    <script>
+        (function () {
+            var button = document.querySelector("#cookieConsent button[data-cookie-string]");
+            button.addEventListener("click", function (event) {
+                document.cookie = button.dataset.cookieString;
+            }, false);
+        })();
+    </script>
+}

+ 77 - 0
HaBookCms.Admin/Views/Shared/_Layout.cshtml

@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>@ViewData["Title"] - HaBookCms.Admin</title>
+
+    <environment include="Development">
+        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
+    </environment>
+    <environment exclude="Development">
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"
+              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
+              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
+              crossorigin="anonymous"
+              integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
+    </environment>
+    <link rel="stylesheet" href="~/css/site.css" />
+</head>
+<body>
+    <header>
+        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
+            <div class="container">
+                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">HaBookCms.Admin</a>
+                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
+                        aria-expanded="false" aria-label="Toggle navigation">
+                    <span class="navbar-toggler-icon"></span>
+                </button>
+                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
+                    <ul class="navbar-nav flex-grow-1">
+                        <li class="nav-item">
+                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
+                        </li>
+                        <li class="nav-item">
+                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+        </nav>
+    </header>
+    <div class="container">
+        <partial name="_CookieConsentPartial" />
+        <main role="main" class="pb-3">
+            @RenderBody()
+        </main>
+    </div>
+
+    <footer class="border-top footer text-muted">
+        <div class="container">
+            &copy; 2018 - HaBookCms.Admin - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
+        </div>
+    </footer>
+
+    <environment include="Development">
+        <script src="~/lib/jquery/dist/jquery.js"></script>
+        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
+    </environment>
+    <environment exclude="Development">
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
+                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
+                asp-fallback-test="window.jQuery"
+                crossorigin="anonymous"
+                integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
+        </script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js"
+                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"
+                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
+                crossorigin="anonymous"
+                integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
+        </script>
+    </environment>
+    <script src="~/js/site.js" asp-append-version="true"></script>
+
+    @RenderSection("Scripts", required: false)
+</body>
+</html>

+ 18 - 0
HaBookCms.Admin/Views/Shared/_ValidationScriptsPartial.cshtml

@@ -0,0 +1,18 @@
+<environment include="Development">
+    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
+    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
+</environment>
+<environment exclude="Development">
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"
+            asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
+            asp-fallback-test="window.jQuery && window.jQuery.validator"
+            crossorigin="anonymous"
+            integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A=">
+    </script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"
+            asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
+            asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
+            crossorigin="anonymous"
+            integrity="sha256-9GycpJnliUjJDVDqP0UEu/bsm9U+3dnQUH8+3W10vkY=">
+    </script>
+</environment>

+ 3 - 0
HaBookCms.Admin/Views/_ViewImports.cshtml

@@ -0,0 +1,3 @@
+@using HaBookCms.Admin
+@using HaBookCms.Admin.Models
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

+ 3 - 0
HaBookCms.Admin/Views/_ViewStart.cshtml

@@ -0,0 +1,3 @@
+@{
+    Layout = "_Layout";
+}

+ 9 - 0
HaBookCms.Admin/appsettings.Development.json

@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Debug",
+      "System": "Information",
+      "Microsoft": "Information"
+    }
+  }
+}

+ 40 - 0
HaBookCms.Admin/appsettings.json

@@ -0,0 +1,40 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Warning"
+    }
+  },
+  "AllowedHosts": "*",
+  //用户配置信息
+  "AppSettings": {
+    //Redis缓存
+    "RedisCaching": {
+      "KeyPrefix": "habook:cms",
+      "Enabled": true,
+      "DataBase": 1,
+      "ConnectionString": "teammodel.redis.cache.chinacloudapi.cn:6380,password=9wcTVDiAWiAf0IF5NOjZBvYrZe9JlbEw1E3F1QFcNbo=,ssl=True,abortConnect=False"
+    },
+    //数据库配置
+    "Azure": {
+      "TableStorageConnection": "DefaultEndpointsProtocol=https;AccountName=teammodelstorage;AccountKey=Yq7D4dE6cFuer2d2UZIccTA/i0c3sJ/6ITc8tNOyW+K5f+/lWw9GCos3Mxhj47PyWQgDL8YbVD63B9XcGtrMxQ==;EndpointSuffix=core.chinacloudapi.cn",
+      "CosmosDBConnection": {
+        "AccountEndpoint": "https://teammodelostest.documents.azure.cn:443/",
+        "AccountKey": "ReGoiHuTbU4Q31YYq4NaiormE6Ci71piT7OrvTzAuhrlgt63ajdtDZmwOZKzcz6gnwR326mJp53InY7rohepQQ=="
+      }
+    },
+    "Date": "2018-08-28",
+    "Author": "Blog.Core"
+  },
+  "JwtAuth": {
+    "SecurityKey": "b0a364cd88a7612870bb1d5f51712d43",
+    "Issuer": "HaBook.Cms.Admin",
+    "Audience": "wr",
+    "WebExp": 12,
+    "AppExp": 1440,
+    "MiniProgramExp": 1440,
+    "OtherExp": 6
+  },
+  "Cache": {
+    "IsUseRedis": true
+  }
+}

+ 56 - 0
HaBookCms.Admin/wwwroot/css/site.css

@@ -0,0 +1,56 @@
+/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
+for details on configuring this project to bundle and minify static web assets. */
+
+a.navbar-brand {
+  white-space: normal;
+  text-align: center;
+  word-break: break-all;
+}
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html {
+  font-size: 14px;
+}
+@media (min-width: 768px) {
+  html {
+    font-size: 16px;
+  }
+}
+
+.border-top {
+  border-top: 1px solid #e5e5e5;
+}
+.border-bottom {
+  border-bottom: 1px solid #e5e5e5;
+}
+
+.box-shadow {
+  box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
+}
+
+button.accept-policy {
+  font-size: 1rem;
+  line-height: inherit;
+}
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html {
+  position: relative;
+  min-height: 100%;
+}
+
+body {
+  /* Margin bottom by footer height */
+  margin-bottom: 60px;
+}
+.footer {
+  position: absolute;
+  bottom: 0;
+  width: 100%;
+  white-space: nowrap;
+  /* Set the fixed height of the footer here */
+  height: 60px;
+  line-height: 60px; /* Vertically center the text there */
+}

BIN
HaBookCms.Admin/wwwroot/favicon.ico


+ 4 - 0
HaBookCms.Admin/wwwroot/js/site.js

@@ -0,0 +1,4 @@
+// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
+// for details on configuring this project to bundle and minify static web assets.
+
+// Write your JavaScript code.

+ 22 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2011-2018 Twitter, Inc.
+Copyright (c) 2011-2018 The Bootstrap Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1912 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map


+ 331 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css

@@ -0,0 +1,331 @@
+/*!
+ * Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
+ * Copyright 2011-2018 The Bootstrap Authors
+ * Copyright 2011-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
+ */
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+}
+
+html {
+  font-family: sans-serif;
+  line-height: 1.15;
+  -webkit-text-size-adjust: 100%;
+  -ms-text-size-adjust: 100%;
+  -ms-overflow-style: scrollbar;
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+@-ms-viewport {
+  width: device-width;
+}
+
+article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
+  display: block;
+}
+
+body {
+  margin: 0;
+  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+  font-size: 1rem;
+  font-weight: 400;
+  line-height: 1.5;
+  color: #212529;
+  text-align: left;
+  background-color: #fff;
+}
+
+[tabindex="-1"]:focus {
+  outline: 0 !important;
+}
+
+hr {
+  box-sizing: content-box;
+  height: 0;
+  overflow: visible;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  margin-top: 0;
+  margin-bottom: 0.5rem;
+}
+
+p {
+  margin-top: 0;
+  margin-bottom: 1rem;
+}
+
+abbr[title],
+abbr[data-original-title] {
+  text-decoration: underline;
+  -webkit-text-decoration: underline dotted;
+  text-decoration: underline dotted;
+  cursor: help;
+  border-bottom: 0;
+}
+
+address {
+  margin-bottom: 1rem;
+  font-style: normal;
+  line-height: inherit;
+}
+
+ol,
+ul,
+dl {
+  margin-top: 0;
+  margin-bottom: 1rem;
+}
+
+ol ol,
+ul ul,
+ol ul,
+ul ol {
+  margin-bottom: 0;
+}
+
+dt {
+  font-weight: 700;
+}
+
+dd {
+  margin-bottom: .5rem;
+  margin-left: 0;
+}
+
+blockquote {
+  margin: 0 0 1rem;
+}
+
+dfn {
+  font-style: italic;
+}
+
+b,
+strong {
+  font-weight: bolder;
+}
+
+small {
+  font-size: 80%;
+}
+
+sub,
+sup {
+  position: relative;
+  font-size: 75%;
+  line-height: 0;
+  vertical-align: baseline;
+}
+
+sub {
+  bottom: -.25em;
+}
+
+sup {
+  top: -.5em;
+}
+
+a {
+  color: #007bff;
+  text-decoration: none;
+  background-color: transparent;
+  -webkit-text-decoration-skip: objects;
+}
+
+a:hover {
+  color: #0056b3;
+  text-decoration: underline;
+}
+
+a:not([href]):not([tabindex]) {
+  color: inherit;
+  text-decoration: none;
+}
+
+a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
+  color: inherit;
+  text-decoration: none;
+}
+
+a:not([href]):not([tabindex]):focus {
+  outline: 0;
+}
+
+pre,
+code,
+kbd,
+samp {
+  font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+  font-size: 1em;
+}
+
+pre {
+  margin-top: 0;
+  margin-bottom: 1rem;
+  overflow: auto;
+  -ms-overflow-style: scrollbar;
+}
+
+figure {
+  margin: 0 0 1rem;
+}
+
+img {
+  vertical-align: middle;
+  border-style: none;
+}
+
+svg {
+  overflow: hidden;
+  vertical-align: middle;
+}
+
+table {
+  border-collapse: collapse;
+}
+
+caption {
+  padding-top: 0.75rem;
+  padding-bottom: 0.75rem;
+  color: #6c757d;
+  text-align: left;
+  caption-side: bottom;
+}
+
+th {
+  text-align: inherit;
+}
+
+label {
+  display: inline-block;
+  margin-bottom: 0.5rem;
+}
+
+button {
+  border-radius: 0;
+}
+
+button:focus {
+  outline: 1px dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+}
+
+input,
+button,
+select,
+optgroup,
+textarea {
+  margin: 0;
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+}
+
+button,
+input {
+  overflow: visible;
+}
+
+button,
+select {
+  text-transform: none;
+}
+
+button,
+html [type="button"],
+[type="reset"],
+[type="submit"] {
+  -webkit-appearance: button;
+}
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+  padding: 0;
+  border-style: none;
+}
+
+input[type="radio"],
+input[type="checkbox"] {
+  box-sizing: border-box;
+  padding: 0;
+}
+
+input[type="date"],
+input[type="time"],
+input[type="datetime-local"],
+input[type="month"] {
+  -webkit-appearance: listbox;
+}
+
+textarea {
+  overflow: auto;
+  resize: vertical;
+}
+
+fieldset {
+  min-width: 0;
+  padding: 0;
+  margin: 0;
+  border: 0;
+}
+
+legend {
+  display: block;
+  width: 100%;
+  max-width: 100%;
+  padding: 0;
+  margin-bottom: .5rem;
+  font-size: 1.5rem;
+  line-height: inherit;
+  color: inherit;
+  white-space: normal;
+}
+
+progress {
+  vertical-align: baseline;
+}
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+
+[type="search"] {
+  outline-offset: -2px;
+  -webkit-appearance: none;
+}
+
+[type="search"]::-webkit-search-cancel-button,
+[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+
+::-webkit-file-upload-button {
+  font: inherit;
+  -webkit-appearance: button;
+}
+
+output {
+  display: inline-block;
+}
+
+summary {
+  display: list-item;
+  cursor: pointer;
+}
+
+template {
+  display: none;
+}
+
+[hidden] {
+  display: none !important;
+}
+/*# sourceMappingURL=bootstrap-reboot.css.map */

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 8 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 9030 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6461 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 3944 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/bootstrap/dist/js/bootstrap.min.js.map


+ 12 - 0
HaBookCms.Admin/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt

@@ -0,0 +1,12 @@
+Copyright (c) .NET Foundation. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+these files except in compliance with the License. You may obtain a copy of the
+License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software distributed
+under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+CONDITIONS OF ANY KIND, either express or implied. See the License for the
+specific language governing permissions and limitations under the License.

+ 432 - 0
HaBookCms.Admin/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js

@@ -0,0 +1,432 @@
+// Unobtrusive validation support library for jQuery and jQuery Validate
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+// @version v3.2.11
+
+/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
+/*global document: false, jQuery: false */
+
+(function (factory) {
+    if (typeof define === 'function' && define.amd) {
+        // AMD. Register as an anonymous module.
+        define("jquery.validate.unobtrusive", ['jquery-validation'], factory);
+    } else if (typeof module === 'object' && module.exports) {
+        // CommonJS-like environments that support module.exports     
+        module.exports = factory(require('jquery-validation'));
+    } else {
+        // Browser global
+        jQuery.validator.unobtrusive = factory(jQuery);
+    }
+}(function ($) {
+    var $jQval = $.validator,
+        adapters,
+        data_validation = "unobtrusiveValidation";
+
+    function setValidationValues(options, ruleName, value) {
+        options.rules[ruleName] = value;
+        if (options.message) {
+            options.messages[ruleName] = options.message;
+        }
+    }
+
+    function splitAndTrim(value) {
+        return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
+    }
+
+    function escapeAttributeValue(value) {
+        // As mentioned on http://api.jquery.com/category/selectors/
+        return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
+    }
+
+    function getModelPrefix(fieldName) {
+        return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
+    }
+
+    function appendModelPrefix(value, prefix) {
+        if (value.indexOf("*.") === 0) {
+            value = value.replace("*.", prefix);
+        }
+        return value;
+    }
+
+    function onError(error, inputElement) {  // 'this' is the form element
+        var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
+            replaceAttrValue = container.attr("data-valmsg-replace"),
+            replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
+
+        container.removeClass("field-validation-valid").addClass("field-validation-error");
+        error.data("unobtrusiveContainer", container);
+
+        if (replace) {
+            container.empty();
+            error.removeClass("input-validation-error").appendTo(container);
+        }
+        else {
+            error.hide();
+        }
+    }
+
+    function onErrors(event, validator) {  // 'this' is the form element
+        var container = $(this).find("[data-valmsg-summary=true]"),
+            list = container.find("ul");
+
+        if (list && list.length && validator.errorList.length) {
+            list.empty();
+            container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
+
+            $.each(validator.errorList, function () {
+                $("<li />").html(this.message).appendTo(list);
+            });
+        }
+    }
+
+    function onSuccess(error) {  // 'this' is the form element
+        var container = error.data("unobtrusiveContainer");
+
+        if (container) {
+            var replaceAttrValue = container.attr("data-valmsg-replace"),
+                replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
+
+            container.addClass("field-validation-valid").removeClass("field-validation-error");
+            error.removeData("unobtrusiveContainer");
+
+            if (replace) {
+                container.empty();
+            }
+        }
+    }
+
+    function onReset(event) {  // 'this' is the form element
+        var $form = $(this),
+            key = '__jquery_unobtrusive_validation_form_reset';
+        if ($form.data(key)) {
+            return;
+        }
+        // Set a flag that indicates we're currently resetting the form.
+        $form.data(key, true);
+        try {
+            $form.data("validator").resetForm();
+        } finally {
+            $form.removeData(key);
+        }
+
+        $form.find(".validation-summary-errors")
+            .addClass("validation-summary-valid")
+            .removeClass("validation-summary-errors");
+        $form.find(".field-validation-error")
+            .addClass("field-validation-valid")
+            .removeClass("field-validation-error")
+            .removeData("unobtrusiveContainer")
+            .find(">*")  // If we were using valmsg-replace, get the underlying error
+            .removeData("unobtrusiveContainer");
+    }
+
+    function validationInfo(form) {
+        var $form = $(form),
+            result = $form.data(data_validation),
+            onResetProxy = $.proxy(onReset, form),
+            defaultOptions = $jQval.unobtrusive.options || {},
+            execInContext = function (name, args) {
+                var func = defaultOptions[name];
+                func && $.isFunction(func) && func.apply(form, args);
+            };
+
+        if (!result) {
+            result = {
+                options: {  // options structure passed to jQuery Validate's validate() method
+                    errorClass: defaultOptions.errorClass || "input-validation-error",
+                    errorElement: defaultOptions.errorElement || "span",
+                    errorPlacement: function () {
+                        onError.apply(form, arguments);
+                        execInContext("errorPlacement", arguments);
+                    },
+                    invalidHandler: function () {
+                        onErrors.apply(form, arguments);
+                        execInContext("invalidHandler", arguments);
+                    },
+                    messages: {},
+                    rules: {},
+                    success: function () {
+                        onSuccess.apply(form, arguments);
+                        execInContext("success", arguments);
+                    }
+                },
+                attachValidation: function () {
+                    $form
+                        .off("reset." + data_validation, onResetProxy)
+                        .on("reset." + data_validation, onResetProxy)
+                        .validate(this.options);
+                },
+                validate: function () {  // a validation function that is called by unobtrusive Ajax
+                    $form.validate();
+                    return $form.valid();
+                }
+            };
+            $form.data(data_validation, result);
+        }
+
+        return result;
+    }
+
+    $jQval.unobtrusive = {
+        adapters: [],
+
+        parseElement: function (element, skipAttach) {
+            /// <summary>
+            /// Parses a single HTML element for unobtrusive validation attributes.
+            /// </summary>
+            /// <param name="element" domElement="true">The HTML element to be parsed.</param>
+            /// <param name="skipAttach" type="Boolean">[Optional] true to skip attaching the
+            /// validation to the form. If parsing just this single element, you should specify true.
+            /// If parsing several elements, you should specify false, and manually attach the validation
+            /// to the form when you are finished. The default is false.</param>
+            var $element = $(element),
+                form = $element.parents("form")[0],
+                valInfo, rules, messages;
+
+            if (!form) {  // Cannot do client-side validation without a form
+                return;
+            }
+
+            valInfo = validationInfo(form);
+            valInfo.options.rules[element.name] = rules = {};
+            valInfo.options.messages[element.name] = messages = {};
+
+            $.each(this.adapters, function () {
+                var prefix = "data-val-" + this.name,
+                    message = $element.attr(prefix),
+                    paramValues = {};
+
+                if (message !== undefined) {  // Compare against undefined, because an empty message is legal (and falsy)
+                    prefix += "-";
+
+                    $.each(this.params, function () {
+                        paramValues[this] = $element.attr(prefix + this);
+                    });
+
+                    this.adapt({
+                        element: element,
+                        form: form,
+                        message: message,
+                        params: paramValues,
+                        rules: rules,
+                        messages: messages
+                    });
+                }
+            });
+
+            $.extend(rules, { "__dummy__": true });
+
+            if (!skipAttach) {
+                valInfo.attachValidation();
+            }
+        },
+
+        parse: function (selector) {
+            /// <summary>
+            /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
+            /// with the [data-val=true] attribute value and enables validation according to the data-val-*
+            /// attribute values.
+            /// </summary>
+            /// <param name="selector" type="String">Any valid jQuery selector.</param>
+
+            // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
+            // element with data-val=true
+            var $selector = $(selector),
+                $forms = $selector.parents()
+                    .addBack()
+                    .filter("form")
+                    .add($selector.find("form"))
+                    .has("[data-val=true]");
+
+            $selector.find("[data-val=true]").each(function () {
+                $jQval.unobtrusive.parseElement(this, true);
+            });
+
+            $forms.each(function () {
+                var info = validationInfo(this);
+                if (info) {
+                    info.attachValidation();
+                }
+            });
+        }
+    };
+
+    adapters = $jQval.unobtrusive.adapters;
+
+    adapters.add = function (adapterName, params, fn) {
+        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.</summary>
+        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
+        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
+        /// <param name="params" type="Array" optional="true">[Optional] An array of parameter names (strings) that will
+        /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
+        /// mmmm is the parameter name).</param>
+        /// <param name="fn" type="Function">The function to call, which adapts the values from the HTML
+        /// attributes into jQuery Validate rules and/or messages.</param>
+        /// <returns type="jQuery.validator.unobtrusive.adapters" />
+        if (!fn) {  // Called with no params, just a function
+            fn = params;
+            params = [];
+        }
+        this.push({ name: adapterName, params: params, adapt: fn });
+        return this;
+    };
+
+    adapters.addBool = function (adapterName, ruleName) {
+        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
+        /// the jQuery Validate validation rule has no parameter values.</summary>
+        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
+        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
+        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
+        /// of adapterName will be used instead.</param>
+        /// <returns type="jQuery.validator.unobtrusive.adapters" />
+        return this.add(adapterName, function (options) {
+            setValidationValues(options, ruleName || adapterName, true);
+        });
+    };
+
+    adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
+        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
+        /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
+        /// one for min-and-max). The HTML parameters are expected to be named -min and -max.</summary>
+        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
+        /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).</param>
+        /// <param name="minRuleName" type="String">The name of the jQuery Validate rule to be used when you only
+        /// have a minimum value.</param>
+        /// <param name="maxRuleName" type="String">The name of the jQuery Validate rule to be used when you only
+        /// have a maximum value.</param>
+        /// <param name="minMaxRuleName" type="String">The name of the jQuery Validate rule to be used when you
+        /// have both a minimum and maximum value.</param>
+        /// <param name="minAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
+        /// contains the minimum value. The default is "min".</param>
+        /// <param name="maxAttribute" type="String" optional="true">[Optional] The name of the HTML attribute that
+        /// contains the maximum value. The default is "max".</param>
+        /// <returns type="jQuery.validator.unobtrusive.adapters" />
+        return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
+            var min = options.params.min,
+                max = options.params.max;
+
+            if (min && max) {
+                setValidationValues(options, minMaxRuleName, [min, max]);
+            }
+            else if (min) {
+                setValidationValues(options, minRuleName, min);
+            }
+            else if (max) {
+                setValidationValues(options, maxRuleName, max);
+            }
+        });
+    };
+
+    adapters.addSingleVal = function (adapterName, attribute, ruleName) {
+        /// <summary>Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
+        /// the jQuery Validate validation rule has a single value.</summary>
+        /// <param name="adapterName" type="String">The name of the adapter to be added. This matches the name used
+        /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).</param>
+        /// <param name="attribute" type="String">[Optional] The name of the HTML attribute that contains the value.
+        /// The default is "val".</param>
+        /// <param name="ruleName" type="String" optional="true">[Optional] The name of the jQuery Validate rule. If not provided, the value
+        /// of adapterName will be used instead.</param>
+        /// <returns type="jQuery.validator.unobtrusive.adapters" />
+        return this.add(adapterName, [attribute || "val"], function (options) {
+            setValidationValues(options, ruleName || adapterName, options.params[attribute]);
+        });
+    };
+
+    $jQval.addMethod("__dummy__", function (value, element, params) {
+        return true;
+    });
+
+    $jQval.addMethod("regex", function (value, element, params) {
+        var match;
+        if (this.optional(element)) {
+            return true;
+        }
+
+        match = new RegExp(params).exec(value);
+        return (match && (match.index === 0) && (match[0].length === value.length));
+    });
+
+    $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
+        var match;
+        if (nonalphamin) {
+            match = value.match(/\W/g);
+            match = match && match.length >= nonalphamin;
+        }
+        return match;
+    });
+
+    if ($jQval.methods.extension) {
+        adapters.addSingleVal("accept", "mimtype");
+        adapters.addSingleVal("extension", "extension");
+    } else {
+        // for backward compatibility, when the 'extension' validation method does not exist, such as with versions
+        // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
+        // validating the extension, and ignore mime-type validations as they are not supported.
+        adapters.addSingleVal("extension", "extension", "accept");
+    }
+
+    adapters.addSingleVal("regex", "pattern");
+    adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
+    adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
+    adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
+    adapters.add("equalto", ["other"], function (options) {
+        var prefix = getModelPrefix(options.element.name),
+            other = options.params.other,
+            fullOtherName = appendModelPrefix(other, prefix),
+            element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
+
+        setValidationValues(options, "equalTo", element);
+    });
+    adapters.add("required", function (options) {
+        // jQuery Validate equates "required" with "mandatory" for checkbox elements
+        if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
+            setValidationValues(options, "required", true);
+        }
+    });
+    adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
+        var value = {
+            url: options.params.url,
+            type: options.params.type || "GET",
+            data: {}
+        },
+            prefix = getModelPrefix(options.element.name);
+
+        $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
+            var paramName = appendModelPrefix(fieldName, prefix);
+            value.data[paramName] = function () {
+                var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
+                // For checkboxes and radio buttons, only pick up values from checked fields.
+                if (field.is(":checkbox")) {
+                    return field.filter(":checked").val() || field.filter(":hidden").val() || '';
+                }
+                else if (field.is(":radio")) {
+                    return field.filter(":checked").val() || '';
+                }
+                return field.val();
+            };
+        });
+
+        setValidationValues(options, "remote", value);
+    });
+    adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
+        if (options.params.min) {
+            setValidationValues(options, "minlength", options.params.min);
+        }
+        if (options.params.nonalphamin) {
+            setValidationValues(options, "nonalphamin", options.params.nonalphamin);
+        }
+        if (options.params.regex) {
+            setValidationValues(options, "regex", options.params.regex);
+        }
+    });
+    adapters.add("fileextensions", ["extensions"], function (options) {
+        setValidationValues(options, "extension", options.params.extensions);
+    });
+
+    $(function () {
+        $jQval.unobtrusive.parse(document);
+    });
+
+    return $jQval.unobtrusive;
+}));

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 5 - 0
HaBookCms.Admin/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js


+ 22 - 0
HaBookCms.Admin/wwwroot/lib/jquery-validation/LICENSE.md

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+=====================
+
+Copyright Jörn Zaefferer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1158 - 0
HaBookCms.Admin/wwwroot/lib/jquery-validation/dist/additional-methods.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 4 - 0
HaBookCms.Admin/wwwroot/lib/jquery-validation/dist/additional-methods.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1601 - 0
HaBookCms.Admin/wwwroot/lib/jquery-validation/dist/jquery.validate.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 4 - 0
HaBookCms.Admin/wwwroot/lib/jquery-validation/dist/jquery.validate.min.js


+ 36 - 0
HaBookCms.Admin/wwwroot/lib/jquery/LICENSE.txt

@@ -0,0 +1,36 @@
+Copyright JS Foundation and other contributors, https://js.foundation/
+
+This software consists of voluntary contributions made by many
+individuals. For exact contribution history, see the revision history
+available at https://github.com/jquery/jquery
+
+The following license applies to all parts of this software except as
+documented below:
+
+====
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+====
+
+All files located in the node_modules and external directories are
+externally maintained libraries used by this software which have their
+own licenses; we recommend you read them, as their terms may differ from
+the terms above.

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 10364 - 0
HaBookCms.Admin/wwwroot/lib/jquery/dist/jquery.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 0
HaBookCms.Admin/wwwroot/lib/jquery/dist/jquery.min.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Admin/wwwroot/lib/jquery/dist/jquery.min.map


+ 8 - 0
HaBookCms.AzureCosmos/Class1.cs

@@ -0,0 +1,8 @@
+using System;
+
+namespace HaBookCms.AzureCosmos
+{
+    public class Class1
+    {
+    }
+}

+ 7 - 0
HaBookCms.AzureCosmos/HaBookCms.AzureCosmos.csproj

@@ -0,0 +1,7 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
+  </PropertyGroup>
+
+</Project>

+ 8 - 0
HaBookCms.AzureStorage/Class1.cs

@@ -0,0 +1,8 @@
+using System;
+
+namespace HaBookCms.AzureStorage
+{
+    public class Class1
+    {
+    }
+}

+ 7 - 0
HaBookCms.AzureStorage/HaBookCms.AzureStorage.csproj

@@ -0,0 +1,7 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
+  </PropertyGroup>
+
+</Project>

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 218 - 0
HaBookCms.Common/CryptHelper/AESCrypt.cs


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 338 - 0
HaBookCms.Common/CryptHelper/AESEncrypt.cs


+ 97 - 0
HaBookCms.Common/CryptHelper/DESCrypt.cs

@@ -0,0 +1,97 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace HaBookCms.Common.CryptHelper
+{
+
+    public class DESCrypt
+    {
+        #region  ========算法========
+        private static string key;//密钥
+        static DESCrypt()
+        {
+            key = "HaBookTeamModel2019";
+        }
+        private static byte[] Keys = new byte[] { 0x12, 0x34, 0x56, 120, 0x90, 0xab, 0xcd, 0xef };//8个bit位,是DES算法的初始化向量  加解密钥也是8位;
+        /// <summary>
+        /// 解密字符串
+        /// </summary>
+        /// <param name="decryptString">是要被解密的密文数据</param>
+        /// <param name="decryptKey">DES算法的工作密钥</param>
+        /// <returns>明文</returns>
+        public static string Decrypt(string decryptString, string decryptKey)
+        {
+            try
+            {
+                decryptKey = Utils.GetSubString(decryptKey, 8, "");
+                decryptKey = decryptKey.PadRight(8, ' ');
+                byte[] bytes = Encoding.UTF8.GetBytes(decryptKey);
+                byte[] keys = Keys;
+                byte[] buffer = Convert.FromBase64String(decryptString);
+                DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
+                MemoryStream stream = new MemoryStream();
+                CryptoStream stream2 = new CryptoStream(stream, provider.CreateDecryptor(bytes, keys), CryptoStreamMode.Write);
+                stream2.Write(buffer, 0, buffer.Length);
+                stream2.FlushFinalBlock();
+                return Encoding.UTF8.GetString(stream.ToArray());
+            }
+            catch
+            {
+                return "";
+            }
+        }
+
+        /// <summary>
+        /// 加密
+        /// </summary>
+        /// <param name="decryptString">要被加密数据</param>
+        /// <param name="decryptKey">DES算法的工作密钥</param>
+        /// <returns>密文</returns>
+        public static string Encrypt(string encryptString, string encryptKey)
+        {
+            encryptKey = Utils.GetSubString(encryptKey, 8, "");
+            encryptKey = encryptKey.PadRight(8, ' ');
+            byte[] bytes = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));
+            byte[] keys = Keys;
+            byte[] buffer = Encoding.UTF8.GetBytes(encryptString);
+            DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
+            MemoryStream stream = new MemoryStream();
+            CryptoStream stream2 = new CryptoStream(stream, provider.CreateEncryptor(bytes, keys), CryptoStreamMode.Write);
+            stream2.Write(buffer, 0, buffer.Length);
+            stream2.FlushFinalBlock();
+            return Convert.ToBase64String(stream.ToArray());//Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节。
+            //Base64编码可用于在HTTP环境下传递较长的标识信息,如较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数,或者将二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。
+        }
+        #endregion
+
+        #region ========加密========
+
+        /// <summary>
+        /// 加密
+        /// </summary>
+        /// <param name="Text"></param>
+        /// <returns></returns>
+        public static string Encrypt(string Text)
+        {
+            return Encrypt(Text, key);
+        }
+        #endregion
+
+        #region ========解密========
+
+        /// <summary>
+        /// 解密
+        /// </summary>
+        /// <param name="Text"></param>
+        /// <returns></returns>
+        public static string Decrypt(string Text)
+        {
+            return Decrypt(Text, key);
+        }
+        #endregion
+
+    }
+}

+ 49 - 0
HaBookCms.Common/CryptHelper/Md5Crypt.cs

@@ -0,0 +1,49 @@
+using System;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace HaBookCms.Common.CryptHelper
+{
+
+    public class Md5Crypt
+    {
+        #region MD5加密字符串处理
+        /// <summary>
+        /// MD5加密字符串处理
+        /// </summary>
+        /// <param name="half">加密是16位还是32位;如果为true为16位</param>
+        /// <param name="input">待加密码字符串</param>
+        /// <returns></returns>
+        public static string Encrypt(string input, bool half)
+        {
+            using (var md5 = MD5.Create())
+            {
+                var result = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
+                var strResult = BitConverter.ToString(result);
+                strResult = strResult.Replace("-", "");
+                if (half)//16位MD5加密(取32位加密的9~25字符)
+                {
+                    strResult = strResult?.Substring(8, 16);
+                }
+                return strResult;
+            }
+        }
+        #endregion
+
+        /// <summary>
+        /// MD5加密
+        /// </summary>
+        /// <param name="strPwd">加密的字符串</param>
+        /// <returns></returns>
+        public static string Encrypt(string strPwd)
+        {
+            MD5 md5 = new MD5CryptoServiceProvider();
+            byte[] data = System.Text.Encoding.Default.GetBytes(strPwd);
+            byte[] result = md5.ComputeHash(data);
+            string ret = "";
+            for (int i = 0; i < result.Length; i++)
+                ret += result[i].ToString("x").PadLeft(2, '0');
+            return ret;
+        }
+    }
+}

+ 64 - 0
HaBookCms.Common/CryptHelper/RSACrypt.cs

@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Security.Cryptography;
+using System.Text;
+using XC.Framework.Security.RSAUtil;
+
+namespace HaBookCms.Common.CryptHelper
+{
+
+    /// <summary>
+    /// RSA加密解密
+    /// https://github.com/stulzq/RSAUtil
+    /// </summary>
+    public class RSACrypt
+    {
+
+        private readonly RsaPkcs1Util _RsaUtil;
+        private readonly Encoding _encoding;
+
+        /// <summary>
+        /// 获得私钥和公钥
+        /// [0]=privateKey  私钥 
+        /// [1]=publicKey  公钥
+        /// </summary>
+        /// <returns></returns>
+        public static List<string> GetKey()
+        {
+            return RsaKeyGenerator.Pkcs1Key(2048, true);
+        }
+
+        /// <summary>
+        /// 实例化
+        /// </summary>
+        /// <param name="encoding">编码类型</param>
+        /// <param name="privateKey">私钥</param>
+        /// <param name="publicKey">公钥</param>
+        public RSACrypt(string privateKey, string publicKey)
+        {
+            _encoding = Encoding.UTF8;
+            _RsaUtil = new RsaPkcs1Util(_encoding, publicKey, privateKey, 1024);
+        }
+
+        /// <summary>
+        /// 加密
+        /// </summary>
+        /// <param name="code">加密代码</param>
+        /// <returns></returns>
+        public string Encrypt(string code)
+        {
+            return _RsaUtil.Encrypt(code, RSAEncryptionPadding.Pkcs1);
+        }
+
+        /// <summary>
+        /// 解密
+        /// </summary>
+        /// <param name="code">解密代码</param>
+        /// <returns></returns>
+        public string Decrypt(string code)
+        {
+            return _RsaUtil.Decrypt(code, RSAEncryptionPadding.Pkcs1);
+        }
+
+    }
+}

+ 753 - 0
HaBookCms.Common/FileHelper/FileHelper.cs

@@ -0,0 +1,753 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.IO;
+using System.Net;
+using System.Text;
+
+namespace HaBookCms.Common.FileHelper
+{
+    public class FileHelper
+    {
+        #region 获取文件到集合中
+        /// <summary>
+        /// 读取指定位置文件列表到集合中
+        /// </summary>
+        /// <param name="path">指定路径</param>
+        /// <returns></returns>
+        public static DataTable GetFileTable(string path)
+        {
+            DataTable dt = new DataTable();
+            dt.Columns.Add("name", typeof(string));
+            dt.Columns.Add("ext", typeof(string));
+            dt.Columns.Add("size", typeof(long));
+            dt.Columns.Add("time", typeof(DateTime));
+
+            DirectoryInfo dirinfo = new DirectoryInfo(path);
+            FileInfo fi;
+            DirectoryInfo dir;
+            string FileName, FileExt;
+            long FileSize = 0;
+            DateTime FileModify;
+            try
+            {
+                foreach (FileSystemInfo fsi in dirinfo.GetFileSystemInfos())
+                {
+                    FileName = string.Empty;
+                    FileExt = string.Empty;
+                    if (fsi is FileInfo)
+                    {
+                        fi = (FileInfo)fsi;
+                        //获取文件名称
+                        FileName = fi.Name;
+                        //获取文件扩展名
+                        FileExt = fi.Extension;
+                        //获取文件大小
+                        FileSize = fi.Length;
+                        //获取文件最后修改时间
+                        FileModify = fi.LastWriteTime;
+                    }
+                    else
+                    {
+                        dir = (DirectoryInfo)fsi;
+                        //获取目录名
+                        FileName = dir.Name;
+                        //获取目录最后修改时间
+                        FileModify = dir.LastWriteTime;
+                        //设置目录文件为文件夹
+                        FileExt = "文件夹";
+                    }
+                    DataRow dr = dt.NewRow();
+                    dr["name"] = FileName;
+                    dr["ext"] = FileExt;
+                    dr["size"] = FileSize;
+                    dr["time"] = FileModify;
+                    dt.Rows.Add(dr);
+                }
+            }
+            catch
+            {
+
+                throw;
+            }
+            return dt;
+        }
+
+        #endregion
+
+        #region 检测指定路径是否存在
+        /// <summary>
+        /// 检测指定路径是否存在
+        /// </summary>
+        /// <param name="path">目录的绝对路径</param> 
+        public static bool IsExistDirectory(string path)
+        {
+            return Directory.Exists(path);
+        }
+        #endregion
+
+        #region 检测指定文件是否存在,如果存在则返回true
+        /// <summary>
+        /// 检测指定文件是否存在,如果存在则返回true
+        /// </summary>
+        /// <param name="filePath">文件的绝对路径</param>  
+        public static bool IsExistFile(string filePath)
+        {
+            return File.Exists(filePath);
+        }
+        #endregion
+
+        #region 创建文件夹
+        /// <summary>
+        /// 创建文件夹
+        /// </summary>
+        /// <param name="folderPath">文件夹的绝对路径</param>
+        public static void CreateFolder(string folderPath)
+        {
+            if (!IsExistDirectory(folderPath))
+            {
+                Directory.CreateDirectory(folderPath);
+            }
+        }
+        #endregion 
+
+        #region 判断上传文件后缀名
+        /// <summary>
+        /// 判断上传文件后缀名
+        /// </summary>
+        /// <param name="strExtension">后缀名</param>
+        public static bool IsCanEdit(string strExtension)
+        {
+            strExtension = strExtension.ToLower();
+            if (strExtension.LastIndexOf(".", StringComparison.Ordinal) >= 0)
+            {
+                strExtension = strExtension.Substring(strExtension.LastIndexOf(".", StringComparison.Ordinal));
+            }
+            else
+            {
+                strExtension = ".txt";
+            }
+            string[] strArray = new string[] { ".htm", ".html", ".txt", ".js", ".css", ".xml", ".sitemap" };
+            for (int i = 0; i < strArray.Length; i++)
+            {
+                if (strExtension.Equals(strArray[i]))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+
+        public static bool IsSafeName(string strExtension)
+        {
+            strExtension = strExtension.ToLower();
+            if (strExtension.LastIndexOf(".") >= 0)
+            {
+                strExtension = strExtension.Substring(strExtension.LastIndexOf("."));
+            }
+            else
+            {
+                strExtension = ".txt";
+            }
+            string[] strArray = new string[] { ".jpg", ".gif", ".png" };
+            for (int i = 0; i < strArray.Length; i++)
+            {
+                if (strExtension.Equals(strArray[i]))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public static bool IsZipName(string strExtension)
+        {
+            strExtension = strExtension.ToLower();
+            if (strExtension.LastIndexOf(".") >= 0)
+            {
+                strExtension = strExtension.Substring(strExtension.LastIndexOf("."));
+            }
+            else
+            {
+                strExtension = ".txt";
+            }
+            string[] strArray = new string[] { ".zip", ".rar" };
+            for (int i = 0; i < strArray.Length; i++)
+            {
+                if (strExtension.Equals(strArray[i]))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+        #endregion
+
+        #region 创建文件夹
+        /// <summary>
+        /// 创建文件夹
+        /// </summary>
+        /// <param name="fileName">文件的绝对路径</param>
+        public static void CreateSuffic(string fileName)
+        {
+            try
+            {
+                if (!Directory.Exists(fileName))
+                {
+                    Directory.CreateDirectory(fileName);
+                }
+            }
+            catch (Exception ex)
+            {
+
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// 创建文件夹
+        /// </summary>
+        /// <param name="fileName">文件的绝对路径</param>
+        public static void CreateFiles(string fileName)
+        {
+            try
+            {
+                //判断文件是否存在,不存在创建该文件
+                if (!IsExistFile(fileName))
+                {
+                    FileInfo file = new FileInfo(fileName);
+                    FileStream fs = file.Create();
+                    fs.Close();
+                }
+            }
+            catch (Exception ex)
+            {
+
+                throw ex;
+            }
+        }
+
+        /// <summary>
+        /// 创建一个文件,并将字节流写入文件。
+        /// </summary>
+        /// <param name="filePath">文件的绝对路径</param>
+        /// <param name="buffer">二进制流数据</param>
+        public static void CreateFile(string filePath, byte[] buffer)
+        {
+            try
+            {
+                //判断文件是否存在,不存在创建该文件
+                if (!IsExistFile(filePath))
+                {
+                    FileInfo file = new FileInfo(filePath);
+                    FileStream fs = file.Create();
+                    fs.Write(buffer, 0, buffer.Length);
+                    fs.Close();
+                }
+                else
+                {
+                    File.WriteAllBytes(filePath, buffer);
+                }
+            }
+            catch (Exception ex)
+            {
+
+                throw ex;
+            }
+        }
+        #endregion
+
+        #region 将文件移动到指定目录
+        /// <summary>
+        /// 将文件移动到指定目录
+        /// </summary>
+        /// <param name="sourceFilePath">需要移动的源文件的绝对路径</param>
+        /// <param name="descDirectoryPath">移动到的目录的绝对路径</param>
+        public static void Move(string sourceFilePath, string descDirectoryPath)
+        {
+            string sourceName = GetFileName(sourceFilePath);
+            if (IsExistDirectory(descDirectoryPath))
+            {
+                //如果目标中存在同名文件,则删除
+                if (IsExistFile(descDirectoryPath + "\\" + sourceFilePath))
+                {
+                    DeleteFile(descDirectoryPath + "\\" + sourceFilePath);
+                }
+                else
+                {
+                    //将文件移动到指定目录
+                    File.Move(sourceFilePath, descDirectoryPath + "\\" + sourceFilePath);
+                }
+            }
+        }
+        #endregion
+
+        # region 将源文件的内容复制到目标文件中
+        /// <summary>
+        /// 将源文件的内容复制到目标文件中
+        /// </summary>
+        /// <param name="sourceFilePath">源文件的绝对路径</param>
+        /// <param name="descDirectoryPath">目标文件的绝对路径</param>
+        public static void Copy(string sourceFilePath, string descDirectoryPath)
+        {
+            File.Copy(sourceFilePath, descDirectoryPath, true);
+        }
+        #endregion
+
+        #region 从文件的绝对路径中获取文件名( 不包含扩展名 )
+        /// <summary>
+        /// 从文件的绝对路径中获取文件名( 不包含扩展名 )
+        /// </summary>
+        /// <param name="filePath">文件的绝对路径</param> 
+        public static string GetFileName(string filePath)
+        {
+            FileInfo file = new FileInfo(filePath);
+            return file.Name;
+        }
+        #endregion
+
+        #region 获取文件的后缀名
+        /// <summary>
+        /// 获取文件的后缀名
+        /// </summary>
+        /// <param name="filePath">文件的绝对路径</param>
+        public static string GetExtension(string filePath)
+        {
+            FileInfo file = new FileInfo(filePath);
+            return file.Extension;
+        }
+
+        /// <summary>
+        /// 返回文件扩展名,不含“.”
+        /// </summary>
+        /// <param name="filepath">文件全名称</param>
+        /// <returns>string</returns>
+        public static string GetFileExt(string filepath)
+        {
+            if (string.IsNullOrEmpty(filepath))
+            {
+                return "";
+            }
+            if (filepath.LastIndexOf(".", StringComparison.Ordinal) > 0)
+            {
+                return filepath.Substring(filepath.LastIndexOf(".", StringComparison.Ordinal) + 1); //文件扩展名,不含“.”
+            }
+            return "";
+        }
+        #endregion
+
+        #region 删除指定文件
+        /// <summary>
+        /// 删除指定文件
+        /// </summary>
+        /// <param name="filePath">文件的绝对路径</param>
+        public static void DeleteFile(string filePath)
+        {
+            if (IsExistFile(filePath))
+            {
+                File.Delete(filePath);
+            }
+        }
+        #endregion
+
+        #region 删除指定目录及其所有子目录
+        /// <summary>
+        /// 删除指定目录及其所有子目录
+        /// </summary>
+        /// <param name="directoryPath">文件的绝对路径</param>
+        public static void DeleteDirectory(string directoryPath)
+        {
+            if (IsExistDirectory(directoryPath))
+            {
+                Directory.Delete(directoryPath);
+            }
+        }
+        #endregion
+
+        #region 清空指定目录下所有文件及子目录,但该目录依然保存.
+        /// <summary>
+        /// 清空指定目录下所有文件及子目录,但该目录依然保存.
+        /// </summary>
+        /// <param name="directoryPath">指定目录的绝对路径</param>
+        public static void ClearDirectory(string directoryPath)
+        {
+            if (!IsExistDirectory(directoryPath)) return;
+            //删除目录中所有的文件
+            string[] fileNames = GetFileNames(directoryPath);
+            for (int i = 0; i < fileNames.Length; i++)
+            {
+                DeleteFile(fileNames[i]);
+            }
+            //删除目录中所有的子目录
+            string[] directoryNames = GetDirectories(directoryPath);
+            for (int i = 0; i < directoryNames.Length; i++)
+            {
+                DeleteDirectory(directoryNames[i]);
+            }
+        }
+        #endregion
+
+        #region  剪切  粘贴
+        /// <summary>
+        /// 剪切文件
+        /// </summary>
+        /// <param name="source">原路径</param> 
+        /// <param name="destination">新路径</param> 
+        public bool FileMove(string source, string destination)
+        {
+            bool ret = false;
+            FileInfo file_s = new FileInfo(source);
+            FileInfo file_d = new FileInfo(destination);
+            if (file_s.Exists)
+            {
+                if (!file_d.Exists)
+                {
+                    file_s.MoveTo(destination);
+                    ret = true;
+                }
+            }
+            if (ret == true)
+            {
+                //Response.Write("<script>alert('剪切文件成功!');</script>");
+            }
+            else
+            {
+                //Response.Write("<script>alert('剪切文件失败!');</script>");
+            }
+            return ret;
+        }
+        #endregion
+
+        #region 检测指定目录是否为空
+        /// <summary>
+        /// 检测指定目录是否为空
+        /// </summary>
+        /// <param name="directoryPath">指定目录的绝对路径</param>  
+        public static bool IsEmptyDirectory(string directoryPath)
+        {
+            try
+            {
+                //判断文件是否存在
+                string[] fileNames = GetFileNames(directoryPath);
+                if (fileNames.Length > 0)
+                {
+                    return false;
+                }
+                //判断是否存在文件夹
+                string[] directoryNames = GetDirectories(directoryPath);
+                if (directoryNames.Length > 0)
+                {
+                    return false;
+                }
+                return true;
+            }
+            catch (Exception ex)
+            {
+
+                return true;
+            }
+        }
+        #endregion
+
+        #region 获取指定目录中所有文件列表
+        /// <summary>
+        /// 获取指定目录中所有文件列表
+        /// </summary>
+        /// <param name="directoryPath">指定目录的绝对路径</param>  
+        public static string[] GetFileNames(string directoryPath)
+        {
+            if (!IsExistDirectory(directoryPath))
+            {
+                throw new FileNotFoundException();
+            }
+            return Directory.GetFiles(directoryPath);
+        }
+        #endregion
+
+        #region 获取指定目录中的子目录列表
+        /// <summary>
+        /// 获取指定目录中所有子目录列表,若要搜索嵌套的子目录列表,请使用重载方法
+        /// </summary>
+        /// <param name="directoryPath">指定目录的绝对路径</param>
+        public static string[] GetDirectories(string directoryPath)
+        {
+            try
+            {
+                return Directory.GetDirectories(directoryPath);
+            }
+            catch (Exception ex)
+            {
+
+                throw ex;
+            }
+        }
+
+        /// <summary>
+        /// 获取指定目录及子目录中所有子目录列表
+        /// </summary>
+        /// <param name="directoryPath">指定目录的绝对路径</param>
+        /// <param name="searchPattern">模式字符串,"*"代表0或N个字符,"?"代表1个字符。
+        /// 范例:"Log*.xml"表示搜索所有以Log开头的Xml文件。</param>
+        /// <param name="isSearchChild">是否搜索子目录</param>
+        public static string[] GetDirectories(string directoryPath, string searchPattern, bool isSearchChild)
+        {
+            try
+            {
+                if (isSearchChild)
+                {
+                    return Directory.GetDirectories(directoryPath, searchPattern, SearchOption.AllDirectories);
+                }
+                else
+                {
+                    return Directory.GetDirectories(directoryPath, searchPattern, SearchOption.TopDirectoryOnly);
+                }
+            }
+            catch (Exception ex)
+            {
+
+                throw ex;
+            }
+        }
+        #endregion
+
+        #region 获取一个文件的长度
+        /// <summary> 
+        /// 获取一个文件的长度,单位为Byte 
+        /// </summary> 
+        /// <param name="filePath">文件的绝对路径</param>         
+        public static int GetFileSize(string filePath)
+        {
+            //创建一个文件对象 
+            FileInfo fi = new FileInfo(filePath);
+            //获取文件的大小 
+            return (int)fi.Length;
+        }
+        /// <summary> 
+        /// 获取一个文件的长度,单位为KB 
+        /// </summary> 
+        /// <param name="filePath">文件的路径</param>         
+        public static double GetFileSizeByKb(string filePath)
+        {
+            //创建一个文件对象 
+            FileInfo fi = new FileInfo(filePath);
+            //获取文件的大小 
+            return Math.Round(Convert.ToDouble(filePath.Length) / 1024, 2);// ConvertHelper.ToDouble(ConvertHelper.ToDouble(fi.Length) / 1024, 1);
+        }
+
+        /// <summary> 
+        /// 获取一个文件的长度,单位为MB 
+        /// </summary> 
+        /// <param name="filePath">文件的路径</param>         
+        public static double GetFileSizeByMb(string filePath)
+        {
+            //创建一个文件对象 
+            FileInfo fi = new FileInfo(filePath);
+            //获取文件的大小 
+            return Math.Round(Convert.ToDouble(Convert.ToDouble(fi.Length) / 1024 / 1024), 2);
+        }
+
+        #endregion
+
+        #region 获取所有文件夹及子文件夹
+        /// <summary>
+        /// 获取所有文件夹及子文件夹
+        /// </summary>
+        /// <param name="dirPath"></param>
+        /// <returns></returns>
+        public static List<ArrayFiles> GetDirs(string dirPath)
+        {
+            var list = new List<ArrayFiles>();
+            return GetArrys(dirPath, 0, list);
+        }
+
+        private static int zdId = 0;
+        private static List<ArrayFiles> GetArrys(string dirPath, int pid, List<ArrayFiles> list)
+        {
+            if (!Directory.Exists(dirPath)) return list;
+            if (Directory.GetDirectories(dirPath).Length <= 0) return list;
+            foreach (string path in Directory.GetDirectories(dirPath))
+            {
+                zdId++;
+                var model = new ArrayFiles()
+                {
+                    id = zdId,
+                    name = path.Substring(path.LastIndexOf('\\') + 1, path.Length - (path.LastIndexOf('\\') + 1)),
+                    pId = pid,
+                    open = false,
+                    target = "DeployBase",
+                    url = "/FytAdmin/FileMiam/DocList?path=" + path
+                };
+                list.Add(model);
+                GetArrys(path, model.id, list);
+            }
+            return list;
+        }
+
+        public class ArrayFiles
+        {
+            public int id { get; set; }
+            public int pId { get; set; }
+            public string name { get; set; }
+            public Boolean open { get; set; }
+            public string target { get; set; }
+            public string url { get; set; }
+        }
+        #endregion
+
+        #region 将文件读取到字符串中
+        /// <summary>
+        /// 将文件读取到字符串中
+        /// </summary>
+        /// <param name="filePath">文件的绝对路径</param>
+        public static string FileToString(string filePath)
+        {
+            return FileToString(filePath, Encoding.UTF8);
+        }
+        /// <summary>
+        /// 将文件读取到字符串中
+        /// </summary>
+        /// <param name="filePath">文件的绝对路径</param>
+        /// <param name="encoding">字符编码</param>
+        public static string FileToString(string filePath, Encoding encoding)
+        {
+            //创建流读取器
+            StreamReader reader = new StreamReader(filePath, encoding);
+            try
+            {
+                //读取流
+                return reader.ReadToEnd();
+            }
+            catch (Exception ex)
+            {
+                throw ex;
+            }
+            finally
+            {
+                //关闭流读取器
+                reader.Close();
+            }
+        }
+        #endregion
+    }
+
+    /// <summary>
+    /// 远程文件下载
+    /// </summary>
+    public class HttpDldFile
+    {
+        /// <summary>
+        /// Http方式下载文件
+        /// </summary>
+        /// <param name="url">http地址</param>
+        /// <param name="localfile">本地文件</param>
+        /// <returns></returns>
+        public bool Download(string url, string localfile)
+        {
+            bool flag = false;
+            long startPosition = 0; // 上次下载的文件起始位置
+            FileStream writeStream; // 写入本地文件流对象
+
+            long remoteFileLength = GetHttpLength(url);// 取得远程文件长度
+            //System.Console.WriteLine("remoteFileLength=" + remoteFileLength);
+            if (remoteFileLength == 745)
+            {
+                System.Console.WriteLine("远程文件不存在.");
+                return false;
+            }
+
+            // 判断要下载的文件夹是否存在
+            if (File.Exists(localfile))
+            {
+
+                writeStream = File.OpenWrite(localfile);             // 存在则打开要下载的文件
+                startPosition = writeStream.Length;                  // 获取已经下载的长度
+
+                if (startPosition >= remoteFileLength)
+                {
+                    System.Console.WriteLine("本地文件长度" + startPosition + "已经大于等于远程文件长度" + remoteFileLength);
+                    writeStream.Close();
+
+                    return false;
+                }
+                else
+                {
+                    writeStream.Seek(startPosition, SeekOrigin.Current); // 本地文件写入位置定位
+                }
+            }
+            else
+            {
+                writeStream = new FileStream(localfile, FileMode.Create);// 文件不保存创建一个文件
+                startPosition = 0;
+            }
+
+
+            try
+            {
+                HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(url);// 打开网络连接
+
+                if (startPosition > 0)
+                {
+                    myRequest.AddRange((int)startPosition);// 设置Range值,与上面的writeStream.Seek用意相同,是为了定义远程文件读取位置
+                }
+
+
+                Stream readStream = myRequest.GetResponse().GetResponseStream();// 向服务器请求,获得服务器的回应数据流
+
+
+                byte[] btArray = new byte[512];// 定义一个字节数据,用来向readStream读取内容和向writeStream写入内容
+                int contentSize = readStream.Read(btArray, 0, btArray.Length);// 向远程文件读第一次
+
+                long currPostion = startPosition;
+
+                while (contentSize > 0)// 如果读取长度大于零则继续读
+                {
+                    currPostion += contentSize;
+                    int percent = (int)(currPostion * 100 / remoteFileLength);
+                    System.Console.WriteLine("percent=" + percent + "%");
+
+                    writeStream.Write(btArray, 0, contentSize);// 写入本地文件
+                    contentSize = readStream.Read(btArray, 0, btArray.Length);// 继续向远程文件读取
+                }
+
+                //关闭流
+                writeStream.Close();
+                readStream.Close();
+
+                flag = true;        //返回true下载成功
+            }
+            catch (Exception)
+            {
+                writeStream.Close();
+                flag = false;       //返回false下载失败
+            }
+
+            return flag;
+        }
+
+        // 从文件头得到远程文件的长度
+        private static long GetHttpLength(string url)
+        {
+            long length = 0;
+
+            try
+            {
+                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);// 打开网络连接
+                HttpWebResponse rsp = (HttpWebResponse)req.GetResponse();
+
+                if (rsp.StatusCode == HttpStatusCode.OK)
+                {
+                    length = rsp.ContentLength;// 从文件头得到远程文件的长度
+                }
+
+                rsp.Close();
+                return length;
+            }
+            catch (Exception e)
+            {
+                return length;
+            }
+
+        }
+    }
+}

+ 552 - 0
HaBookCms.Common/FileHelper/FileHelperCore.cs

@@ -0,0 +1,552 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HaBookCms.Common.FileHelper
+{
+
+    /// <summary>
+    /// Describe:文件帮助类
+    /// </summary>
+    public class FileHelperCore
+    {
+        private static IHostingEnvironment _hostingEnvironment = new HttpContextAccessor().HttpContext.RequestServices.GetService(typeof(IHostingEnvironment)) as IHostingEnvironment;
+
+        /// <summary>
+        /// 目录分隔符
+        /// windows "\" OSX and Linux  "/"
+        /// </summary>
+        private static string DirectorySeparatorChar = Path.DirectorySeparatorChar.ToString();
+        /// <summary>
+        /// 包含应用程序的目录的绝对路径
+        /// </summary>
+        private static string _ContentRootPath = _hostingEnvironment.ContentRootPath;
+
+        #region 检测指定路径是否存在
+
+        /// <summary>
+        /// 检测指定路径是否存在
+        /// </summary>
+        /// <param name="path">路径</param>
+        /// <returns></returns>
+        public static bool IsExist(string path)
+        {
+            return IsDirectory(MapPath(path)) ? Directory.Exists(MapPath(path)) : File.Exists(MapPath(path));
+        }
+        /// <summary>
+        /// 检测指定路径是否存在(异步方式)
+        /// </summary>
+        /// <param name="path">路径</param>
+        /// <returns></returns>
+        public static async Task<bool> IsExistAsync(string path)
+        {
+            return await Task.Run(() => IsDirectory(MapPath(path)) ? Directory.Exists(MapPath(path)) : File.Exists(MapPath(path)));
+        }
+
+        #endregion
+
+        #region 检测目录是否为空
+
+        /// <summary>
+        /// 检测目录是否为空
+        /// </summary>
+        /// <param name="path">路径</param>
+        /// <returns></returns>
+        public static bool IsEmptyDirectory(string path)
+        {
+            return Directory.GetFiles(MapPath(path)).Length <= 0 && Directory.GetDirectories(MapPath(path)).Length <= 0;
+        }
+        /// <summary>
+        /// 检测目录是否为空
+        /// </summary>
+        /// <param name="path">路径</param>
+        /// <returns></returns>
+        public static async Task<bool> IsEmptyDirectoryAsync(string path)
+        {
+            return await Task.Run(() => Directory.GetFiles(MapPath(path)).Length <= 0 && Directory.GetDirectories(MapPath(path)).Length <= 0);
+        }
+
+        #endregion
+
+        #region 创建目录
+
+        /// <summary>
+        /// 创建目录
+        /// </summary>
+        /// <param name="path">路径</param>
+        public static void CreateFiles(string path)
+        {
+            try
+            {
+                if (IsDirectory(MapPath(path)))
+                    Directory.CreateDirectory(MapPath(path));
+                else
+                    File.Create(MapPath(path)).Dispose();
+            }
+            catch (Exception ex)
+            {
+                throw ex;
+            }
+        }
+
+        #endregion
+
+        #region 删除文件或目录
+
+        /// <summary>
+        /// 删除目录或文件
+        /// </summary>
+        /// <param name="path">路径</param>
+        public static void DeleteFiles(string path)
+        {
+            try
+            {
+                if (IsExist(path))
+                {
+                    if (IsDirectory(MapPath(path)))
+                        Directory.Delete(MapPath(path));
+                    else
+                        File.Delete(MapPath(path));
+                }
+            }
+            catch (Exception ex)
+            {
+                throw ex;
+            }
+        }
+
+        /// <summary>
+        /// 清空目录下所有文件及子目录,依然保留该目录
+        /// </summary>
+        /// <param name="path"></param>
+        public static void ClearDirectory(string path)
+        {
+            if (IsExist(path))
+            {
+                //目录下所有文件
+                string[] files = Directory.GetFiles(MapPath(path));
+                foreach (var file in files)
+                {
+                    DeleteFiles(file);
+                }
+                //目录下所有子目录
+                string[] directorys = Directory.GetDirectories(MapPath(path));
+                foreach (var dir in directorys)
+                {
+                    DeleteFiles(dir);
+                }
+            }
+        }
+
+        #endregion
+
+        #region 判断文件是否为隐藏文件(系统独占文件)
+
+        /// <summary>
+        /// 检测文件或文件夹是否为隐藏文件
+        /// </summary>
+        /// <param name="path">路径</param>
+        /// <returns></returns>
+        public static bool IsHiddenFile(string path)
+        {
+            return IsDirectory(MapPath(path)) ? InspectHiddenFile(new DirectoryInfo(MapPath(path))) : InspectHiddenFile(new FileInfo(MapPath(path)));
+        }
+        /// <summary>
+        /// 检测文件或文件夹是否为隐藏文件(异步方式)
+        /// </summary>
+        /// <param name="path">路径</param>
+        /// <returns></returns>
+        public static async Task<bool> IsHiddenFileAsync(string path)
+        {
+            return await Task.Run(() => IsDirectory(MapPath(path)) ? InspectHiddenFile(new DirectoryInfo(MapPath(path))) : InspectHiddenFile(new FileInfo(MapPath(path))));
+        }
+        /// <summary>
+        /// 私有方法 文件是否为隐藏文件(系统独占文件)
+        /// </summary>
+        /// <param name="fileSystemInfo"></param>
+        /// <returns></returns>
+        private static bool InspectHiddenFile(FileSystemInfo fileSystemInfo)
+        {
+            if (fileSystemInfo.Name.StartsWith("."))
+            {
+                return true;
+            }
+            else if (fileSystemInfo.Exists &&
+                ((fileSystemInfo.Attributes & FileAttributes.Hidden) != 0 ||
+                 (fileSystemInfo.Attributes & FileAttributes.System) != 0))
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        #endregion
+
+        #region 文件操作
+
+        #region 复制文件
+
+        /// <summary>
+        /// 复制文件内容到目标文件夹
+        /// </summary>
+        /// <param name="sourcePath">源文件</param>
+        /// <param name="targetPath">目标文件夹</param>
+        /// <param name="isOverWrite">是否可以覆盖</param>
+        public static void Copy(string sourcePath, string targetPath, bool isOverWrite = true)
+        {
+            File.Copy(MapPath(sourcePath), MapPath(targetPath) + GetFileName(sourcePath), isOverWrite);
+        }
+        /// <summary>
+        /// 复制文件内容到目标文件夹
+        /// </summary>
+        /// <param name="sourcePath">源文件</param>
+        /// <param name="targetPath">目标文件夹</param>
+        /// <param name="newName">新文件名称</param>
+        /// <param name="isOverWrite">是否可以覆盖</param>
+        public static void Copy(string sourcePath, string targetPath, string newName, bool isOverWrite = true)
+        {
+            File.Copy(MapPath(sourcePath), MapPath(targetPath) + newName, isOverWrite);
+        }
+
+        #endregion
+
+        #region 移动文件
+
+        /// <summary>
+        /// 移动文件到目标目录
+        /// </summary>
+        /// <param name="sourcePath">源文件</param>
+        /// <param name="targetPath">目标目录</param>
+        public static void Move(string sourcePath, string targetPath)
+        {
+            string sourceFileName = GetFileName(sourcePath);
+            //如果目标目录不存在则创建
+            if (IsExist(targetPath))
+            {
+                CreateFiles(targetPath);
+            }
+            else
+            {
+                //如果目标目录存在同名文件则删除
+                if (IsExist(Path.Combine(MapPath(targetPath), sourceFileName)))
+                {
+                    DeleteFiles(Path.Combine(MapPath(targetPath), sourceFileName));
+                }
+            }
+
+            File.Move(MapPath(sourcePath), Path.Combine(MapPath(targetPath), sourceFileName));
+
+
+        }
+
+        #endregion
+
+        /// <summary>
+        /// 获取文件名和扩展名
+        /// </summary>
+        /// <param name="path">文件路径</param>
+        /// <returns></returns>
+        public static string GetFileName(string path)
+        {
+            return Path.GetFileName(MapPath(path));
+        }
+
+        /// <summary>
+        /// 获取文件名不带扩展名
+        /// </summary>
+        /// <param name="path">文件路径</param>
+        /// <returns></returns>
+        public static string GetFileNameWithOutExtension(string path)
+        {
+            return Path.GetFileNameWithoutExtension(MapPath(path));
+        }
+
+        /// <summary>
+        /// 获取文件扩展名
+        /// </summary>
+        /// <param name="path">文件路径</param>
+        /// <returns></returns>
+        public static string GetFileExtension(string path)
+        {
+            return Path.GetExtension(MapPath(path));
+        }
+
+        #endregion
+
+        #region 获取文件绝对路径
+
+        /// <summary>
+        /// 获取文件绝对路径
+        /// </summary>
+        /// <param name="path">文件路径</param>
+        /// <returns></returns>
+        public static string MapPath(string path)
+        {
+            return Path.Combine(_ContentRootPath, path.TrimStart('~', '/').Replace("/", DirectorySeparatorChar));
+        }
+        /// <summary>
+        /// 获取文件绝对路径(异步方式)
+        /// </summary>
+        /// <param name="path">文件路径</param>
+        /// <returns></returns>
+        public static async Task<string> MapPathAsync(string path)
+        {
+            return await Task.Run(() => Path.Combine(_ContentRootPath, path.TrimStart('~', '/').Replace("/", DirectorySeparatorChar)));
+        }
+
+
+        /// <summary>
+        /// 是否为目录或文件夹
+        /// </summary>
+        /// <param name="path">路径</param>
+        /// <returns></returns>
+        public static bool IsDirectory(string path)
+        {
+            if (path.EndsWith(DirectorySeparatorChar))
+                return true;
+            else
+                return false;
+        }
+
+        #endregion
+
+        #region 物理路径转虚拟路径
+        public static string PhysicalToVirtual(string physicalPath)
+        {
+            return physicalPath.Replace(_ContentRootPath, "").Replace(DirectorySeparatorChar, "/");
+        }
+        #endregion
+
+        #region 文件格式
+        /// <summary>
+        /// 是否可添加水印
+        /// </summary>
+        /// <param name="_fileExt">文件扩展名,不含“.”</param>
+        /// <returns></returns>
+        public static bool IsCanWater(string _fileExt)
+        {
+            var images = new List<string> { "jpg", "jpeg" };
+            if (images.Contains(_fileExt.ToLower())) return true;
+            return false;
+        }
+        /// <summary>
+        /// 是否为图片
+        /// </summary>
+        /// <param name="_fileExt">文件扩展名,不含“.”</param>
+        /// <returns></returns>
+        public static bool IsImage(string _fileExt)
+        {
+            var images = new List<string> { "bmp", "gif", "jpg", "jpeg", "png" };
+            if (images.Contains(_fileExt.ToLower())) return true;
+            return false;
+        }
+        /// <summary>
+        /// 是否为视频
+        /// </summary>
+        /// <param name="_fileExt">文件扩展名,不含“.”</param>
+        /// <returns></returns>
+        public static bool IsVideos(string _fileExt)
+        {
+            var videos = new List<string> { "rmvb", "mkv", "ts", "wma", "avi", "rm", "mp4", "flv", "mpeg", "mov", "3gp", "mpg" };
+            if (videos.Contains(_fileExt.ToLower())) return true;
+            return false;
+        }
+        /// <summary>
+        /// 是否为音频
+        /// </summary>
+        /// <param name="_fileExt">文件扩展名,不含“.”</param>
+        /// <returns></returns>
+        public static bool IsMusics(string _fileExt)
+        {
+            var musics = new List<string> { "mp3", "wav" };
+            if (musics.Contains(_fileExt.ToLower())) return true;
+            return false;
+        }
+        /// <summary>
+        /// 是否为文档
+        /// </summary>
+        /// <param name="_fileExt">文件扩展名,不含“.”</param>
+        /// <returns></returns>
+        public static bool IsDocument(string _fileExt)
+        {
+            var documents = new List<string> { "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "pdf" };
+            if (documents.Contains(_fileExt.ToLower())) return true;
+            return false;
+        }
+        #endregion
+
+        #region 文件图标
+        public static string FindFileIcon(string fileExt)
+        {
+            if (IsImage(fileExt))
+                return "fa fa-image";
+            if (IsVideos(fileExt))
+                return "fa fa-film";
+            if (IsMusics(fileExt))
+                return "fa fa-music";
+            if (IsDocument(fileExt))
+                switch (fileExt.ToLower())
+                {
+                    case ".xls":
+                    case ".xlsx":
+                        return "fa fa-file-excel-o";
+                    case ".ppt":
+                    case ".pptx":
+                        return "fa fa-file-powerpoint-o";
+                    case ".pdf":
+                        return "fa fa-file-pdf-o";
+                    case ".txt":
+                        return "fa fa-file-text-o";
+                    default:
+                        return "fa fa-file-word-o";
+                }
+            if (fileExt.ToLower() == "zip" || fileExt.ToLower() == "rar")
+                return "fa fa-file-zip-o";
+            else
+                return "fa fa-file";
+        }
+        #endregion
+
+        #region 文件大小转换
+        /// <summary>
+        ///  文件大小转为B、KB、MB、GB...
+        /// </summary>
+        /// <param name="size"></param>
+        /// <returns></returns>
+        public static string FileSizeTransf(long size)
+        {
+            String[] units = new String[] { "B", "KB", "MB", "GB", "TB", "PB" };
+            long mod = 1024;
+            int i = 0;
+            while (size > mod)
+            {
+                size /= mod;
+                i++;
+            }
+            return size + units[i];
+
+        }
+        #endregion
+
+        #region 获取目录下所有文件
+        public static List<FilesInfo> FindFiles(string path, string staticFiles = "/wwwroot")
+        {
+            string[] folders = Directory.GetDirectories(MapPath(path), "*", SearchOption.AllDirectories);
+            var Files = new List<FilesInfo>();
+
+            foreach (var folder in folders)
+            {
+                foreach (var fsi in new DirectoryInfo(folder).GetFiles())
+                {
+                    Files.Add(new FilesInfo()
+                    {
+                        Name = fsi.Name,
+                        FullName = fsi.FullName,
+                        FileExt = fsi.Extension,
+                        FileOriginalSize = fsi.Length,
+                        FileSize = FileSizeTransf(fsi.Length),
+                        FileIcon = FindFileIcon(fsi.Extension.Remove(0, 1)),
+                        FileName = PhysicalToVirtual(fsi.FullName).Replace(staticFiles, ""),
+                        FileStyle = IsImage(fsi.Extension.Remove(0, 1)) ? "images" :
+                                    IsDocument(fsi.Extension.Remove(0, 1)) ? "documents" :
+                                    IsVideos(fsi.Extension.Remove(0, 1)) ? "videos" :
+                                    IsMusics(fsi.Extension.Remove(0, 1)) ? "musics" : "others",
+                        CreateDate = fsi.CreationTime,
+                        LastWriteDate = fsi.LastWriteTime,
+                        LastAccessDate = fsi.LastAccessTime
+                    });
+                }
+            }
+            return Files;
+        }
+
+        /// <summary>
+        /// 获得指定文件夹下面的所有文件
+        /// </summary>
+        /// <param name="path"></param>
+        /// <param name="staticFiles"></param>
+        /// <returns></returns>
+        public static List<FilesInfo> ResolveFileInfo(string path, string staticFiles = "/wwwroot")
+        {
+            var foldersPath = MapPath(path);
+            var Files = new List<FilesInfo>();
+            foreach (var fsi in new DirectoryInfo(foldersPath).GetFiles())
+            {
+                Files.Add(new FilesInfo()
+                {
+                    Name = fsi.Name,
+                    FullName = fsi.FullName,
+                    FileExt = fsi.Extension,
+                    FileOriginalSize = fsi.Length,
+                    FileSize = FileSizeTransf(fsi.Length),
+                    FileIcon = FindFileIcon(fsi.Extension.Remove(0, 1)),
+                    FileName = PhysicalToVirtual(fsi.FullName).Replace(staticFiles, ""),
+                    FileStyle = IsImage(fsi.Extension.Remove(0, 1)) ? "images" :
+                                IsDocument(fsi.Extension.Remove(0, 1)) ? "documents" :
+                                IsVideos(fsi.Extension.Remove(0, 1)) ? "videos" :
+                                IsMusics(fsi.Extension.Remove(0, 1)) ? "musics" : "others",
+                    CreateDate = fsi.CreationTime,
+                    LastWriteDate = fsi.LastWriteTime,
+                    LastAccessDate = fsi.LastAccessTime
+                });
+            }
+            return Files;
+        }
+        #endregion
+
+    }
+
+    public class FilesInfo
+    {
+        /// <summary>
+        /// 文件名称
+        /// </summary>
+        public string Name { get; set; }
+        /// <summary>
+        /// 文件物理路径
+        /// </summary>
+        public string FullName { get; set; }
+        /// <summary>
+        /// 扩展名
+        /// </summary>
+        public string FileExt { get; set; }
+        /// <summary>
+        /// 原始大小(字节)
+        /// </summary>
+        public long FileOriginalSize { get; set; }
+        /// <summary>
+        /// 文件大小
+        /// </summary>
+        public string FileSize { get; set; }
+        /// <summary>
+        /// 文件虚拟路径
+        /// </summary>
+        public string FileName { get; set; }
+        /// <summary>
+        /// 文件类型
+        /// </summary>
+        public string FileStyle { get; set; }
+        /// <summary>
+        /// 文件图标
+        /// </summary>
+        public string FileIcon { get; set; }
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public DateTime CreateDate { get; set; }
+        /// <summary>
+        /// 最后修改时间
+        /// </summary>
+        public DateTime LastWriteDate { get; set; }
+        /// <summary>
+        /// 最后访问时间
+        /// </summary>
+        public DateTime LastAccessDate { get; set; }
+
+    }
+}

+ 23 - 0
HaBookCms.Common/HaBookCms.Common.csproj

@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Folder Include="EnumHelper\" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="log4net" Version="2.0.8" />
+    <PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
+    <PackageReference Include="XC.Framework.Security.RSAUtil" Version="1.0.1" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Reference Include="Microsoft.AspNetCore.Http">
+      <HintPath>C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.http\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+
+</Project>

+ 154 - 0
HaBookCms.Common/LogHelper/ILoggerHelper.cs

@@ -0,0 +1,154 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace HaBookCms.Common.LogHelper
+{
+    /// <summary>
+    /// 日志接口
+    /// </summary>
+    public interface ILoggerHelper
+    {
+
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Debug(object source, string message);
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="ps">ps</param>
+        void Debug(object source, string message, params object[] ps);
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Debug(Type source, string message);
+        /// <summary>
+        /// 关键信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Info(object source, object message);
+        /// <summary>
+        /// 关键信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Info(Type source, object message);
+        /// <summary>
+        /// 警告信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Warn(object source, object message);
+        /// <summary>
+        /// 警告信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Warn(Type source, object message);
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Error(object source, object message);
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Error(Type source, object message);
+        /// <summary>
+        /// 失败信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Fatal(object source, object message);
+        /// <summary>
+        /// 失败信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        void Fatal(Type source, object message);
+
+        /* Log a message object and exception */
+
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Debug(object source, object message, Exception exception);
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Debug(Type source, object message, Exception exception);
+        /// <summary>
+        /// 关键信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Info(object source, object message, Exception exception);
+        /// <summary>
+        /// 关键信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Info(Type source, object message, Exception exception);
+        /// <summary>
+        /// 警告信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Warn(object source, object message, Exception exception);
+        /// <summary>
+        /// 警告信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Warn(Type source, object message, Exception exception);
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Error(object source, object message, Exception exception);
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Error(Type source, object message, Exception exception);
+        /// <summary>
+        /// 失败信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Fatal(object source, object message, Exception exception);
+        /// <summary>
+        /// 失败信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        void Fatal(Type source, object message, Exception exception);
+    }
+}

+ 284 - 0
HaBookCms.Common/LogHelper/LogHelper.cs

@@ -0,0 +1,284 @@
+using log4net;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Text;
+
+namespace HaBookCms.Common.LogHelper
+{
+    /// <summary>
+    /// 
+    /// </summary>
+    public class LogHelper : ILoggerHelper
+    {
+        private readonly ConcurrentDictionary<Type, ILog> Loggers = new ConcurrentDictionary<Type, ILog>();
+
+        /// <summary>
+        /// 获取记录器
+        /// </summary>
+        /// <param name="source">soruce</param>
+        /// <returns></returns>
+        private ILog GetLogger(Type source)
+        {
+            if (Loggers.ContainsKey(source))
+            {
+                return Loggers[source];
+            }
+            else
+            {
+                
+                   //ILog logger = LogManager.GetLogger(Startup.repository.Name, source);
+                ILog logger = LogManager.GetLogger("HaBookCms", source);
+                Loggers.TryAdd(source, logger);
+                return logger;
+            }
+        }
+
+        /* Log a message object */
+
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Debug(object source, string message)
+        {
+            Debug(source.GetType(), message);
+        }
+
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="ps">ps</param>
+        public void Debug(object source, string message, params object[] ps)
+        {
+            Debug(source.GetType(), string.Format(message, ps));
+        }
+
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Debug(Type source, string message)
+        {
+            ILog logger = GetLogger(source);
+            if (logger.IsDebugEnabled)
+            {
+                logger.Debug(message);
+            }
+        }
+
+        /// <summary>
+        /// 关键信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Info(object source, object message)
+        {
+            Info(source.GetType(), message);
+        }
+
+        /// <summary>
+        /// 关键信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Info(Type source, object message)
+        {
+            ILog logger = GetLogger(source);
+            if (logger.IsInfoEnabled)
+            {
+                logger.Info(message);
+            }
+        }
+
+        /// <summary>
+        /// 警告信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Warn(object source, object message)
+        {
+            Warn(source.GetType(), message);
+        }
+
+        /// <summary>
+        /// 警告信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Warn(Type source, object message)
+        {
+            ILog logger = GetLogger(source);
+            if (logger.IsWarnEnabled)
+            {
+                logger.Warn(message);
+            }
+        }
+
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Error(object source, object message)
+        {
+            Error(source.GetType(), message);
+        }
+
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Error(Type source, object message)
+        {
+            ILog logger = GetLogger(source);
+            if (logger.IsErrorEnabled)
+            {
+                logger.Error(message);
+            }
+        }
+
+        /// <summary>
+        /// 失败信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Fatal(object source, object message)
+        {
+            Fatal(source.GetType(), message);
+        }
+
+        /// <summary>
+        /// 失败信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        public void Fatal(Type source, object message)
+        {
+            ILog logger = GetLogger(source);
+            if (logger.IsFatalEnabled)
+            {
+                logger.Fatal(message);
+            }
+        }
+
+        /* Log a message object and exception */
+
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Debug(object source, object message, Exception exception)
+        {
+            Debug(source.GetType(), message, exception);
+        }
+
+        /// <summary>
+        /// 调试信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Debug(Type source, object message, Exception exception)
+        {
+            GetLogger(source).Debug(message, exception);
+        }
+
+        /// <summary>
+        /// 关键信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Info(object source, object message, Exception exception)
+        {
+            Info(source.GetType(), message, exception);
+        }
+
+        /// <summary>
+        /// 关键信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Info(Type source, object message, Exception exception)
+        {
+            GetLogger(source).Info(message, exception);
+        }
+
+        /// <summary>
+        /// 警告信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Warn(object source, object message, Exception exception)
+        {
+            Warn(source.GetType(), message, exception);
+        }
+
+        /// <summary>
+        /// 警告信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Warn(Type source, object message, Exception exception)
+        {
+            GetLogger(source).Warn(message, exception);
+        }
+
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Error(object source, object message, Exception exception)
+        {
+            Error(source.GetType(), message, exception);
+        }
+
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Error(Type source, object message, Exception exception)
+        {
+            GetLogger(source).Error(message, exception);
+        }
+
+        /// <summary>
+        /// 失败信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Fatal(object source, object message, Exception exception)
+        {
+            Fatal(source.GetType(), message, exception);
+        }
+
+        /// <summary>
+        /// 失败信息
+        /// </summary>
+        /// <param name="source">source</param>
+        /// <param name="message">message</param>
+        /// <param name="exception">ex</param>
+        public void Fatal(Type source, object message, Exception exception)
+        {
+            GetLogger(source).Fatal(message, exception);
+        }
+
+
+    }
+}

+ 738 - 0
HaBookCms.Common/Utils.cs

@@ -0,0 +1,738 @@
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+namespace HaBookCms.Common
+{
+
+    public class Utils
+    {
+        /// <summary>
+        /// 生成随机字母字符串(数字字母混和)
+        /// </summary>
+        /// <param name="codeCount">待生成的位数</param>
+        public static string GetCheckCode(int codeCount)
+        {
+            string str = string.Empty;
+            int rep = 0;
+            long num2 = DateTime.Now.Ticks + rep;
+            rep++;
+            Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep)));
+            for (int i = 0; i < codeCount; i++)
+            {
+                char ch;
+                int num = random.Next();
+                if ((num % 2) == 0)
+                {
+                    ch = (char)(0x30 + ((ushort)(num % 10)));
+                }
+                else
+                {
+                    ch = (char)(0x41 + ((ushort)(num % 0x1a)));
+                }
+                str = str + ch.ToString();
+            }
+            return str;
+        }
+
+        /// <summary>
+        /// 将字符串转换为int类型数组
+        /// </summary>
+        /// <param name="str">如1,2,3,4,5</param>
+        /// <returns></returns>
+        public static List<int> StrToListInt(string str)
+        {
+            var list = new List<int>();
+            if (!str.Contains(","))
+            {
+                list.Add(int.Parse(str));
+                return list;
+            }
+            var slist = str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+            foreach (var item in slist)
+            {
+                list.Add(int.Parse(item));
+            }
+            return list;
+        }
+
+        /// <summary>
+        /// 将字符串转换为int类型数组
+        /// </summary>
+        /// <param name="str">如1,2,3,4,5</param>
+        /// <returns></returns>
+        public static List<string> StrToListString(string str)
+        {
+            var list = new List<string>();
+            if (!str.Contains(","))
+            {
+                list.Add(str);
+                return list;
+            }
+            var slist = str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+            foreach (var item in slist)
+            {
+                list.Add(item);
+            }
+            return list;
+        }
+
+        /// <summary>
+        /// 将字符串转换为数组
+        /// </summary>
+        /// <param name="str">字符串</param>
+        /// <returns>字符串数组</returns>
+        public static string[] GetStrArray(string str)
+        {
+            return str.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+        }
+
+        #region 截取字符串
+        public static string GetSubString(string pSrcString, int pLength, string pTailString)
+        {
+            return GetSubString(pSrcString, 0, pLength, pTailString);
+        }
+        public static string GetSubString(string pSrcString, int pStartIndex, int pLength, string pTailString)
+        {
+            string str = pSrcString;
+            byte[] bytes = Encoding.UTF8.GetBytes(pSrcString);
+            foreach (char ch in Encoding.UTF8.GetChars(bytes))
+            {
+                if (((ch > 'ࠀ') && (ch < '一')) || ((ch > 0xac00) && (ch < 0xd7a3)))
+                {
+                    if (pStartIndex >= pSrcString.Length)
+                    {
+                        return "";
+                    }
+                    return pSrcString.Substring(pStartIndex, ((pLength + pStartIndex) > pSrcString.Length) ? (pSrcString.Length - pStartIndex) : pLength);
+                }
+            }
+            if (pLength < 0)
+            {
+                return str;
+            }
+            byte[] sourceArray = Encoding.Default.GetBytes(pSrcString);
+            if (sourceArray.Length <= pStartIndex)
+            {
+                return str;
+            }
+            int length = sourceArray.Length;
+            if (sourceArray.Length > (pStartIndex + pLength))
+            {
+                length = pLength + pStartIndex;
+            }
+            else
+            {
+                pLength = sourceArray.Length - pStartIndex;
+                pTailString = "";
+            }
+            int num2 = pLength;
+            int[] numArray = new int[pLength];
+            byte[] destinationArray = null;
+            int num3 = 0;
+            for (int i = pStartIndex; i < length; i++)
+            {
+                if (sourceArray[i] > 0x7f)
+                {
+                    num3++;
+                    if (num3 == 3)
+                    {
+                        num3 = 1;
+                    }
+                }
+                else
+                {
+                    num3 = 0;
+                }
+                numArray[i] = num3;
+            }
+            if ((sourceArray[length - 1] > 0x7f) && (numArray[pLength - 1] == 1))
+            {
+                num2 = pLength + 1;
+            }
+            destinationArray = new byte[num2];
+            Array.Copy(sourceArray, pStartIndex, destinationArray, 0, num2);
+            return (Encoding.Default.GetString(destinationArray) + pTailString);
+        }
+        #endregion
+
+        #region 截取字符长度
+        /// <summary>
+        /// 截取字符长度
+        /// </summary>
+        /// <param name="inputString">字符</param>
+        /// <param name="len">长度</param>
+        /// <returns></returns>
+        public static string CutString(string inputString, int len)
+        {
+            if (string.IsNullOrEmpty(inputString))
+                return "";
+            inputString = DropHtml(inputString);
+            ASCIIEncoding ascii = new ASCIIEncoding();
+            int tempLen = 0;
+            string tempString = "";
+            byte[] s = ascii.GetBytes(inputString);
+            for (int i = 0; i < s.Length; i++)
+            {
+                if ((int)s[i] == 63)
+                {
+                    tempLen += 2;
+                }
+                else
+                {
+                    tempLen += 1;
+                }
+
+                try
+                {
+                    tempString += inputString.Substring(i, 1);
+                }
+                catch
+                {
+                    break;
+                }
+
+                if (tempLen > len)
+                    break;
+            }
+            //如果截过则加上半个省略号 
+            byte[] mybyte = System.Text.Encoding.Default.GetBytes(inputString);
+            if (mybyte.Length > len)
+                tempString += "…";
+            return tempString;
+        }
+
+        public static string DropHtml(string htmlstring)
+        {
+            if (string.IsNullOrEmpty(htmlstring)) return "";
+            //删除脚本  
+            htmlstring = Regex.Replace(htmlstring, @"<script[^>]*?>.*?</script>", "", RegexOptions.IgnoreCase);
+            //删除HTML  
+            htmlstring = Regex.Replace(htmlstring, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"([\r\n])[\s]+", "", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"-->", "", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"<!--.*", "", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(quot|#34);", "\"", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(amp|#38);", "&", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(lt|#60);", "<", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(gt|#62);", ">", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(nbsp|#160);", " ", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(iexcl|#161);", "\xa1", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(cent|#162);", "\xa2", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(pound|#163);", "\xa3", RegexOptions.IgnoreCase);
+            htmlstring = Regex.Replace(htmlstring, @"&(copy|#169);", "\xa9", RegexOptions.IgnoreCase);
+
+            htmlstring = Regex.Replace(htmlstring, @"&#(\d+);", "", RegexOptions.IgnoreCase);
+            htmlstring = htmlstring.Replace("<", "");
+            htmlstring = htmlstring.Replace(">", "");
+            htmlstring = htmlstring.Replace("\r\n", "");
+            //htmlstring = HttpContext.Current.Server.HtmlEncode(htmlstring).Trim(); 
+            return htmlstring;
+        }
+        #endregion
+
+        #region 得到一个汉字的拼音第一个字母,如果是一个英文字母则直接返回大写字母
+        /// <summary>
+        /// 得到一个汉字的拼音第一个字母,如果是一个英文字母则直接返回大写字母
+        /// </summary>
+        /// <param name="CnChar">单个汉字</param>
+        /// <returns>单个大写字母</returns>
+        public static string GetCharSpellCode(string CnChar)
+        {
+            long iCnChar;
+            byte[] ZW = Encoding.Default.GetBytes(CnChar);
+
+            //如果是字母,则直接返回首字母
+            if (ZW.Length == 1)
+            {
+                return CutString(CnChar.ToUpper(), 1);
+            }
+            else
+            {
+                int i1 = (short)(ZW[0]);
+                int i2 = (short)(ZW[1]);
+                iCnChar = i1 * 256 + i2;
+            }
+            // iCnChar match the constant
+            if ((iCnChar >= 45217) && (iCnChar <= 45252))
+            {
+                return "A";
+            }
+            else if ((iCnChar >= 45253) && (iCnChar <= 45760))
+            {
+                return "B";
+            }
+            else if ((iCnChar >= 45761) && (iCnChar <= 46317))
+            {
+                return "C";
+            }
+            else if ((iCnChar >= 46318) && (iCnChar <= 46825))
+            {
+                return "D";
+            }
+            else if ((iCnChar >= 46826) && (iCnChar <= 47009))
+            {
+                return "E";
+            }
+            else if ((iCnChar >= 47010) && (iCnChar <= 47296))
+            {
+                return "F";
+            }
+            else if ((iCnChar >= 47297) && (iCnChar <= 47613))
+            {
+                return "G";
+            }
+            else if ((iCnChar >= 47614) && (iCnChar <= 48118))
+            {
+                return "H";
+            }
+            else if ((iCnChar >= 48119) && (iCnChar <= 49061))
+            {
+                return "J";
+            }
+            else if ((iCnChar >= 49062) && (iCnChar <= 49323))
+            {
+                return "K";
+            }
+            else if ((iCnChar >= 49324) && (iCnChar <= 49895))
+            {
+                return "L";
+            }
+            else if ((iCnChar >= 49896) && (iCnChar <= 50370))
+            {
+                return "M";
+            }
+            else if ((iCnChar >= 50371) && (iCnChar <= 50613))
+            {
+                return "N";
+            }
+            else if ((iCnChar >= 50614) && (iCnChar <= 50621))
+            {
+                return "O";
+            }
+            else if ((iCnChar >= 50622) && (iCnChar <= 50905))
+            {
+                return "P";
+            }
+            else if ((iCnChar >= 50906) && (iCnChar <= 51386))
+            {
+                return "Q";
+            }
+            else if ((iCnChar >= 51387) && (iCnChar <= 51445))
+            {
+                return "R";
+            }
+            else if ((iCnChar >= 51446) && (iCnChar <= 52217))
+            {
+                return "S";
+            }
+            else if ((iCnChar >= 52218) && (iCnChar <= 52697))
+            {
+                return "T";
+            }
+            else if ((iCnChar >= 52698) && (iCnChar <= 52979))
+            {
+                return "W";
+            }
+            else if ((iCnChar >= 52980) && (iCnChar <= 53640))
+            {
+                return "X";
+            }
+            else if ((iCnChar >= 53689) && (iCnChar <= 54480))
+            {
+                return "Y";
+            }
+            else if ((iCnChar >= 54481) && (iCnChar <= 55289))
+            {
+                return "Z";
+            }
+            else
+                return ("?");
+
+        }
+        #endregion
+
+        #region 获得IP地址
+        /// <summary>
+        /// 获得IP地址
+        /// </summary>
+        /// <returns>字符串数组</returns>
+        public static string GetIp()
+        {
+            HttpContextAccessor _context = new HttpContextAccessor();
+            var ip = _context.HttpContext.Request.Headers["X-Forwarded-For"].ToString();
+            if (string.IsNullOrEmpty(ip))
+            {
+                ip = _context.HttpContext.Connection.RemoteIpAddress.ToString();
+            }
+            return ip;
+        }
+        #endregion
+
+        #region 获得当前访问的URL地址
+        /// <summary>
+        /// 获得当前访问的URL地址
+        /// </summary>
+        /// <returns>字符串数组</returns>
+        public static string GetUrl()
+        {
+            HttpContextAccessor _context = new HttpContextAccessor();
+            return _context.HttpContext.Request.Path.ToString();
+        }
+        #endregion
+
+        #region 分割字符串
+        public static string[] SplitString(string strContent, char strSplit)
+        {
+            if (!string.IsNullOrEmpty(strContent))
+            {
+                return strContent.Split(new char[] { strSplit }, StringSplitOptions.RemoveEmptyEntries);
+            }
+            else
+            {
+                return new string[0] { };
+            }
+        }
+        /// <summary>
+        /// 分割字符串
+        /// </summary>
+        public static string[] SplitString(string strContent, string strSplit)
+        {
+            if (!string.IsNullOrEmpty(strContent))
+            {
+                if (strContent.IndexOf(strSplit, StringComparison.Ordinal) < 0)
+                    return new string[] { strContent };
+
+                return Regex.Split(strContent, Regex.Escape(strSplit), RegexOptions.IgnoreCase);
+            }
+            else
+                return new string[0] { };
+        }
+        #endregion
+
+        #region 显示错层方法
+        /// <summary>
+        /// 显示错层方法
+        /// </summary>
+        public static string LevelName(string name, decimal? level)
+        {
+            if (level > 1)
+            {
+                string nbsp = "";
+                for (int i = 0; i < level; i++)
+                {
+                    nbsp += " ";
+                }
+                name = nbsp + "|--" + name;
+            }
+            return name;
+        }
+        #endregion
+
+        #region 生成随机字母或数字
+
+        private static readonly Random Random = new Random();
+
+        /// <summary>
+        /// 生成随机数字
+        /// </summary>
+        /// <param name="length">生成长度</param>
+        /// <returns></returns>
+        public static string Number(int length)
+        {
+            return Number(length, false);
+        }
+
+        /// <summary>
+        /// 生成随机数字
+        /// </summary>
+        /// <param name="length">生成长度</param>
+        /// <param name="sleep">是否要在生成前将当前线程阻止以避免重复</param>
+        /// <returns></returns>
+        public static string Number(int length, bool sleep)
+        {
+            if (sleep)
+                System.Threading.Thread.Sleep(2);
+            string result = "";
+
+            for (int i = 0; i < length; i++)
+            {
+                result += Random.Next(10).ToString();
+            }
+            return result;
+        }
+
+
+        /// <summary>
+        /// 根据日期和随机码生成订单号
+        /// </summary>
+        /// <returns></returns>
+        public static string GetOrderNumber()
+        {
+            string num = DateTime.Now.ToString("yyyyMMddHHmmssms"); //yyyyMMddHHmmssms
+            return num + Number(2);
+        }
+
+        #endregion
+
+        #region 条形码解析
+        /// <summary>
+        /// 分解条形码,并返回数组
+        /// </summary>
+        /// <param name="code">条形码</param>
+        /// <returns>数组0=品牌  1=季节  2=款式  3=批次  4=尺码</returns>
+        public static List<string> GetSkuArray(string code)
+        {
+            var str = new List<string>();
+            //品牌,截取0-3
+            str.Add(code.Substring(0, 3));
+            //季节截取
+            str.Add(code.Substring(3, 1));
+            //款式截取
+            str.Add(code.Substring(4, 1));
+            //批次截取
+            str.Add(code.Substring(5, 1));
+            //尺码截取
+            str.Add(code.Substring(6, 1));
+            return str;
+        }
+        #endregion
+
+        #region 返回采购单入库状态
+        /// <summary>
+        /// 返回采购单入库状态
+        /// </summary>
+        /// <param name="status">状态</param>
+        /// <returns></returns>
+        public static string PurchaseStatus(string status)
+        {
+            var str = "";
+            switch (int.Parse(status))
+            {
+                case 1: str = "未完成入库"; break;
+                case 2: str = "未完成付款"; break;
+                case 3: str = "未完成到票"; break;
+                case 4: str = "完成"; break;
+            }
+            return str;
+        }
+        #endregion
+
+        #region 生成采购单编号
+        /// <summary>
+        /// 生成采购单编号
+        /// </summary>
+        /// <returns></returns>
+        public static string PurchaseNumber(int lastNumber)
+        {
+            return "CG-" + DateTime.Now.ToString("yyyyMMdd") + "-" + lastNumber.ToString();
+        }
+        #endregion
+
+        #region 上传配置
+        /// <summary>
+        ///  根据文件类型分配路径
+        /// </summary>
+        /// <param name="fileExt"></param>
+        /// <returns></returns>
+        public static string AssigendPath(string fileExt, string path)
+        {
+            if (IsImage(fileExt))
+                return path + "/upload/images/" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + "/";
+            if (IsVideos(fileExt))
+                return path + "/upload/videos/" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + "/";
+            if (IsDocument(fileExt))
+                return "/upload/files/" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + "/";
+            if (IsMusics(fileExt))
+                return "/upload/musics/" + DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + "/";
+            return path + "/upload/others/";
+        }
+        #endregion
+
+        #region 文件格式
+        /// <summary>
+        /// 是否为图片
+        /// </summary>
+        /// <param name="_fileExt">文件扩展名,不含“.”</param>
+        /// <returns></returns>
+        private static bool IsImage(string _fileExt)
+        {
+            var images = new List<string> { "bmp", "gif", "jpg", "jpeg", "png" };
+            if (images.Contains(_fileExt.ToLower())) return true;
+            return false;
+        }
+        /// <summary>
+        /// 是否为视频
+        /// </summary>
+        /// <param name="_fileExt">文件扩展名,不含“.”</param>
+        /// <returns></returns>
+        private static bool IsVideos(string _fileExt)
+        {
+            var videos = new List<string> { "rmvb", "mkv", "ts", "wma", "avi", "rm", "mp4", "flv", "mpeg", "mov", "3gp", "mpg" };
+            if (videos.Contains(_fileExt.ToLower())) return true;
+            return false;
+        }
+        /// <summary>
+        /// 是否为音频
+        /// </summary>
+        /// <param name="_fileExt">文件扩展名,不含“.”</param>
+        /// <returns></returns>
+        private static bool IsMusics(string _fileExt)
+        {
+            var musics = new List<string> { "mp3", "wav" };
+            if (musics.Contains(_fileExt.ToLower())) return true;
+            return false;
+        }
+        /// <summary>
+        /// 是否为文档
+        /// </summary>
+        /// <param name="_fileExt">文件扩展名,不含“.”</param>
+        /// <returns></returns>
+        private static bool IsDocument(string _fileExt)
+        {
+            var documents = new List<string> { "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "pdf" };
+            if (documents.Contains(_fileExt.ToLower())) return true;
+            return false;
+        }
+        #endregion
+
+        #region 返回活动名称
+        /// <summary>
+        /// 返回活动名称
+        /// </summary>
+        /// <param name="method"></param>
+        /// <returns></returns>
+        public static string GetActivityMethod(int method)
+        {
+            var str = "";
+            switch (method)
+            {
+                case 1: str = "打折"; break;
+                case 2: str = "满减"; break;
+                case 3: str = "买一赠一"; break;
+                default: str = "无"; break;
+            }
+            return str;
+        }
+        /// <summary>
+        /// 根据方式返回参加活动类型
+        /// </summary>
+        /// <param name="method"></param>
+        /// <returns></returns>
+        public static byte GetActivityTypes(int method)
+        {
+            byte str = 1;
+            switch (method)
+            {
+                case 1: str = 2; break;
+                case 2: str = 3; break;
+                case 3: str = 4; break;
+            }
+            return str;
+        }
+        #endregion
+
+        #region 得到一周的周一和周日的日期
+        /// <summary> 
+        /// 计算本周的周一日期 
+        /// </summary> 
+        /// <returns></returns> 
+        public static DateTime GetMondayDate()
+        {
+            return GetMondayDate(DateTime.Now);
+        }
+        /// <summary> 
+        /// 计算本周周日的日期 
+        /// </summary> 
+        /// <returns></returns> 
+        public static DateTime GetSundayDate()
+        {
+            return GetSundayDate(DateTime.Now);
+        }
+        /// <summary> 
+        /// 计算某日起始日期(礼拜一的日期) 
+        /// </summary> 
+        /// <param name="someDate">该周中任意一天</param> 
+        /// <returns>返回礼拜一日期,后面的具体时、分、秒和传入值相等</returns> 
+        public static DateTime GetMondayDate(DateTime someDate)
+        {
+            int i = someDate.DayOfWeek - DayOfWeek.Monday;
+            if (i == -1) i = 6;// i值 > = 0 ,因为枚举原因,Sunday排在最前,此时Sunday-Monday=-1,必须+7=6。 
+            TimeSpan ts = new TimeSpan(i, 0, 0, 0);
+            return someDate.Subtract(ts);
+        }
+        /// <summary> 
+        /// 计算某日结束日期(礼拜日的日期) 
+        /// </summary> 
+        /// <param name="someDate">该周中任意一天</param> 
+        /// <returns>返回礼拜日日期,后面的具体时、分、秒和传入值相等</returns> 
+        public static DateTime GetSundayDate(DateTime someDate)
+        {
+            int i = someDate.DayOfWeek - DayOfWeek.Sunday;
+            if (i != 0) i = 7 - i;// 因为枚举原因,Sunday排在最前,相减间隔要被7减。 
+            TimeSpan ts = new TimeSpan(i, 0, 0, 0);
+            return someDate.Add(ts);
+        }
+
+        /// <summary>
+        /// 根据星期几获得数字的星期几
+        /// </summary>
+        /// <param name="weekName">例如周一:Monday</param>
+        /// <returns></returns>
+        public static int GetWeekByWeekName(string weekName)
+        {
+            var week = 1;
+            switch (weekName)
+            {
+                case "Monday":
+                    week = 1;
+                    break;
+                case "Tuesday":
+                    week = 2;
+                    break;
+                case "Wednesday":
+                    week = 3;
+                    break;
+                case "Thursday":
+                    week = 4;
+                    break;
+                case "Friday":
+                    week = 5;
+                    break;
+                case "Saturday":
+                    week = 6;
+                    break;
+                case "Sunday":
+                    week = 7;
+                    break;
+            }
+            return week;
+        }
+        #endregion
+
+        /// <summary>
+        /// 时间戳转换为日期(时间戳单位秒)
+        /// </summary>
+        /// <param name="TimeStamp"></param>
+        /// <returns></returns>
+        public static DateTime ConvertToDateTime(long timeStamp)
+        {
+            var dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
+            TimeSpan toNow = new TimeSpan(timeStamp);
+            return dtStart.Add(toNow);
+            //var start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+            //return start.AddMilliseconds(timeStamp).AddHours(8);
+        }
+        /// <summary>
+        /// 日期转换为时间戳(时间戳单位秒)
+        /// </summary>
+        /// <param name="TimeStamp"></param>
+        /// <returns></returns>
+        public static long ConvertToTimeStamp(DateTime time)
+        {
+            DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+            return (long)(time.AddHours(-8) - Jan1st1970).TotalMilliseconds;
+        }
+    }
+}

+ 29 - 0
HaBookCms.Contest/Controllers/HomeController.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using HaBookCms.Contest.Models;
+
+namespace HaBookCms.Contest.Controllers
+{
+    public class HomeController : Controller
+    {
+        public IActionResult Index()
+        {
+            return View();
+        }
+
+        public IActionResult Privacy()
+        {
+            return View();
+        }
+
+        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
+        public IActionResult Error()
+        {
+            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
+        }
+    }
+}

+ 14 - 0
HaBookCms.Contest/HaBookCms.Contest.csproj

@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.2</TargetFramework>
+    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
+  </PropertyGroup>
+
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.App" />
+    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
+  </ItemGroup>
+
+</Project>

+ 11 - 0
HaBookCms.Contest/Models/ErrorViewModel.cs

@@ -0,0 +1,11 @@
+using System;
+
+namespace HaBookCms.Contest.Models
+{
+    public class ErrorViewModel
+    {
+        public string RequestId { get; set; }
+
+        public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
+    }
+}

+ 24 - 0
HaBookCms.Contest/Program.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+
+namespace HaBookCms.Contest
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateWebHostBuilder(args).Build().Run();
+        }
+
+        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
+            WebHost.CreateDefaultBuilder(args)
+                .UseStartup<Startup>();
+    }
+}

+ 27 - 0
HaBookCms.Contest/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false, 
+    "anonymousAuthentication": true, 
+    "iisExpress": {
+      "applicationUrl": "http://localhost:63686",
+      "sslPort": 44399
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "HaBookCms.Contest": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "applicationUrl": "https://localhost:5001;http://localhost:5000",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 64 - 0
HaBookCms.Contest/Startup.cs

@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.HttpsPolicy;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace HaBookCms.Contest
+{
+    public class Startup
+    {
+        public Startup(IConfiguration configuration)
+        {
+            Configuration = configuration;
+        }
+
+        public IConfiguration Configuration { get; }
+
+        // This method gets called by the runtime. Use this method to add services to the container.
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.Configure<CookiePolicyOptions>(options =>
+            {
+                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
+                options.CheckConsentNeeded = context => true;
+                options.MinimumSameSitePolicy = SameSiteMode.None;
+            });
+
+
+            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+        {
+            if (env.IsDevelopment())
+            {
+                app.UseDeveloperExceptionPage();
+            }
+            else
+            {
+                app.UseExceptionHandler("/Home/Error");
+                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
+                app.UseHsts();
+            }
+
+            app.UseHttpsRedirection();
+            app.UseStaticFiles();
+            app.UseCookiePolicy();
+
+            app.UseMvc(routes =>
+            {
+                routes.MapRoute(
+                    name: "default",
+                    template: "{controller=Home}/{action=Index}/{id?}");
+            });
+        }
+    }
+}

+ 8 - 0
HaBookCms.Contest/Views/Home/Index.cshtml

@@ -0,0 +1,8 @@
+@{
+    ViewData["Title"] = "Home Page";
+}
+
+<div class="text-center">
+    <h1 class="display-4">Welcome</h1>
+    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
+</div>

+ 6 - 0
HaBookCms.Contest/Views/Home/Privacy.cshtml

@@ -0,0 +1,6 @@
+@{
+    ViewData["Title"] = "Privacy Policy";
+}
+<h1>@ViewData["Title"]</h1>
+
+<p>Use this page to detail your site's privacy policy.</p>

+ 25 - 0
HaBookCms.Contest/Views/Shared/Error.cshtml

@@ -0,0 +1,25 @@
+@model ErrorViewModel
+@{
+    ViewData["Title"] = "Error";
+}
+
+<h1 class="text-danger">Error.</h1>
+<h2 class="text-danger">An error occurred while processing your request.</h2>
+
+@if (Model.ShowRequestId)
+{
+    <p>
+        <strong>Request ID:</strong> <code>@Model.RequestId</code>
+    </p>
+}
+
+<h3>Development Mode</h3>
+<p>
+    Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
+</p>
+<p>
+    <strong>The Development environment shouldn't be enabled for deployed applications.</strong>
+    It can result in displaying sensitive information from exceptions to end users.
+    For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
+    and restarting the app.
+</p>

+ 25 - 0
HaBookCms.Contest/Views/Shared/_CookieConsentPartial.cshtml

@@ -0,0 +1,25 @@
+@using Microsoft.AspNetCore.Http.Features
+
+@{
+    var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
+    var showBanner = !consentFeature?.CanTrack ?? false;
+    var cookieString = consentFeature?.CreateConsentCookie();
+}
+
+@if (showBanner)
+{
+    <div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
+        Use this space to summarize your privacy and cookie use policy. <a asp-area="" asp-controller="Home" asp-action="Privacy">Learn More</a>.
+        <button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
+            <span aria-hidden="true">Accept</span>
+        </button>
+    </div>
+    <script>
+        (function () {
+            var button = document.querySelector("#cookieConsent button[data-cookie-string]");
+            button.addEventListener("click", function (event) {
+                document.cookie = button.dataset.cookieString;
+            }, false);
+        })();
+    </script>
+}

+ 77 - 0
HaBookCms.Contest/Views/Shared/_Layout.cshtml

@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>@ViewData["Title"] - HaBookCms.Contest</title>
+
+    <environment include="Development">
+        <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
+    </environment>
+    <environment exclude="Development">
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css"
+              asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
+              asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute"
+              crossorigin="anonymous"
+              integrity="sha256-eSi1q2PG6J7g7ib17yAaWMcrr5GrtohYChqibrV7PBE="/>
+    </environment>
+    <link rel="stylesheet" href="~/css/site.css" />
+</head>
+<body>
+    <header>
+        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
+            <div class="container">
+                <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">HaBookCms.Contest</a>
+                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
+                        aria-expanded="false" aria-label="Toggle navigation">
+                    <span class="navbar-toggler-icon"></span>
+                </button>
+                <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
+                    <ul class="navbar-nav flex-grow-1">
+                        <li class="nav-item">
+                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
+                        </li>
+                        <li class="nav-item">
+                            <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
+                        </li>
+                    </ul>
+                </div>
+            </div>
+        </nav>
+    </header>
+    <div class="container">
+        <partial name="_CookieConsentPartial" />
+        <main role="main" class="pb-3">
+            @RenderBody()
+        </main>
+    </div>
+
+    <footer class="border-top footer text-muted">
+        <div class="container">
+            &copy; 2018 - HaBookCms.Contest - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
+        </div>
+    </footer>
+
+    <environment include="Development">
+        <script src="~/lib/jquery/dist/jquery.js"></script>
+        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
+    </environment>
+    <environment exclude="Development">
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
+                asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
+                asp-fallback-test="window.jQuery"
+                crossorigin="anonymous"
+                integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=">
+        </script>
+        <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/js/bootstrap.bundle.min.js"
+                asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"
+                asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
+                crossorigin="anonymous"
+                integrity="sha256-E/V4cWE4qvAeO5MOhjtGtqDzPndRO1LBk8lJ/PR7CA4=">
+        </script>
+    </environment>
+    <script src="~/js/site.js" asp-append-version="true"></script>
+
+    @RenderSection("Scripts", required: false)
+</body>
+</html>

+ 18 - 0
HaBookCms.Contest/Views/Shared/_ValidationScriptsPartial.cshtml

@@ -0,0 +1,18 @@
+<environment include="Development">
+    <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
+    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
+</environment>
+<environment exclude="Development">
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"
+            asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
+            asp-fallback-test="window.jQuery && window.jQuery.validator"
+            crossorigin="anonymous"
+            integrity="sha256-F6h55Qw6sweK+t7SiOJX+2bpSAa3b/fnlrVCJvmEj1A=">
+    </script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"
+            asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
+            asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
+            crossorigin="anonymous"
+            integrity="sha256-9GycpJnliUjJDVDqP0UEu/bsm9U+3dnQUH8+3W10vkY=">
+    </script>
+</environment>

+ 3 - 0
HaBookCms.Contest/Views/_ViewImports.cshtml

@@ -0,0 +1,3 @@
+@using HaBookCms.Contest
+@using HaBookCms.Contest.Models
+@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

+ 3 - 0
HaBookCms.Contest/Views/_ViewStart.cshtml

@@ -0,0 +1,3 @@
+@{
+    Layout = "_Layout";
+}

+ 9 - 0
HaBookCms.Contest/appsettings.Development.json

@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Debug",
+      "System": "Information",
+      "Microsoft": "Information"
+    }
+  }
+}

+ 8 - 0
HaBookCms.Contest/appsettings.json

@@ -0,0 +1,8 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Warning"
+    }
+  },
+  "AllowedHosts": "*"
+}

+ 56 - 0
HaBookCms.Contest/wwwroot/css/site.css

@@ -0,0 +1,56 @@
+/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
+for details on configuring this project to bundle and minify static web assets. */
+
+a.navbar-brand {
+  white-space: normal;
+  text-align: center;
+  word-break: break-all;
+}
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html {
+  font-size: 14px;
+}
+@media (min-width: 768px) {
+  html {
+    font-size: 16px;
+  }
+}
+
+.border-top {
+  border-top: 1px solid #e5e5e5;
+}
+.border-bottom {
+  border-bottom: 1px solid #e5e5e5;
+}
+
+.box-shadow {
+  box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
+}
+
+button.accept-policy {
+  font-size: 1rem;
+  line-height: inherit;
+}
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html {
+  position: relative;
+  min-height: 100%;
+}
+
+body {
+  /* Margin bottom by footer height */
+  margin-bottom: 60px;
+}
+.footer {
+  position: absolute;
+  bottom: 0;
+  width: 100%;
+  white-space: nowrap;
+  /* Set the fixed height of the footer here */
+  height: 60px;
+  line-height: 60px; /* Vertically center the text there */
+}

BIN
HaBookCms.Contest/wwwroot/favicon.ico


+ 4 - 0
HaBookCms.Contest/wwwroot/js/site.js

@@ -0,0 +1,4 @@
+// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
+// for details on configuring this project to bundle and minify static web assets.
+
+// Write your JavaScript code.

+ 22 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/LICENSE

@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2011-2018 Twitter, Inc.
+Copyright (c) 2011-2018 The Bootstrap Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1912 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.min.css.map


+ 331 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css

@@ -0,0 +1,331 @@
+/*!
+ * Bootstrap Reboot v4.1.3 (https://getbootstrap.com/)
+ * Copyright 2011-2018 The Bootstrap Authors
+ * Copyright 2011-2018 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
+ */
+*,
+*::before,
+*::after {
+  box-sizing: border-box;
+}
+
+html {
+  font-family: sans-serif;
+  line-height: 1.15;
+  -webkit-text-size-adjust: 100%;
+  -ms-text-size-adjust: 100%;
+  -ms-overflow-style: scrollbar;
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+
+@-ms-viewport {
+  width: device-width;
+}
+
+article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
+  display: block;
+}
+
+body {
+  margin: 0;
+  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+  font-size: 1rem;
+  font-weight: 400;
+  line-height: 1.5;
+  color: #212529;
+  text-align: left;
+  background-color: #fff;
+}
+
+[tabindex="-1"]:focus {
+  outline: 0 !important;
+}
+
+hr {
+  box-sizing: content-box;
+  height: 0;
+  overflow: visible;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  margin-top: 0;
+  margin-bottom: 0.5rem;
+}
+
+p {
+  margin-top: 0;
+  margin-bottom: 1rem;
+}
+
+abbr[title],
+abbr[data-original-title] {
+  text-decoration: underline;
+  -webkit-text-decoration: underline dotted;
+  text-decoration: underline dotted;
+  cursor: help;
+  border-bottom: 0;
+}
+
+address {
+  margin-bottom: 1rem;
+  font-style: normal;
+  line-height: inherit;
+}
+
+ol,
+ul,
+dl {
+  margin-top: 0;
+  margin-bottom: 1rem;
+}
+
+ol ol,
+ul ul,
+ol ul,
+ul ol {
+  margin-bottom: 0;
+}
+
+dt {
+  font-weight: 700;
+}
+
+dd {
+  margin-bottom: .5rem;
+  margin-left: 0;
+}
+
+blockquote {
+  margin: 0 0 1rem;
+}
+
+dfn {
+  font-style: italic;
+}
+
+b,
+strong {
+  font-weight: bolder;
+}
+
+small {
+  font-size: 80%;
+}
+
+sub,
+sup {
+  position: relative;
+  font-size: 75%;
+  line-height: 0;
+  vertical-align: baseline;
+}
+
+sub {
+  bottom: -.25em;
+}
+
+sup {
+  top: -.5em;
+}
+
+a {
+  color: #007bff;
+  text-decoration: none;
+  background-color: transparent;
+  -webkit-text-decoration-skip: objects;
+}
+
+a:hover {
+  color: #0056b3;
+  text-decoration: underline;
+}
+
+a:not([href]):not([tabindex]) {
+  color: inherit;
+  text-decoration: none;
+}
+
+a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
+  color: inherit;
+  text-decoration: none;
+}
+
+a:not([href]):not([tabindex]):focus {
+  outline: 0;
+}
+
+pre,
+code,
+kbd,
+samp {
+  font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+  font-size: 1em;
+}
+
+pre {
+  margin-top: 0;
+  margin-bottom: 1rem;
+  overflow: auto;
+  -ms-overflow-style: scrollbar;
+}
+
+figure {
+  margin: 0 0 1rem;
+}
+
+img {
+  vertical-align: middle;
+  border-style: none;
+}
+
+svg {
+  overflow: hidden;
+  vertical-align: middle;
+}
+
+table {
+  border-collapse: collapse;
+}
+
+caption {
+  padding-top: 0.75rem;
+  padding-bottom: 0.75rem;
+  color: #6c757d;
+  text-align: left;
+  caption-side: bottom;
+}
+
+th {
+  text-align: inherit;
+}
+
+label {
+  display: inline-block;
+  margin-bottom: 0.5rem;
+}
+
+button {
+  border-radius: 0;
+}
+
+button:focus {
+  outline: 1px dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+}
+
+input,
+button,
+select,
+optgroup,
+textarea {
+  margin: 0;
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+}
+
+button,
+input {
+  overflow: visible;
+}
+
+button,
+select {
+  text-transform: none;
+}
+
+button,
+html [type="button"],
+[type="reset"],
+[type="submit"] {
+  -webkit-appearance: button;
+}
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+  padding: 0;
+  border-style: none;
+}
+
+input[type="radio"],
+input[type="checkbox"] {
+  box-sizing: border-box;
+  padding: 0;
+}
+
+input[type="date"],
+input[type="time"],
+input[type="datetime-local"],
+input[type="month"] {
+  -webkit-appearance: listbox;
+}
+
+textarea {
+  overflow: auto;
+  resize: vertical;
+}
+
+fieldset {
+  min-width: 0;
+  padding: 0;
+  margin: 0;
+  border: 0;
+}
+
+legend {
+  display: block;
+  width: 100%;
+  max-width: 100%;
+  padding: 0;
+  margin-bottom: .5rem;
+  font-size: 1.5rem;
+  line-height: inherit;
+  color: inherit;
+  white-space: normal;
+}
+
+progress {
+  vertical-align: baseline;
+}
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+
+[type="search"] {
+  outline-offset: -2px;
+  -webkit-appearance: none;
+}
+
+[type="search"]::-webkit-search-cancel-button,
+[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+
+::-webkit-file-upload-button {
+  font: inherit;
+  -webkit-appearance: button;
+}
+
+output {
+  display: inline-block;
+}
+
+summary {
+  display: list-item;
+  cursor: pointer;
+}
+
+template {
+  display: none;
+}
+
+[hidden] {
+  display: none !important;
+}
+/*# sourceMappingURL=bootstrap-reboot.css.map */

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 8 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 9030 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap.css.map


+ 0 - 0
HaBookCms.Contest/wwwroot/lib/bootstrap/dist/css/bootstrap.min.css


Vissa filer visades inte eftersom för många filer har ändrats