├── .gitignore ├── BeetleX.Blog ├── BeetleX.Blog.csproj ├── BeetleX.Blog.csproj.user ├── Codes │ ├── CacheHelper.cs │ ├── JWTHelper.cs │ ├── TCloudCosObject.cs │ └── Units.cs ├── Controller │ ├── AdminBlog.cs │ ├── AdminBlog.js │ ├── AdminCategory.cs │ ├── AdminCategory.js │ ├── AdminComment.cs │ ├── AdminComment.js │ ├── AdminPhoto.Model.cs │ ├── AdminPhoto.cs │ ├── AdminPhoto.js │ ├── AdminSetting.cs │ ├── AdminSetting.js │ ├── CacheFilter.cs │ ├── ESExceptionFilter.cs │ ├── FileManagerController.cs │ ├── FileManagerController.js │ ├── Rewrite.cs │ ├── Site.cs │ ├── Site.js │ └── TokenFilter.cs ├── DBModules │ ├── Blog.Model.cs │ ├── Blog.cs │ ├── BoolConvter.cs │ ├── Category.Model.cs │ ├── Category.cs │ ├── Comment.Model.cs │ ├── Comment.cs │ ├── DBHelper.cs │ ├── DateTimeConvter.cs │ ├── IPhoto.Model.cs │ ├── IPhoto.cs │ ├── ISequence.Model.cs │ ├── ISequence.cs │ ├── ISetting.Model.cs │ ├── ISetting.cs │ └── SqliteDriver.cs ├── ES │ ├── ESBlog.cs │ └── ESHelper.cs ├── HttpConfig.json ├── Program.cs ├── beetlex_blog.db ├── bundleconfig.json ├── main.sql └── views │ ├── PublicModule.html │ ├── admin │ ├── about.html │ ├── blogeditor.html │ ├── categories.html │ ├── comments.html │ ├── connections.html │ ├── files.html │ ├── index.html │ ├── login.html │ ├── password.html │ ├── photoitems.html │ ├── photos.html │ ├── setting.html │ └── system.html │ ├── blog.html │ ├── css │ ├── admin.css │ ├── bootstrap-theme.css │ ├── bootstrap.css │ └── site.css │ ├── favicon.ico │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 │ ├── images │ ├── admin │ │ ├── about.png │ │ ├── admin.png │ │ ├── blog.png │ │ ├── cate.png │ │ ├── connections.png │ │ ├── down.png │ │ ├── exit.png │ │ ├── file.png │ │ ├── home.png │ │ ├── home_page.png │ │ ├── nav.png │ │ ├── password.png │ │ ├── photo.png │ │ ├── setting.png │ │ ├── statu_error.png │ │ ├── statu_ok.png │ │ ├── system.png │ │ ├── tag.png │ │ ├── talk.png │ │ └── up.png │ ├── ajax-loader.gif │ ├── category.png │ ├── date.png │ ├── home_icon.png │ ├── img_view_close.png │ ├── refresh.png │ ├── search.png │ ├── small_img.jpg │ ├── small_img.png │ ├── some.png │ ├── tags.png │ ├── user.png │ └── white.gif │ ├── index.html │ ├── js │ ├── AdminController.js │ ├── FastHttpApi.js │ ├── FileManagerController.Model.cs │ ├── FileManagerController.js │ ├── ModuleLoader.js │ ├── Monitor.js │ ├── ReadFileHandler.Model.cs │ ├── ReadFileHandler.js │ ├── Site.js │ ├── admin │ │ ├── AdminBlog.js │ │ ├── AdminCategory.js │ │ ├── AdminComment.js │ │ ├── AdminPhoto.js │ │ ├── AdminSetting.js │ │ ├── FileManagerController.js │ │ └── ReadFileHandler.js │ ├── bootstrap.js │ ├── bundle.js │ ├── bundle.min.js │ ├── highlight_min.js │ ├── highlight_pack.js │ ├── jquery.js │ ├── jquery_goup.js │ ├── lodash.js │ ├── marked.js │ ├── md5.js │ ├── vue-lazyload.js │ └── vue.js │ ├── photos.html │ └── tags.html ├── LICENSE ├── Publish ├── XBlog.zip ├── XBlog0.5.8.0.zip └── XBlog1.0.zip ├── README.md └── XBlog.sln /.gitignore: -------------------------------------------------------------------------------- 1 | BeetleX.Blog/Properties/ 2 | BeetleX.Blog/bin/ 3 | BeetleX.Blog/obj/ 4 | .vs/XBlog/v15/ 5 | .vs/ 6 | -------------------------------------------------------------------------------- /BeetleX.Blog/BeetleX.Blog.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | false 5 | <_LastSelectedProfileId>D:\VisualStudio\BitHub\XBlog\BeetleX.Blog\Properties\PublishProfiles\FolderProfile.pubxml 6 | 7 | -------------------------------------------------------------------------------- /BeetleX.Blog/Codes/CacheHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Concurrent; 4 | using System.Text; 5 | 6 | namespace BeetleX.Blog 7 | { 8 | public class CacheHelper 9 | { 10 | 11 | private static ConcurrentDictionary mCache = new ConcurrentDictionary(); 12 | 13 | public static object Get(string key) 14 | { 15 | if (mCache.TryGetValue(key, out CacheItem item)) 16 | { 17 | if (TimeWatch.GetTotalSeconds() > item.ActiveTime) 18 | { 19 | return null; 20 | } 21 | return item.Data; 22 | } 23 | return null; 24 | } 25 | 26 | public static T Get(string key) 27 | { 28 | return (T)Get(key); 29 | } 30 | 31 | public static void Set(string key, object data, double seconds = 60) 32 | { 33 | CacheItem item = new CacheItem(); 34 | item.Data = data; 35 | item.ActiveTime = TimeWatch.GetTotalSeconds() + seconds; 36 | mCache[key] = item; 37 | } 38 | 39 | class CacheItem 40 | { 41 | public object Data { get; set; } 42 | 43 | public double ActiveTime { get; set; } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /BeetleX.Blog/Codes/JWTHelper.cs: -------------------------------------------------------------------------------- 1 | using BeetleX.FastHttpApi; 2 | using Microsoft.IdentityModel.Tokens; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IdentityModel.Tokens.Jwt; 6 | using System.Linq; 7 | using System.Security.Claims; 8 | using System.Text; 9 | 10 | namespace BeetleX.Blog 11 | { 12 | public class JWTHelper 13 | { 14 | public const string TOKEN_KEY = "Token"; 15 | 16 | private string mIssuer = null; 17 | 18 | private string mAudience = null; 19 | 20 | private SecurityKey mSecurityKey; 21 | 22 | private SigningCredentials mSigningCredentials; 23 | 24 | private TokenValidationParameters mTokenValidation = new TokenValidationParameters(); 25 | 26 | private JwtSecurityTokenHandler mJwtSecurityTokenHandler = new JwtSecurityTokenHandler(); 27 | 28 | public JWTHelper(string issuer, string audience, byte[] key) 29 | { 30 | mIssuer = issuer; 31 | mAudience = audience; 32 | mSecurityKey = new SymmetricSecurityKey(key); 33 | if (string.IsNullOrEmpty(mIssuer)) 34 | { 35 | mTokenValidation.ValidateIssuer = false; 36 | } 37 | else 38 | { 39 | mTokenValidation.ValidIssuer = mIssuer; 40 | } 41 | if (string.IsNullOrEmpty(mAudience)) 42 | { 43 | mTokenValidation.ValidateAudience = false; 44 | } 45 | else 46 | { 47 | mTokenValidation.ValidAudience = mAudience; 48 | } 49 | mTokenValidation.IssuerSigningKey = mSecurityKey; 50 | mSigningCredentials = new SigningCredentials(mSecurityKey, SecurityAlgorithms.HmacSha256); 51 | Expires = 60 * 24; 52 | } 53 | 54 | public int Expires { get; set; } 55 | 56 | 57 | 58 | public void ClearToken(HttpResponse response) 59 | { 60 | response.SetCookie(TOKEN_KEY, "", "/", DateTime.Now); 61 | } 62 | 63 | public void CreateToken(HttpResponse response, string name, string role, int timeout = 20) 64 | { 65 | string token = CreateToken(name, role, timeout); 66 | response.SetCookie(TOKEN_KEY, token, "/", DateTime.Now.AddDays(100)); 67 | } 68 | 69 | public string CreateToken(string name, string role, int timeout = 20) 70 | { 71 | ClaimsIdentity claimsIdentity = new ClaimsIdentity(); 72 | claimsIdentity.AddClaim(new Claim("Name", name)); 73 | claimsIdentity.AddClaim(new Claim("Role", role)); 74 | var item = mJwtSecurityTokenHandler.CreateEncodedJwt(mIssuer, mAudience, claimsIdentity, DateTime.Now.AddMinutes(-5), 75 | DateTime.Now.AddMinutes(timeout), DateTime.Now, 76 | mSigningCredentials); 77 | return item; 78 | } 79 | 80 | public ClaimsPrincipal ValidateToken(string token) 81 | { 82 | return mJwtSecurityTokenHandler.ValidateToken(token, mTokenValidation, out var securityToken); 83 | } 84 | 85 | public UserInfo GetUserInfo(HttpRequest request) 86 | { 87 | string token = request.Cookies[TOKEN_KEY]; 88 | if (string.IsNullOrEmpty(token)) 89 | return null; 90 | try 91 | { 92 | return GetUserInfo(token); 93 | } 94 | catch (Exception e_) 95 | { 96 | HttpApiServer server = request.Server; 97 | if (server.EnableLog(EventArgs.LogType.Info)) 98 | { 99 | server.Log(EventArgs.LogType.Info, $"{request.RemoteIPAddress} get token error {e_.Message}"); 100 | } 101 | return null; 102 | } 103 | 104 | } 105 | 106 | public UserInfo GetUserInfo(string token) 107 | { 108 | UserInfo userInfo = new UserInfo(); 109 | if (!string.IsNullOrEmpty(token)) 110 | { 111 | var info = ValidateToken(token); 112 | ClaimsIdentity identity = info?.Identity as ClaimsIdentity; 113 | userInfo.Name = identity?.Claims?.FirstOrDefault(c => c.Type == "Name")?.Value; 114 | userInfo.Role = identity?.Claims?.FirstOrDefault(c => c.Type == "Role")?.Value; 115 | } 116 | return userInfo; 117 | } 118 | 119 | public class UserInfo 120 | { 121 | public string Name; 122 | 123 | public string Role; 124 | } 125 | 126 | public static JWTHelper Default 127 | { 128 | get; 129 | set; 130 | } 131 | 132 | public static void Init() 133 | { 134 | Default = new JWTHelper("BeetleX", "BeetleX", Convert.FromBase64String(DBModules.DBHelper.Default.Setting.JwtKey.Value)); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /BeetleX.Blog/Codes/TCloudCosObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Net; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | 8 | namespace BeetleX.Blog 9 | { 10 | public class TCloudCosObject 11 | { 12 | public TCloudCosObject(string secretId, string secretKey, string host) 13 | { 14 | 15 | if (host[host.Length - 1] == '/') 16 | host = host.Substring(0, host.Length - 1); 17 | Host = host; 18 | SecretId = secretId; 19 | SecretKey = secretKey; 20 | } 21 | 22 | public static int DefaultConnectionLimit 23 | { 24 | get 25 | { 26 | return ServicePointManager.DefaultConnectionLimit; 27 | } 28 | set 29 | { 30 | ServicePointManager.DefaultConnectionLimit = value; 31 | } 32 | } 33 | 34 | public string Host { get; set; } 35 | 36 | public string SecretId { get; set; } 37 | 38 | public string SecretKey { get; set; } 39 | 40 | private string GetSignature(string method, string filename) 41 | { 42 | method = method.ToLower(); 43 | if (filename.IndexOf("/") != 0) 44 | { 45 | filename = "/" + filename; 46 | } 47 | var baseDate = new System.DateTime(1970, 1, 1); 48 | var now = (int)(DateTime.Now.AddDays(-5) - baseDate).TotalSeconds; 49 | var exp = (int)(DateTime.Now.AddMinutes(2) - baseDate).TotalSeconds; 50 | string signTime = now + ";" + exp; 51 | string keyTime = signTime; 52 | string singKey = HmacSha1Sign(keyTime, SecretKey); 53 | string httpString = method + "\n" + filename + "\n\n\n"; 54 | string sha1edHttpString = EncryptToSHA1(httpString); 55 | string stringToSign = $"sha1\n{signTime}\n{sha1edHttpString}\n"; 56 | string signature = HmacSha1Sign(stringToSign, singKey); 57 | var authorization = $"q-sign-algorithm=sha1&q-ak={SecretId}&q-sign-time={signTime}&q-key-time={signTime}&q-header-list=&q-url-param-list=&q-signature={signature}"; 58 | return authorization; 59 | } 60 | 61 | public string GetPutToken(string file) 62 | { 63 | return GetSignature("put", file); 64 | } 65 | 66 | public string GetPutUrl(string file) 67 | { 68 | if (file[0] != '/') 69 | file = "/" + file; 70 | return Host + file; 71 | } 72 | 73 | private string EncryptToSHA1(string str) 74 | { 75 | var buffer = Encoding.UTF8.GetBytes(str); 76 | var data = System.Security.Cryptography.SHA1.Create().ComputeHash(buffer); 77 | var sb = new StringBuilder(); 78 | foreach (var t in data) 79 | { 80 | sb.Append(t.ToString("X2")); 81 | } 82 | return sb.ToString().ToLower(); 83 | } 84 | 85 | private string HmacSha1Sign(string EncryptText, string EncryptKey) 86 | { 87 | HMACSHA1 myHMACSHA1 = new HMACSHA1(Encoding.Default.GetBytes(EncryptKey)); 88 | byte[] RstRes = myHMACSHA1.ComputeHash(Encoding.Default.GetBytes(EncryptText)); 89 | StringBuilder EnText = new StringBuilder(); 90 | foreach (byte Byte in RstRes) 91 | { 92 | EnText.AppendFormat("{0:x2}", Byte); 93 | } 94 | return EnText.ToString(); 95 | } 96 | 97 | public bool Put(string file, string localFile) 98 | { 99 | using (System.IO.Stream stream = System.IO.File.OpenRead(localFile)) 100 | { 101 | byte[] data = new byte[stream.Length]; 102 | stream.Read(data, 0, data.Length); 103 | return Put(file, data); 104 | } 105 | } 106 | 107 | public bool Put(string file, byte[] data) 108 | { 109 | if (file[0] != '/') 110 | file = "/" + file; 111 | var sign = GetSignature("put", file); 112 | string url = Host + file; 113 | WebClient webClient = new WebClient(); 114 | webClient.Headers.Add("Authorization", sign); 115 | webClient.Credentials = CredentialCache.DefaultCredentials; 116 | try 117 | { 118 | Stream postStream = webClient.OpenWrite(url, "PUT"); 119 | postStream.Write(data, 0, data.Length); 120 | postStream.Close(); 121 | } 122 | catch (WebException webError) 123 | { 124 | string errorText; 125 | using (System.IO.StreamReader reader = new StreamReader(webError.Response.GetResponseStream())) 126 | { 127 | errorText = reader.ReadToEnd(); 128 | } 129 | throw new Exception(errorText, webError); 130 | } 131 | return true; 132 | } 133 | 134 | public bool Del(string file) 135 | { 136 | if (file[0] != '/') 137 | file = "/" + file; 138 | var sign = GetSignature("DELETE", file); 139 | string url = Host + file; 140 | var request = (HttpWebRequest)WebRequest.Create(url); 141 | request.Method = "DELETE"; 142 | request.Headers.Add("Authorization", sign); 143 | try 144 | { 145 | var response = (HttpWebResponse)request.GetResponse(); 146 | var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd(); 147 | } 148 | catch (WebException webError) 149 | { 150 | string errorText; 151 | using (System.IO.StreamReader reader = new StreamReader(webError.Response.GetResponseStream())) 152 | { 153 | errorText = reader.ReadToEnd(); 154 | } 155 | throw new Exception(errorText, webError); 156 | } 157 | return true; 158 | } 159 | 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /BeetleX.Blog/Codes/Units.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Security.Cryptography; 4 | using System.Text; 5 | 6 | namespace BeetleX.Blog 7 | { 8 | class Units 9 | { 10 | 11 | 12 | public static string MD5Encrypt(string value) 13 | { 14 | using (MD5 md5Hash = MD5.Create()) 15 | { 16 | byte[] hash = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(value)); 17 | 18 | return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); 19 | } 20 | } 21 | 22 | public static string ImagePath { get; set; } 23 | 24 | public static string GetImageUrl(string url) 25 | { 26 | string[] host = null; 27 | if (string.IsNullOrEmpty(url)) 28 | url = "/images/small_img.jpg"; 29 | if (!string.IsNullOrEmpty(DBModules.DBHelper.Default.Setting.ImgHost.Value)) 30 | { 31 | host = DBModules.DBHelper.Default.Setting.ImgHost.Value.Split(';', StringSplitOptions.RemoveEmptyEntries); 32 | } 33 | if (host == null || host.Length == 0) 34 | return url; 35 | else 36 | { 37 | string imghost = "http://" + host[Math.Abs(url.GetHashCode()) % host.Length]; 38 | return imghost + url; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/AdminBlog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using BeetleX.FastHttpApi; 5 | using Peanut; 6 | using BeetleX.Blog.DBModules; 7 | using System.Linq; 8 | namespace BeetleX.Blog.Controller 9 | { 10 | [Controller(BaseUrl = "/admin/blog")] 11 | [AdminFilter] 12 | public class AdminBlog 13 | { 14 | [Post] 15 | public void Modify(long id, string title, bool top, string tag, long category, string sourceUrl, string content, 16 | string summary) 17 | { 18 | DBModules.Blog item; 19 | if (id > 0) 20 | { 21 | item = DBContext.Load(id); 22 | } 23 | else 24 | { 25 | item = new DBModules.Blog(); 26 | } 27 | if (item != null) 28 | { 29 | item.Title = title; 30 | item.Top = top; 31 | item.Tags = tag; 32 | item.CategoryID = category; 33 | Category cate = DBContext.Load(category); 34 | if (cate != null) 35 | item.Category = cate.Name; 36 | item.SourceUrl = sourceUrl; 37 | item.Content = content; 38 | item.Summary = summary; 39 | item.Save(); 40 | RefreshBlog refreshBlog = new RefreshBlog(); 41 | refreshBlog.BlogID = item.ID; 42 | refreshBlog.Status = 1; 43 | refreshBlog.Save(); 44 | } 45 | } 46 | 47 | public void AllSyncToES() 48 | { 49 | foreach (DBModules.Blog item in new Expression().List()) 50 | { 51 | RefreshBlog refreshBlog = new RefreshBlog(); 52 | refreshBlog.BlogID = item.ID; 53 | refreshBlog.Status = 1; 54 | refreshBlog.Save(); 55 | } 56 | } 57 | 58 | [Post] 59 | public void Delete(long[] id) 60 | { 61 | if (id != null && id.Length > 0) 62 | { 63 | (DBModules.Blog.iD == id).Delete(); 64 | (DBModules.Comment.blogID == id).Delete(); 65 | foreach (var item in id) 66 | { 67 | RefreshBlog refreshBlog = new RefreshBlog(); 68 | refreshBlog.BlogID = item; 69 | refreshBlog.Status = 0; 70 | refreshBlog.Save(); 71 | } 72 | } 73 | } 74 | 75 | public object Get(long id) 76 | { 77 | var item = DBContext.Load(id); 78 | if (item != null) 79 | return new { item.ID, item.Title, item.Content, item.CategoryID, item.SourceUrl, item.Tags, item.Top }; 80 | return new object(); 81 | } 82 | 83 | public Object List(long category, int index) 84 | { 85 | int size = 15; 86 | Expression exp = new Expression(); 87 | if (category > 0) 88 | exp &= DBModules.Blog.categoryID == category; 89 | int count = exp.Count(); 90 | int pages = count / size; 91 | if (count % size > 0) 92 | pages++; 93 | var datas = exp.List(new Region(index, size), DBModules.Blog.createTime.Desc); 94 | var items = from a in datas select new { a.ID, a.Title, a.Category, a.Top, CreateTime = a.CreateTime.ToString() }; 95 | return new { Index = index, Pages = pages, Items = items }; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/AdminBlog.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | FastHttpApi javascript api Generator Copyright © henryfan 2018 email:henryfan@msn.com 3 | https://github.com/IKende/FastHttpApi 4 | **************************************************************************************/ 5 | 6 | 7 | 8 | 9 | var AdminBlogModifyUrl='/admin/blog/Modify'; 10 | /** 11 | * 'var result= await AdminBlogModify(params);' 12 | **/ 13 | function AdminBlogModify(id,title,top,tag,category,sourceUrl,content,summary,useHttp) 14 | { 15 | return api(AdminBlogModifyUrl,{id:id,title:title,top:top,tag:tag,category:category,sourceUrl:sourceUrl,content:content,summary:summary},useHttp,true).sync(); 16 | } 17 | /** 18 | * 'AdminBlogModifyAsync(params).execute(function(result){},useHttp);' 19 | **/ 20 | function AdminBlogModifyAsync(id,title,top,tag,category,sourceUrl,content,summary,useHttp) 21 | { 22 | return api(AdminBlogModifyUrl,{id:id,title:title,top:top,tag:tag,category:category,sourceUrl:sourceUrl,content:content,summary:summary},useHttp,true); 23 | } 24 | var AdminBlogAllSyncToESUrl='/admin/blog/AllSyncToES'; 25 | /** 26 | * 'var result= await AdminBlogAllSyncToES(params);' 27 | **/ 28 | function AdminBlogAllSyncToES(useHttp) 29 | { 30 | return api(AdminBlogAllSyncToESUrl,{},useHttp).sync(); 31 | } 32 | /** 33 | * 'AdminBlogAllSyncToESAsync(params).execute(function(result){},useHttp);' 34 | **/ 35 | function AdminBlogAllSyncToESAsync(useHttp) 36 | { 37 | return api(AdminBlogAllSyncToESUrl,{},useHttp); 38 | } 39 | var AdminBlogDeleteUrl='/admin/blog/Delete'; 40 | /** 41 | * 'var result= await AdminBlogDelete(params);' 42 | **/ 43 | function AdminBlogDelete(id,useHttp) 44 | { 45 | return api(AdminBlogDeleteUrl,{id:id},useHttp,true).sync(); 46 | } 47 | /** 48 | * 'AdminBlogDeleteAsync(params).execute(function(result){},useHttp);' 49 | **/ 50 | function AdminBlogDeleteAsync(id,useHttp) 51 | { 52 | return api(AdminBlogDeleteUrl,{id:id},useHttp,true); 53 | } 54 | var AdminBlogGetUrl='/admin/blog/Get'; 55 | /** 56 | * 'var result= await AdminBlogGet(params);' 57 | **/ 58 | function AdminBlogGet(id,useHttp) 59 | { 60 | return api(AdminBlogGetUrl,{id:id},useHttp).sync(); 61 | } 62 | /** 63 | * 'AdminBlogGetAsync(params).execute(function(result){},useHttp);' 64 | **/ 65 | function AdminBlogGetAsync(id,useHttp) 66 | { 67 | return api(AdminBlogGetUrl,{id:id},useHttp); 68 | } 69 | var AdminBlogListUrl='/admin/blog/List'; 70 | /** 71 | * 'var result= await AdminBlogList(params);' 72 | **/ 73 | function AdminBlogList(category,index,useHttp) 74 | { 75 | return api(AdminBlogListUrl,{category:category,index:index},useHttp).sync(); 76 | } 77 | /** 78 | * 'AdminBlogListAsync(params).execute(function(result){},useHttp);' 79 | **/ 80 | function AdminBlogListAsync(category,index,useHttp) 81 | { 82 | return api(AdminBlogListUrl,{category:category,index:index},useHttp); 83 | } 84 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/AdminCategory.cs: -------------------------------------------------------------------------------- 1 | using BeetleX.FastHttpApi; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using BeetleX.Blog.DBModules; 6 | using System.Linq; 7 | using Peanut; 8 | namespace BeetleX.Blog.Controller 9 | { 10 | [Controller(BaseUrl = "/admin/category")] 11 | [AdminFilter] 12 | public class AdminCategory 13 | { 14 | [Post] 15 | public void Add(string name, string remark) 16 | { 17 | if ((Category.name == name).Count() == 0) 18 | { 19 | Category category = new Category(); 20 | category.Name = name; 21 | category.Remark = remark; 22 | category.Save(); 23 | } 24 | } 25 | 26 | public void Order(long id, bool up) 27 | { 28 | Category item = DBContext.Load(id); 29 | if (item != null) 30 | { 31 | if (up) 32 | item.OrderBy -= 1; 33 | else 34 | item.OrderBy += 1; 35 | item.Save(); 36 | } 37 | } 38 | 39 | public void Del(long id) 40 | { 41 | (Category.iD == id).Delete(); 42 | } 43 | 44 | public object List() 45 | { 46 | var items = new Expression().List(Category.orderBy.Asc); 47 | return from a in items 48 | select new { a.ID, a.Name, a.Remark }; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/AdminCategory.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | FastHttpApi javascript api Generator Copyright © henryfan 2018 email:henryfan@msn.com 3 | https://github.com/IKende/FastHttpApi 4 | **************************************************************************************/ 5 | 6 | 7 | 8 | 9 | var AdminCategoryAddUrl='/admin/category/Add'; 10 | /** 11 | * 'var result= await AdminCategoryAdd(params);' 12 | **/ 13 | function AdminCategoryAdd(name,remark,useHttp) 14 | { 15 | return api(AdminCategoryAddUrl,{name:name,remark:remark},useHttp,true).sync(); 16 | } 17 | /** 18 | * 'AdminCategoryAddAsync(params).execute(function(result){},useHttp);' 19 | **/ 20 | function AdminCategoryAddAsync(name,remark,useHttp) 21 | { 22 | return api(AdminCategoryAddUrl,{name:name,remark:remark},useHttp,true); 23 | } 24 | var AdminCategoryOrderUrl='/admin/category/Order'; 25 | /** 26 | * 'var result= await AdminCategoryOrder(params);' 27 | **/ 28 | function AdminCategoryOrder(id,up,useHttp) 29 | { 30 | return api(AdminCategoryOrderUrl,{id:id,up:up},useHttp).sync(); 31 | } 32 | /** 33 | * 'AdminCategoryOrderAsync(params).execute(function(result){},useHttp);' 34 | **/ 35 | function AdminCategoryOrderAsync(id,up,useHttp) 36 | { 37 | return api(AdminCategoryOrderUrl,{id:id,up:up},useHttp); 38 | } 39 | var AdminCategoryDelUrl='/admin/category/Del'; 40 | /** 41 | * 'var result= await AdminCategoryDel(params);' 42 | **/ 43 | function AdminCategoryDel(id,useHttp) 44 | { 45 | return api(AdminCategoryDelUrl,{id:id},useHttp).sync(); 46 | } 47 | /** 48 | * 'AdminCategoryDelAsync(params).execute(function(result){},useHttp);' 49 | **/ 50 | function AdminCategoryDelAsync(id,useHttp) 51 | { 52 | return api(AdminCategoryDelUrl,{id:id},useHttp); 53 | } 54 | var AdminCategoryListUrl='/admin/category/List'; 55 | /** 56 | * 'var result= await AdminCategoryList(params);' 57 | **/ 58 | function AdminCategoryList(useHttp) 59 | { 60 | return api(AdminCategoryListUrl,{},useHttp).sync(); 61 | } 62 | /** 63 | * 'AdminCategoryListAsync(params).execute(function(result){},useHttp);' 64 | **/ 65 | function AdminCategoryListAsync(useHttp) 66 | { 67 | return api(AdminCategoryListUrl,{},useHttp); 68 | } 69 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/AdminComment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using BeetleX.FastHttpApi; 6 | using Peanut; 7 | namespace BeetleX.Blog.Controller 8 | { 9 | [Controller(BaseUrl = "/admin/comment")] 10 | [AdminFilter] 11 | public class AdminComment 12 | { 13 | public object List(int index) 14 | { 15 | int size = 15; 16 | Expression exp = new Expression(); 17 | int Pages; 18 | int count = exp.Count(); 19 | Pages = count / size; 20 | if (count % size > 0) 21 | Pages++; 22 | var items = exp.List(new Region(index, size), DBModules.Comment.createTime.At().Desc); 23 | var Items = from a in items select new { a.ID, a.CommentID, a.Title, a.NickName, a.Content, CreateTime = a.CreateTime.ToString() }; 24 | return new { Pages, Items }; 25 | } 26 | 27 | public void Del(long[] id) 28 | { 29 | if (id != null && id.Length > 0) 30 | { 31 | (DBModules.Comment.iD == id).Delete(); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/AdminComment.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | FastHttpApi javascript api Generator Copyright © henryfan 2018 email:henryfan@msn.com 3 | https://github.com/IKende/FastHttpApi 4 | **************************************************************************************/ 5 | 6 | 7 | 8 | 9 | var AdminCommentListUrl='/admin/comment/List'; 10 | /** 11 | * 'var result= await AdminCommentList(params);' 12 | **/ 13 | function AdminCommentList(index,useHttp) 14 | { 15 | return api(AdminCommentListUrl,{index:index},useHttp).sync(); 16 | } 17 | /** 18 | * 'AdminCommentListAsync(params).execute(function(result){},useHttp);' 19 | **/ 20 | function AdminCommentListAsync(index,useHttp) 21 | { 22 | return api(AdminCommentListUrl,{index:index},useHttp); 23 | } 24 | var AdminCommentDelUrl='/admin/comment/Del'; 25 | /** 26 | * 'var result= await AdminCommentDel(params);' 27 | **/ 28 | function AdminCommentDel(id,useHttp) 29 | { 30 | return api(AdminCommentDelUrl,{id:id},useHttp).sync(); 31 | } 32 | /** 33 | * 'AdminCommentDelAsync(params).execute(function(result){},useHttp);' 34 | **/ 35 | function AdminCommentDelAsync(id,useHttp) 36 | { 37 | return api(AdminCommentDelUrl,{id:id},useHttp); 38 | } 39 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/AdminPhoto.Model.cs: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/AdminPhoto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using BeetleX.FastHttpApi; 5 | using BeetleX.Blog.DBModules; 6 | using Peanut; 7 | using System.Linq; 8 | using BeetleX.FastHttpApi.Data; 9 | 10 | namespace BeetleX.Blog.Controller 11 | { 12 | [Controller(BaseUrl = "/admin/photo")] 13 | [AdminFilter] 14 | public class AdminPhoto 15 | { 16 | 17 | public void Add(string title) 18 | { 19 | Photo photo = new Photo(); 20 | photo.Title = title; 21 | photo.Save(); 22 | } 23 | 24 | public void Del(long[] id) 25 | { 26 | if (id != null && id.Length > 0) 27 | { 28 | (PhotoItem.photoID == id).Delete(); 29 | (Photo.iD == id).Delete(); 30 | } 31 | } 32 | 33 | private static byte[] mImageBuffer = new byte[1024 * 1024]; 34 | 35 | public void SetDefault(string id) 36 | { 37 | PhotoItem item = DBContext.Load(id); 38 | if (item != null) 39 | { 40 | Photo photo = DBContext.Load(item.PhotoID); 41 | if (photo != null) 42 | { 43 | photo.SmallUrl = item.SmallUrl; 44 | photo.LargeUrl = item.LargeUrl; 45 | photo.Save(); 46 | } 47 | } 48 | } 49 | 50 | public string GetImageID() 51 | { 52 | return DBHelper.Default.GetSequence("photo_key").ToString(); 53 | } 54 | 55 | [Put] 56 | [NoDataConvert] 57 | public void UploadImage(string id, string file, long photoid, bool large, HttpRequest request) 58 | { 59 | lock (mImageBuffer) 60 | { 61 | Photo photo = DBContext.Load(photoid); 62 | if (photo != null) 63 | { 64 | request.Stream.Read(mImageBuffer, 0, request.Length); 65 | if (!large) 66 | file = "s_" + file; 67 | string fileUrl = SaveImage(file, mImageBuffer, request.Length); 68 | 69 | PhotoItem item = DBContext.Load(id); 70 | if (item == null) 71 | { 72 | item = new PhotoItem(); 73 | item.ID = id; 74 | } 75 | item.PhotoID = photo.ID; 76 | if (large) 77 | item.LargeUrl = fileUrl; 78 | else 79 | item.SmallUrl = fileUrl; 80 | item.Save(); 81 | if (string.IsNullOrEmpty(photo.LargeUrl) || string.IsNullOrEmpty(photo.SmallUrl)) 82 | { 83 | photo.LargeUrl = item.LargeUrl; 84 | photo.SmallUrl = item.SmallUrl; 85 | photo.Save(); 86 | } 87 | } 88 | } 89 | } 90 | 91 | private string SaveImage(string file, byte[] data, int length) 92 | { 93 | int code = Math.Abs(file.GetHashCode()); 94 | string subfolder = (code % 10).ToString("00"); 95 | string filename = Units.ImagePath + subfolder 96 | + System.IO.Path.DirectorySeparatorChar + file; 97 | using (System.IO.Stream stream = System.IO.File.Create(filename)) 98 | { 99 | stream.Write(data, 0, length); 100 | stream.Flush(); 101 | } 102 | string url = "/images/" + subfolder + "/" + file; 103 | return url; 104 | } 105 | 106 | 107 | public void DelItem(string[] id) 108 | { 109 | (PhotoItem.iD == id).Delete(); 110 | } 111 | 112 | public object Get(long id) 113 | { 114 | Photo photo = DBContext.Load(id); 115 | var items = (PhotoItem.photoID == id).List(); 116 | var Items = from a in items select new { a.ID, a.SmallUrl }; 117 | return new { photo.Title, Items }; 118 | } 119 | 120 | public object List(int index) 121 | { 122 | int size = 10; 123 | Expression expression = new Expression(); 124 | int Count = expression.Count(); 125 | int Pages = Count / size; 126 | if (Count % size > 0) 127 | Pages++; 128 | var items = expression.List(new Region(index, size), Photo.createTime.Desc); 129 | var Items = from a in items 130 | select new 131 | { 132 | a.ID, 133 | a.Title, 134 | CreateTime = a.CreateTime.ToShortDateString(), 135 | SmallUrl = Blog.Units.GetImageUrl(a.SmallUrl) 136 | }; 137 | return new { Count, Pages, Items }; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/AdminPhoto.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | FastHttpApi javascript api Generator Copyright © henryfan 2018 email:henryfan@msn.com 3 | https://github.com/IKende/FastHttpApi 4 | **************************************************************************************/ 5 | 6 | 7 | 8 | 9 | var AdminPhotoAddUrl='/admin/photo/Add'; 10 | /** 11 | * 'var result= await AdminPhotoAdd(params);' 12 | **/ 13 | function AdminPhotoAdd(title,useHttp) 14 | { 15 | return api(AdminPhotoAddUrl,{title:title},useHttp).sync(); 16 | } 17 | /** 18 | * 'AdminPhotoAddAsync(params).execute(function(result){},useHttp);' 19 | **/ 20 | function AdminPhotoAddAsync(title,useHttp) 21 | { 22 | return api(AdminPhotoAddUrl,{title:title},useHttp); 23 | } 24 | var AdminPhotoDelUrl='/admin/photo/Del'; 25 | /** 26 | * 'var result= await AdminPhotoDel(params);' 27 | **/ 28 | function AdminPhotoDel(id,useHttp) 29 | { 30 | return api(AdminPhotoDelUrl,{id:id},useHttp).sync(); 31 | } 32 | /** 33 | * 'AdminPhotoDelAsync(params).execute(function(result){},useHttp);' 34 | **/ 35 | function AdminPhotoDelAsync(id,useHttp) 36 | { 37 | return api(AdminPhotoDelUrl,{id:id},useHttp); 38 | } 39 | var AdminPhotoSetDefaultUrl='/admin/photo/SetDefault'; 40 | /** 41 | * 'var result= await AdminPhotoSetDefault(params);' 42 | **/ 43 | function AdminPhotoSetDefault(id,useHttp) 44 | { 45 | return api(AdminPhotoSetDefaultUrl,{id:id},useHttp).sync(); 46 | } 47 | /** 48 | * 'AdminPhotoSetDefaultAsync(params).execute(function(result){},useHttp);' 49 | **/ 50 | function AdminPhotoSetDefaultAsync(id,useHttp) 51 | { 52 | return api(AdminPhotoSetDefaultUrl,{id:id},useHttp); 53 | } 54 | var AdminPhotoGetImageIDUrl='/admin/photo/GetImageID'; 55 | /** 56 | * 'var result= await AdminPhotoGetImageID(params);' 57 | **/ 58 | function AdminPhotoGetImageID(useHttp) 59 | { 60 | return api(AdminPhotoGetImageIDUrl,{},useHttp).sync(); 61 | } 62 | /** 63 | * 'AdminPhotoGetImageIDAsync(params).execute(function(result){},useHttp);' 64 | **/ 65 | function AdminPhotoGetImageIDAsync(useHttp) 66 | { 67 | return api(AdminPhotoGetImageIDUrl,{},useHttp); 68 | } 69 | var AdminPhotoUploadImageUrl='/admin/photo/UploadImage'; 70 | /** 71 | * 'var result= await AdminPhotoUploadImage(params);' 72 | **/ 73 | function AdminPhotoUploadImage(id,file,photoid,large,useHttp) 74 | { 75 | return api(AdminPhotoUploadImageUrl,{id:id,file:file,photoid:photoid,large:large},useHttp).sync(); 76 | } 77 | /** 78 | * 'AdminPhotoUploadImageAsync(params).execute(function(result){},useHttp);' 79 | **/ 80 | function AdminPhotoUploadImageAsync(id,file,photoid,large,useHttp) 81 | { 82 | return api(AdminPhotoUploadImageUrl,{id:id,file:file,photoid:photoid,large:large},useHttp); 83 | } 84 | var AdminPhotoDelItemUrl='/admin/photo/DelItem'; 85 | /** 86 | * 'var result= await AdminPhotoDelItem(params);' 87 | **/ 88 | function AdminPhotoDelItem(id,useHttp) 89 | { 90 | return api(AdminPhotoDelItemUrl,{id:id},useHttp).sync(); 91 | } 92 | /** 93 | * 'AdminPhotoDelItemAsync(params).execute(function(result){},useHttp);' 94 | **/ 95 | function AdminPhotoDelItemAsync(id,useHttp) 96 | { 97 | return api(AdminPhotoDelItemUrl,{id:id},useHttp); 98 | } 99 | var AdminPhotoGetUrl='/admin/photo/Get'; 100 | /** 101 | * 'var result= await AdminPhotoGet(params);' 102 | **/ 103 | function AdminPhotoGet(id,useHttp) 104 | { 105 | return api(AdminPhotoGetUrl,{id:id},useHttp).sync(); 106 | } 107 | /** 108 | * 'AdminPhotoGetAsync(params).execute(function(result){},useHttp);' 109 | **/ 110 | function AdminPhotoGetAsync(id,useHttp) 111 | { 112 | return api(AdminPhotoGetUrl,{id:id},useHttp); 113 | } 114 | var AdminPhotoListUrl='/admin/photo/List'; 115 | /** 116 | * 'var result= await AdminPhotoList(params);' 117 | **/ 118 | function AdminPhotoList(index,useHttp) 119 | { 120 | return api(AdminPhotoListUrl,{index:index},useHttp).sync(); 121 | } 122 | /** 123 | * 'AdminPhotoListAsync(params).execute(function(result){},useHttp);' 124 | **/ 125 | function AdminPhotoListAsync(index,useHttp) 126 | { 127 | return api(AdminPhotoListUrl,{index:index},useHttp); 128 | } 129 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/CacheFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using BeetleX.FastHttpApi; 5 | namespace BeetleX.Blog.Controller 6 | { 7 | public class HttpCacheFilter : FilterAttribute 8 | { 9 | public HttpCacheFilter(int seconds = 300) 10 | { 11 | Seconds = seconds; 12 | } 13 | 14 | public int Seconds { get; set; } 15 | 16 | public override void Executed(ActionContext context) 17 | { 18 | base.Executed(context); 19 | if (!context.HttpContext.Server.Options.Debug) 20 | { 21 | if (!context.HttpContext.WebSocket) 22 | { 23 | context.HttpContext.Response.Header.Add(HeaderTypeFactory.CACHE_CONTROL, "public, max-age=" + Seconds); 24 | } 25 | } 26 | } 27 | } 28 | 29 | public class ActionCacehFilter : FilterAttribute 30 | { 31 | 32 | public ActionCacehFilter(string key, double seconds = 60) 33 | { 34 | Key = key; 35 | Seconds = seconds; 36 | } 37 | 38 | public string Key { get; set; } 39 | 40 | public double Seconds { get; set; } 41 | 42 | public override bool Executing(ActionContext context) 43 | { 44 | if (context.HttpContext.Server.Options.Debug) 45 | return true; 46 | object result = CacheHelper.Get(Key); 47 | if (result != null) 48 | { 49 | context.Result = result; 50 | return false; 51 | } 52 | return base.Executing(context); 53 | } 54 | 55 | public override void Executed(ActionContext context) 56 | { 57 | base.Executed(context); 58 | CacheHelper.Set(Key, context.Result, Seconds); 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/ESExceptionFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using BeetleX.FastHttpApi; 5 | namespace BeetleX.Blog.Controller 6 | { 7 | public class ESExceptionFilter : FilterAttribute 8 | { 9 | public override bool Executing(ActionContext context) 10 | { 11 | if (ES.ESHelper.Blog == null) 12 | { 13 | context.Result = new ActionResult(500, "检测不到Elastic search服务,请在管理中配置相关服务地址!"); 14 | return false; 15 | } 16 | return base.Executing(context); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/FileManagerController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using BeetleX.FastHttpApi; 5 | 6 | namespace BeetleX.Blog.Controller 7 | { 8 | [Controller(BaseUrl = "/admin/files")] 9 | [AdminFilter] 10 | public class FileManager : BeetleX.FastHttpApi.IController 11 | { 12 | 13 | private string mPath; 14 | 15 | public const string FILE_UPLOAE_MANAGER = "_FILE_UPLOAD_MANAGER"; 16 | /// 17 | /// 创建文件夹 18 | /// 19 | /// 当前目录 20 | /// 新建目录名称 21 | public void CreateFolder(string folder, string name) 22 | { 23 | if (string.IsNullOrEmpty(folder)) 24 | folder = System.IO.Path.DirectorySeparatorChar.ToString(); 25 | string newFolder = mPath + folder + name; 26 | if (!System.IO.Directory.Exists(newFolder)) 27 | System.IO.Directory.CreateDirectory(newFolder); 28 | 29 | } 30 | /// 31 | /// 上传文件信息 32 | /// 33 | /// 当前目录 34 | /// 文件信息 35 | [Post] 36 | public void UploadFile(string folder,UploadInfo info, IHttpContext context) 37 | { 38 | if (string.IsNullOrEmpty(folder)) 39 | folder = System.IO.Path.DirectorySeparatorChar.ToString(); 40 | UploadManager manager = (UploadManager)context.Session[FILE_UPLOAE_MANAGER]; 41 | if (manager == null) 42 | { 43 | manager = new UploadManager(); 44 | context.Session[FILE_UPLOAE_MANAGER] = manager; 45 | } 46 | string filename = mPath + folder + info.Name; 47 | UploadWriter uw = manager.GetWriter(filename); 48 | uw.Write(info); 49 | if (info.Eof) 50 | { 51 | manager.CloseWriter(filename); 52 | } 53 | } 54 | /// 55 | /// 删除资源 56 | /// 57 | /// 当前目录 58 | /// 删除资源名称 59 | /// 是否文件 60 | public void DeleteResource(string folder, string name, bool file) 61 | { 62 | if (string.IsNullOrEmpty(folder)) 63 | folder = System.IO.Path.DirectorySeparatorChar.ToString(); 64 | string recName = mPath + folder + name; 65 | if (file) 66 | { 67 | System.IO.File.Delete(recName); 68 | } 69 | else 70 | { 71 | 72 | System.IO.Directory.Delete(recName, true); 73 | } 74 | } 75 | /// 76 | /// 获取目录资源信息 77 | /// 78 | /// 当前目录 79 | /// 资源列表 80 | public object List(string folder) 81 | { 82 | if (string.IsNullOrEmpty(folder)) 83 | folder = System.IO.Path.DirectorySeparatorChar.ToString(); 84 | List items = new List(); 85 | if (folder != System.IO.Path.DirectorySeparatorChar.ToString()) 86 | { 87 | items.Add(new Resource { Name = System.IO.Path.DirectorySeparatorChar.ToString() }); 88 | } 89 | foreach (string item in System.IO.Directory.GetDirectories(mPath + folder)) 90 | { 91 | Resource rec = new Resource(); 92 | rec.Name = System.IO.Path.GetFileName(item); 93 | rec.Path = folder + rec.Name + System.IO.Path.DirectorySeparatorChar; 94 | rec.Url = "/Files" + rec.Path.Replace(System.IO.Path.DirectorySeparatorChar, '/'); 95 | items.Add(rec); 96 | } 97 | foreach (string file in System.IO.Directory.GetFiles(mPath + folder)) 98 | { 99 | Resource rec = new Resource(); 100 | rec.Name = System.IO.Path.GetFileName(file); 101 | rec.Path = folder + rec.Name; 102 | rec.Url = "/Files" + rec.Path.Replace(System.IO.Path.DirectorySeparatorChar, '/'); 103 | rec.IsFile = true; 104 | items.Add(rec); 105 | } 106 | 107 | return items; 108 | } 109 | 110 | [NotAction] 111 | public void Init(BeetleX.FastHttpApi.HttpApiServer server) 112 | { 113 | mPath = server.Options.StaticResourcePath; 114 | if (mPath[mPath.Length - 1] != System.IO.Path.DirectorySeparatorChar) 115 | mPath += System.IO.Path.DirectorySeparatorChar; 116 | mPath += "Files"; 117 | if (!System.IO.Directory.Exists(mPath)) 118 | System.IO.Directory.CreateDirectory(mPath); 119 | server.HttpDisconnect += (o, e) => 120 | { 121 | UploadManager manager = (UploadManager)e.Session[FILE_UPLOAE_MANAGER]; 122 | if (manager != null) 123 | { 124 | manager.Dispose(); 125 | } 126 | }; 127 | } 128 | 129 | public class Resource 130 | { 131 | 132 | 133 | public string Name { get; set; } 134 | 135 | public bool IsFile { get; set; } 136 | 137 | public string Path { get; set; } 138 | 139 | public string Url { get; set; } 140 | 141 | 142 | } 143 | } 144 | 145 | public class UploadInfo 146 | { 147 | public bool Eof { get; set; } 148 | 149 | public string Data { get; set; } 150 | 151 | public string Name { get; set; } 152 | } 153 | 154 | public class UploadManager : IDisposable 155 | { 156 | private Dictionary mWriters = new Dictionary(); 157 | 158 | public UploadWriter GetWriter(string name) 159 | { 160 | lock (this) 161 | { 162 | UploadWriter writer; 163 | if (!mWriters.TryGetValue(name, out writer)) 164 | { 165 | writer = new UploadWriter(name); 166 | mWriters[name] = writer; 167 | } 168 | return writer; 169 | } 170 | } 171 | 172 | public void CloseWriter(string name) 173 | { 174 | lock (this) 175 | { 176 | UploadWriter writer; 177 | if (mWriters.TryGetValue(name, out writer)) 178 | { 179 | mWriters.Remove(name); 180 | } 181 | } 182 | } 183 | 184 | public void Dispose() 185 | { 186 | lock (this) 187 | { 188 | foreach (UploadWriter item in mWriters.Values) 189 | { 190 | item.Dispose(); 191 | } 192 | mWriters.Clear(); 193 | } 194 | } 195 | } 196 | 197 | public class UploadWriter : IDisposable 198 | { 199 | public UploadWriter(string file) 200 | { 201 | mFileStream = System.IO.File.Create(file); 202 | } 203 | private System.IO.Stream mFileStream; 204 | 205 | public void Write(UploadInfo data) 206 | { 207 | mFileStream.Write(Convert.FromBase64String(data.Data)); 208 | mFileStream.Flush(); 209 | if (data.Eof) 210 | mFileStream.Close(); 211 | } 212 | 213 | public void Dispose() 214 | { 215 | mFileStream.Close(); 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/FileManagerController.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | FastHttpApi javascript api Generator Copyright © henryfan 2018 email:henryfan@msn.com 3 | https://github.com/IKende/FastHttpApi 4 | **************************************************************************************/ 5 | 6 | 7 | 8 | 9 | /** 10 | 创建文件夹 url 11 | **/ 12 | var FileManagerCreateFolderUrl='/admin/files/CreateFolder'; 13 | /** 创建文件夹 'var result=await FileManagerCreateFolder(params)' 14 | /* @param folder 当前目录 15 | /* @param name 新建目录名称 16 | /* @param useHttp only http request 17 | /* @return 18 | **/ 19 | function FileManagerCreateFolder(folder,name,useHttp) 20 | { 21 | return api(FileManagerCreateFolderUrl,{folder:folder,name:name},useHttp).sync(); 22 | } 23 | /** 创建文件夹 'FileManagerCreateFolderAsync(params).execute(function(result){},useHttp)' 24 | /* @param folder 当前目录 25 | /* @param name 新建目录名称 26 | /* @param useHttp only http request 27 | /* @return 28 | **/ 29 | function FileManagerCreateFolderAsync(folder,name,useHttp) 30 | { 31 | return api(FileManagerCreateFolderUrl,{folder:folder,name:name},useHttp); 32 | } 33 | /** 34 | 上传文件信息 url 35 | **/ 36 | var FileManagerUploadFileUrl='/admin/files/UploadFile'; 37 | /** 上传文件信息 'var result=await FileManagerUploadFile(params)' 38 | /* @param folder 当前目录 39 | /* @param info 文件信息 40 | /* @param useHttp only http request 41 | /* @return 42 | **/ 43 | function FileManagerUploadFile(folder,info,useHttp) 44 | { 45 | return api(FileManagerUploadFileUrl,{folder:folder,info:info},useHttp,true).sync(); 46 | } 47 | /** 上传文件信息 'FileManagerUploadFileAsync(params).execute(function(result){},useHttp)' 48 | /* @param folder 当前目录 49 | /* @param info 文件信息 50 | /* @param useHttp only http request 51 | /* @return 52 | **/ 53 | function FileManagerUploadFileAsync(folder,info,useHttp) 54 | { 55 | return api(FileManagerUploadFileUrl,{folder:folder,info:info},useHttp,true); 56 | } 57 | /** 58 | 删除资源 url 59 | **/ 60 | var FileManagerDeleteResourceUrl='/admin/files/DeleteResource'; 61 | /** 删除资源 'var result=await FileManagerDeleteResource(params)' 62 | /* @param folder 当前目录 63 | /* @param name 删除资源名称 64 | /* @param file 是否文件 65 | /* @param useHttp only http request 66 | /* @return 67 | **/ 68 | function FileManagerDeleteResource(folder,name,file,useHttp) 69 | { 70 | return api(FileManagerDeleteResourceUrl,{folder:folder,name:name,file:file},useHttp).sync(); 71 | } 72 | /** 删除资源 'FileManagerDeleteResourceAsync(params).execute(function(result){},useHttp)' 73 | /* @param folder 当前目录 74 | /* @param name 删除资源名称 75 | /* @param file 是否文件 76 | /* @param useHttp only http request 77 | /* @return 78 | **/ 79 | function FileManagerDeleteResourceAsync(folder,name,file,useHttp) 80 | { 81 | return api(FileManagerDeleteResourceUrl,{folder:folder,name:name,file:file},useHttp); 82 | } 83 | /** 84 | 获取目录资源信息 url 85 | **/ 86 | var FileManagerListUrl='/admin/files/List'; 87 | /** 获取目录资源信息 'var result=await FileManagerList(params)' 88 | /* @param folder 当前目录 89 | /* @param useHttp only http request 90 | /* @return 资源列表 91 | **/ 92 | function FileManagerList(folder,useHttp) 93 | { 94 | return api(FileManagerListUrl,{folder:folder},useHttp).sync(); 95 | } 96 | /** 获取目录资源信息 'FileManagerListAsync(params).execute(function(result){},useHttp)' 97 | /* @param folder 当前目录 98 | /* @param useHttp only http request 99 | /* @return 资源列表 100 | **/ 101 | function FileManagerListAsync(folder,useHttp) 102 | { 103 | return api(FileManagerListUrl,{folder:folder},useHttp); 104 | } 105 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/Rewrite.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using BeetleX.FastHttpApi; 5 | namespace BeetleX.Blog.Controller 6 | { 7 | [Controller] 8 | public class Rewrite : IController 9 | { 10 | [NotAction] 11 | public void Init(HttpApiServer server) 12 | { 13 | server.Options.StaticResurceCacheTime = 60 * 5; 14 | server.UrlRewrite.Add("/cate/{0}.html", "/index.html", "html") 15 | .Add("/search/{0}.html", "/index.html", "html") 16 | .Add("/tag/{0}.html", "/index.html", "html") 17 | .Add("/blog/{0}.html", "/blog.html", "html") 18 | .Add("/photos/{0}.html", "/photos.html", "html") 19 | ; 20 | server.ResourceCenter.FileResponse += (request, e) => 21 | { 22 | if (e.Request.Ext == "jpg" || e.Request.Ext == "png") 23 | { 24 | if (!server.Options.Debug) 25 | { 26 | e.Response.Header.Add(HeaderTypeFactory.CACHE_CONTROL, "public, max-age=600000"); 27 | } 28 | } 29 | 30 | }; 31 | 32 | #region init imagepath 33 | Units.ImagePath = server.Options.StaticResourcePath; 34 | if (Units.ImagePath[Units.ImagePath.Length - 1] != System.IO.Path.DirectorySeparatorChar) 35 | Units.ImagePath += System.IO.Path.DirectorySeparatorChar; 36 | Units.ImagePath += "images" + System.IO.Path.DirectorySeparatorChar; 37 | if (!System.IO.Directory.Exists(Units.ImagePath)) 38 | System.IO.Directory.CreateDirectory(Units.ImagePath); 39 | for (int i = 0; i < 10; i++) 40 | { 41 | string subpath = Units.ImagePath + i.ToString("00"); 42 | if (!System.IO.Directory.Exists(subpath)) 43 | System.IO.Directory.CreateDirectory(subpath); 44 | } 45 | #endregion 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/Site.js: -------------------------------------------------------------------------------- 1 | /************************************************************************************ 2 | FastHttpApi javascript api Generator Copyright © henryfan 2018 email:henryfan@msn.com 3 | https://github.com/IKende/FastHttpApi 4 | **************************************************************************************/ 5 | 6 | 7 | 8 | 9 | var SiteGetTitleAndMenuUrl='/GetTitleAndMenu'; 10 | /** 11 | * 'var result= await SiteGetTitleAndMenu(params);' 12 | **/ 13 | function SiteGetTitleAndMenu(useHttp) 14 | { 15 | return api(SiteGetTitleAndMenuUrl,{},useHttp).sync(); 16 | } 17 | /** 18 | * 'SiteGetTitleAndMenuAsync(params).execute(function(result){},useHttp);' 19 | **/ 20 | function SiteGetTitleAndMenuAsync(useHttp) 21 | { 22 | return api(SiteGetTitleAndMenuUrl,{},useHttp); 23 | } 24 | var SiteGetTagsUrl='/GetTags'; 25 | /** 26 | * 'var result= await SiteGetTags(params);' 27 | **/ 28 | function SiteGetTags(top,useHttp) 29 | { 30 | return api(SiteGetTagsUrl,{top:top},useHttp).sync(); 31 | } 32 | /** 33 | * 'SiteGetTagsAsync(params).execute(function(result){},useHttp);' 34 | **/ 35 | function SiteGetTagsAsync(top,useHttp) 36 | { 37 | return api(SiteGetTagsUrl,{top:top},useHttp); 38 | } 39 | var SiteGetAllTagsUrl='/GetAllTags'; 40 | /** 41 | * 'var result= await SiteGetAllTags(params);' 42 | **/ 43 | function SiteGetAllTags(useHttp) 44 | { 45 | return api(SiteGetAllTagsUrl,{},useHttp).sync(); 46 | } 47 | /** 48 | * 'SiteGetAllTagsAsync(params).execute(function(result){},useHttp);' 49 | **/ 50 | function SiteGetAllTagsAsync(useHttp) 51 | { 52 | return api(SiteGetAllTagsUrl,{},useHttp); 53 | } 54 | var SiteTopCommentUrl='/TopComment'; 55 | /** 56 | * 'var result= await SiteTopComment(params);' 57 | **/ 58 | function SiteTopComment(useHttp) 59 | { 60 | return api(SiteTopCommentUrl,{},useHttp).sync(); 61 | } 62 | /** 63 | * 'SiteTopCommentAsync(params).execute(function(result){},useHttp);' 64 | **/ 65 | function SiteTopCommentAsync(useHttp) 66 | { 67 | return api(SiteTopCommentUrl,{},useHttp); 68 | } 69 | var SiteTopBlogUrl='/TopBlog'; 70 | /** 71 | * 'var result= await SiteTopBlog(params);' 72 | **/ 73 | function SiteTopBlog(useHttp) 74 | { 75 | return api(SiteTopBlogUrl,{},useHttp).sync(); 76 | } 77 | /** 78 | * 'SiteTopBlogAsync(params).execute(function(result){},useHttp);' 79 | **/ 80 | function SiteTopBlogAsync(useHttp) 81 | { 82 | return api(SiteTopBlogUrl,{},useHttp); 83 | } 84 | var SiteNewBlogUrl='/NewBlog'; 85 | /** 86 | * 'var result= await SiteNewBlog(params);' 87 | **/ 88 | function SiteNewBlog(useHttp) 89 | { 90 | return api(SiteNewBlogUrl,{},useHttp).sync(); 91 | } 92 | /** 93 | * 'SiteNewBlogAsync(params).execute(function(result){},useHttp);' 94 | **/ 95 | function SiteNewBlogAsync(useHttp) 96 | { 97 | return api(SiteNewBlogUrl,{},useHttp); 98 | } 99 | var SiteGetAboutUrl='/GetAbout'; 100 | /** 101 | * 'var result= await SiteGetAbout(params);' 102 | **/ 103 | function SiteGetAbout(useHttp) 104 | { 105 | return api(SiteGetAboutUrl,{},useHttp).sync(); 106 | } 107 | /** 108 | * 'SiteGetAboutAsync(params).execute(function(result){},useHttp);' 109 | **/ 110 | function SiteGetAboutAsync(useHttp) 111 | { 112 | return api(SiteGetAboutUrl,{},useHttp); 113 | } 114 | var SiteListCommintUrl='/ListCommint'; 115 | /** 116 | * 'var result= await SiteListCommint(params);' 117 | **/ 118 | function SiteListCommint(id,useHttp) 119 | { 120 | return api(SiteListCommintUrl,{id:id},useHttp).sync(); 121 | } 122 | /** 123 | * 'SiteListCommintAsync(params).execute(function(result){},useHttp);' 124 | **/ 125 | function SiteListCommintAsync(id,useHttp) 126 | { 127 | return api(SiteListCommintUrl,{id:id},useHttp); 128 | } 129 | var SiteGetPhotoUrl='/GetPhoto'; 130 | /** 131 | * 'var result= await SiteGetPhoto(params);' 132 | **/ 133 | function SiteGetPhoto(id,useHttp) 134 | { 135 | return api(SiteGetPhotoUrl,{id:id},useHttp).sync(); 136 | } 137 | /** 138 | * 'SiteGetPhotoAsync(params).execute(function(result){},useHttp);' 139 | **/ 140 | function SiteGetPhotoAsync(id,useHttp) 141 | { 142 | return api(SiteGetPhotoUrl,{id:id},useHttp); 143 | } 144 | var SiteListPhotoUrl='/ListPhoto'; 145 | /** 146 | * 'var result= await SiteListPhoto(params);' 147 | **/ 148 | function SiteListPhoto(index,useHttp) 149 | { 150 | return api(SiteListPhotoUrl,{index:index},useHttp).sync(); 151 | } 152 | /** 153 | * 'SiteListPhotoAsync(params).execute(function(result){},useHttp);' 154 | **/ 155 | function SiteListPhotoAsync(index,useHttp) 156 | { 157 | return api(SiteListPhotoUrl,{index:index},useHttp); 158 | } 159 | var SiteCommintUrl='/Commint'; 160 | /** 161 | * 'var result= await SiteCommint(params);' 162 | **/ 163 | function SiteCommint(id,nickName,content,useHttp) 164 | { 165 | return api(SiteCommintUrl,{id:id,nickName:nickName,content:content},useHttp,true).sync(); 166 | } 167 | /** 168 | * 'SiteCommintAsync(params).execute(function(result){},useHttp);' 169 | **/ 170 | function SiteCommintAsync(id,nickName,content,useHttp) 171 | { 172 | return api(SiteCommintUrl,{id:id,nickName:nickName,content:content},useHttp,true); 173 | } 174 | var SiteGetBlogUrl='/GetBlog'; 175 | /** 176 | * 'var result= await SiteGetBlog(params);' 177 | **/ 178 | function SiteGetBlog(id,useHttp) 179 | { 180 | return api(SiteGetBlogUrl,{id:id},useHttp).sync(); 181 | } 182 | /** 183 | * 'SiteGetBlogAsync(params).execute(function(result){},useHttp);' 184 | **/ 185 | function SiteGetBlogAsync(id,useHttp) 186 | { 187 | return api(SiteGetBlogUrl,{id:id},useHttp); 188 | } 189 | var SiteGetServerInfoUrl='/GetServerInfo'; 190 | /** 191 | * 'var result= await SiteGetServerInfo(params);' 192 | **/ 193 | function SiteGetServerInfo(useHttp) 194 | { 195 | return api(SiteGetServerInfoUrl,{},useHttp).sync(); 196 | } 197 | /** 198 | * 'SiteGetServerInfoAsync(params).execute(function(result){},useHttp);' 199 | **/ 200 | function SiteGetServerInfoAsync(useHttp) 201 | { 202 | return api(SiteGetServerInfoUrl,{},useHttp); 203 | } 204 | var SiteSearchUrl='/Search'; 205 | /** 206 | * 'var result= await SiteSearch(params);' 207 | **/ 208 | function SiteSearch(cate,tag,query,index,useHttp) 209 | { 210 | return api(SiteSearchUrl,{cate:cate,tag:tag,query:query,index:index},useHttp).sync(); 211 | } 212 | /** 213 | * 'SiteSearchAsync(params).execute(function(result){},useHttp);' 214 | **/ 215 | function SiteSearchAsync(cate,tag,query,index,useHttp) 216 | { 217 | return api(SiteSearchUrl,{cate:cate,tag:tag,query:query,index:index},useHttp); 218 | } 219 | -------------------------------------------------------------------------------- /BeetleX.Blog/Controller/TokenFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using BeetleX.FastHttpApi; 5 | 6 | namespace BeetleX.Blog.Controller 7 | { 8 | public class TokenFilter : FastHttpApi.FilterAttribute 9 | { 10 | public override bool Executing(ActionContext context) 11 | { 12 | var user = JWTHelper.Default.GetUserInfo(context.HttpContext.Request); 13 | if (user == null) 14 | { 15 | var result = new ActionResult(403, "没权限操作资源"); 16 | result.Data = "/admin/login.html"; 17 | context.Result = result; 18 | return false; 19 | } 20 | else 21 | { 22 | context.HttpContext.Data.SetValue("_userName", user.Name); 23 | context.HttpContext.Data.SetValue("_userRole", user.Role); 24 | } 25 | return true; 26 | } 27 | } 28 | 29 | public class AdminFilter : TokenFilter 30 | { 31 | public override bool Executing(ActionContext context) 32 | { 33 | if (base.Executing(context)) 34 | { 35 | string name = context.HttpContext.Data["_userRole"]; 36 | if (name != "admin") 37 | { 38 | var result = new ActionResult(403, "没权限操作资源"); 39 | result.Data = "/admin/login.html"; 40 | context.Result = result; 41 | return false; 42 | } 43 | else 44 | { 45 | return true; 46 | } 47 | } 48 | return false; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/Blog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut.Mappings; 5 | namespace BeetleX.Blog.DBModules 6 | { 7 | [Table] 8 | public interface IBlog 9 | { 10 | [ID] 11 | [SequenceID] 12 | long ID { get; set; } 13 | [Column] 14 | string Title { get; set; } 15 | [Column] 16 | [BoolConvter] 17 | bool Top { get; set; } 18 | [Column] 19 | string Content { get; set; } 20 | [Column] 21 | string Summary { get; set; } 22 | [Column] 23 | string Category { get; set; } 24 | [Column] 25 | long CategoryID { get; set; } 26 | [Column] 27 | string Tags { get; set; } 28 | [Column] 29 | string SourceUrl { get; set; } 30 | [Column] 31 | [DateTimeConvter] 32 | [NowDate] 33 | DateTime CreateTime { set; get; } 34 | } 35 | 36 | [Table] 37 | public interface IRefreshBlog 38 | { 39 | [Column] 40 | long BlogID { get; set; } 41 | [Column] 42 | [DateTimeConvter] 43 | [NowDate] 44 | DateTime CreateTime { get; set; } 45 | [Column] 46 | int Status { get; set; } 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/BoolConvter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace BeetleX.Blog.DBModules 6 | { 7 | public class BoolConvter : Peanut.Mappings.PropertyCastAttribute 8 | { 9 | public override object ToColumn(object value, Type ptype, object source) 10 | { 11 | if ((bool)value) 12 | { 13 | return 1; 14 | } 15 | else 16 | return 0; 17 | } 18 | public override object ToProperty(object value, Type ptype, object source) 19 | { 20 | return value != null && (long)value > 0; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/Category.Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut.Mappings; 5 | 6 | namespace BeetleX.Blog.DBModules 7 | { 8 | /// 9 | ///Peanut Generator Copyright @ henryfan 2018 email:henryfan@msn.com 10 | ///website:http://www.ikende.com 11 | /// 12 | [Table()] 13 | public partial class Category : Peanut.Mappings.DataObject 14 | { 15 | private long mID; 16 | public static Peanut.FieldInfo iD = new Peanut.FieldInfo("Category", "ID"); 17 | private string mName; 18 | public static Peanut.FieldInfo name = new Peanut.FieldInfo("Category", "Name"); 19 | private string mRemark; 20 | public static Peanut.FieldInfo remark = new Peanut.FieldInfo("Category", "Remark"); 21 | private int mOrderBy; 22 | public static Peanut.FieldInfo orderBy = new Peanut.FieldInfo("Category", "OrderBy"); 23 | /// 24 | ///Type:long 25 | /// 26 | [ID()] 27 | [SequenceID] 28 | public virtual long ID 29 | { 30 | get 31 | { 32 | return mID; 33 | 34 | } 35 | set 36 | { 37 | mID = value; 38 | EntityState.FieldChange("ID"); 39 | 40 | } 41 | 42 | } 43 | /// 44 | ///Type:string 45 | /// 46 | [Column()] 47 | public virtual string Name 48 | { 49 | get 50 | { 51 | return mName; 52 | 53 | } 54 | set 55 | { 56 | mName = value; 57 | EntityState.FieldChange("Name"); 58 | 59 | } 60 | 61 | } 62 | /// 63 | ///Type:string 64 | /// 65 | [Column()] 66 | public virtual string Remark 67 | { 68 | get 69 | { 70 | return mRemark; 71 | 72 | } 73 | set 74 | { 75 | mRemark = value; 76 | EntityState.FieldChange("Remark"); 77 | 78 | } 79 | 80 | } 81 | /// 82 | ///Type:int 83 | /// 84 | [Column()] 85 | public virtual int OrderBy 86 | { 87 | get 88 | { 89 | return mOrderBy; 90 | 91 | } 92 | set 93 | { 94 | mOrderBy = value; 95 | EntityState.FieldChange("OrderBy"); 96 | 97 | } 98 | 99 | } 100 | 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/Category.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut.Mappings; 5 | namespace BeetleX.Blog.DBModules 6 | { 7 | [Table] 8 | public interface ICategory 9 | { 10 | [ID] 11 | [SequenceID] 12 | long ID { get; set; } 13 | [Column] 14 | string Name { get; set; } 15 | [Column] 16 | string Remark { get; set; } 17 | [Column] 18 | int OrderBy { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/Comment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut.Mappings; 5 | namespace BeetleX.Blog.DBModules 6 | { 7 | [Table] 8 | public interface IComment 9 | { 10 | [ID] 11 | [SequenceID] 12 | long ID { get; set; } 13 | [Column] 14 | string NickName { get; set; } 15 | [Column] 16 | string HeadUrl { get; set; } 17 | [Column] 18 | long BlogID { get; set; } 19 | [Column] 20 | string Content { get; set; } 21 | [Column] 22 | [NowDate] 23 | [DateTimeConvter] 24 | DateTime CreateTime { get; set; } 25 | [Column] 26 | string UserID { get; set; } 27 | } 28 | [Table("Comment inner join Blog on Comment.BlogID=Blog.ID")] 29 | public interface ITopComment 30 | { 31 | [Column("Blog.ID")] 32 | long ID { get; set; } 33 | [Column("Comment.ID")] 34 | long CommentID { get; set; } 35 | [Column] 36 | string Title { get; set; } 37 | [Column("Comment.Content")] 38 | string Content { get; set; } 39 | [Column] 40 | string NickName { get; set; } 41 | [Column("Comment.CreateTime")] 42 | [DateTimeConvter] 43 | DateTime CreateTime { get; set; } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/DBHelper.cs: -------------------------------------------------------------------------------- 1 | using Peanut; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace BeetleX.Blog.DBModules 7 | { 8 | public class DBHelper 9 | { 10 | private static DBHelper mDefault; 11 | 12 | public long GetSequence(string key) 13 | { 14 | lock (this) 15 | { 16 | Sequence sequence = (Sequence.key == key).ListFirst(); 17 | if (sequence == null) 18 | { 19 | sequence = new Sequence(); 20 | sequence.Key = key; 21 | sequence.Value = 10000; 22 | } 23 | sequence.Value++; 24 | long result = sequence.Value; 25 | sequence.Save(); 26 | return result; 27 | } 28 | } 29 | 30 | public static DBHelper Default 31 | { 32 | get 33 | { 34 | 35 | if (mDefault == null) 36 | { 37 | lock (typeof(DBHelper)) 38 | { 39 | if (mDefault == null) 40 | { 41 | DBContext.SetConnectionDriver(DB.DB1); 42 | DBContext.SetConnectionString(DB.DB1, "Data Source=beetlex_blog.db;Pooling=true;FailIfMissing=false;"); 43 | mDefault = new DBHelper(); 44 | mDefault.Setting = new Setting(); 45 | mDefault.Setting.Init(); 46 | mDefault.Setting.Load(); 47 | } 48 | 49 | } 50 | } 51 | return mDefault; 52 | } 53 | } 54 | 55 | 56 | public Setting Setting { get; private set; } 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/DateTimeConvter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace BeetleX.Blog.DBModules 6 | { 7 | public class DateTimeConvter : Peanut.Mappings.PropertyCastAttribute 8 | { 9 | public override object ToColumn(object value, Type ptype, object source) 10 | { 11 | return ((DateTime)value).Ticks; 12 | } 13 | public override object ToProperty(object value, Type ptype, object source) 14 | { 15 | return new DateTime((long)value); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/IPhoto.Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut.Mappings; 5 | 6 | namespace BeetleX.Blog.DBModules 7 | { 8 | /// 9 | ///Peanut Generator Copyright @ henryfan 2018 email:henryfan@msn.com 10 | ///website:http://www.ikende.com 11 | /// 12 | [Table()] 13 | public partial class Photo : Peanut.Mappings.DataObject 14 | { 15 | private long mID; 16 | public static Peanut.FieldInfo iD = new Peanut.FieldInfo("Photo", "ID"); 17 | private string mTitle; 18 | public static Peanut.FieldInfo title = new Peanut.FieldInfo("Photo", "Title"); 19 | private DateTime mCreateTime; 20 | public static Peanut.FieldInfo createTime = new Peanut.FieldInfo("Photo", "CreateTime"); 21 | private string mSmallUrl; 22 | public static Peanut.FieldInfo smallUrl = new Peanut.FieldInfo("Photo", "SmallUrl"); 23 | private string mLargeUrl; 24 | public static Peanut.FieldInfo largeUrl = new Peanut.FieldInfo("Photo", "LargeUrl"); 25 | /// 26 | ///Type:long 27 | /// 28 | [ID()] 29 | [SequenceID] 30 | public virtual long ID 31 | { 32 | get 33 | { 34 | return mID; 35 | 36 | } 37 | set 38 | { 39 | mID = value; 40 | EntityState.FieldChange("ID"); 41 | 42 | } 43 | 44 | } 45 | /// 46 | ///Type:string 47 | /// 48 | [Column()] 49 | public virtual string Title 50 | { 51 | get 52 | { 53 | return mTitle; 54 | 55 | } 56 | set 57 | { 58 | mTitle = value; 59 | EntityState.FieldChange("Title"); 60 | 61 | } 62 | 63 | } 64 | /// 65 | ///Type:DateTime 66 | /// 67 | [Column()] 68 | [DateTimeConvter] 69 | [NowDate] 70 | public virtual DateTime CreateTime 71 | { 72 | get 73 | { 74 | return mCreateTime; 75 | 76 | } 77 | set 78 | { 79 | mCreateTime = value; 80 | EntityState.FieldChange("CreateTime"); 81 | 82 | } 83 | 84 | } 85 | /// 86 | ///Type:string 87 | /// 88 | [Column()] 89 | public virtual string SmallUrl 90 | { 91 | get 92 | { 93 | return mSmallUrl; 94 | 95 | } 96 | set 97 | { 98 | mSmallUrl = value; 99 | EntityState.FieldChange("SmallUrl"); 100 | 101 | } 102 | 103 | } 104 | /// 105 | ///Type:string 106 | /// 107 | [Column()] 108 | public virtual string LargeUrl 109 | { 110 | get 111 | { 112 | return mLargeUrl; 113 | 114 | } 115 | set 116 | { 117 | mLargeUrl = value; 118 | EntityState.FieldChange("LargeUrl"); 119 | 120 | } 121 | 122 | } 123 | 124 | } 125 | /// 126 | ///Peanut Generator Copyright @ henryfan 2018 email:henryfan@msn.com 127 | ///website:http://www.ikende.com 128 | /// 129 | [Table()] 130 | public partial class PhotoItem : Peanut.Mappings.DataObject 131 | { 132 | private string mID; 133 | public static Peanut.FieldInfo iD = new Peanut.FieldInfo("PhotoItem", "ID"); 134 | private long mPhotoID; 135 | public static Peanut.FieldInfo photoID = new Peanut.FieldInfo("PhotoItem", "PhotoID"); 136 | private string mLargeUrl; 137 | public static Peanut.FieldInfo largeUrl = new Peanut.FieldInfo("PhotoItem", "LargeUrl"); 138 | private string mSmallUrl; 139 | public static Peanut.FieldInfo smallUrl = new Peanut.FieldInfo("PhotoItem", "SmallUrl"); 140 | /// 141 | ///Type:string 142 | /// 143 | [ID()] 144 | public virtual string ID 145 | { 146 | get 147 | { 148 | return mID; 149 | 150 | } 151 | set 152 | { 153 | mID = value; 154 | EntityState.FieldChange("ID"); 155 | 156 | } 157 | 158 | } 159 | /// 160 | ///Type:long 161 | /// 162 | [Column()] 163 | public virtual long PhotoID 164 | { 165 | get 166 | { 167 | return mPhotoID; 168 | 169 | } 170 | set 171 | { 172 | mPhotoID = value; 173 | EntityState.FieldChange("PhotoID"); 174 | 175 | } 176 | 177 | } 178 | /// 179 | ///Type:string 180 | /// 181 | [Column()] 182 | public virtual string LargeUrl 183 | { 184 | get 185 | { 186 | return mLargeUrl; 187 | 188 | } 189 | set 190 | { 191 | mLargeUrl = value; 192 | EntityState.FieldChange("LargeUrl"); 193 | 194 | } 195 | 196 | } 197 | /// 198 | ///Type:string 199 | /// 200 | [Column()] 201 | public virtual string SmallUrl 202 | { 203 | get 204 | { 205 | return mSmallUrl; 206 | 207 | } 208 | set 209 | { 210 | mSmallUrl = value; 211 | EntityState.FieldChange("SmallUrl"); 212 | 213 | } 214 | 215 | } 216 | 217 | } 218 | 219 | } 220 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/IPhoto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut.Mappings; 5 | namespace BeetleX.Blog.DBModules 6 | { 7 | [Table] 8 | public interface IPhoto 9 | { 10 | [ID] 11 | [SequenceID] 12 | long ID { get; set; } 13 | [Column] 14 | string Title { get; set; } 15 | [Column] 16 | [DateTimeConvter] 17 | [NowDate] 18 | DateTime CreateTime { get; set; } 19 | [Column] 20 | string SmallUrl { get; set; } 21 | [Column] 22 | string LargeUrl { get; set; } 23 | } 24 | [Table] 25 | public interface IPhotoItem 26 | { 27 | [ID] 28 | string ID { get; set; } 29 | [Column] 30 | long PhotoID { get; set; } 31 | [Column] 32 | string LargeUrl { get; set; } 33 | [Column] 34 | string SmallUrl { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/ISequence.Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut; 5 | using Peanut.Mappings; 6 | 7 | namespace BeetleX.Blog.DBModules 8 | { 9 | /// 10 | ///Peanut Generator Copyright @ henryfan 2018 email:henryfan@msn.com 11 | ///website:http://www.ikende.com 12 | /// 13 | [Table()] 14 | public partial class Sequence : Peanut.Mappings.DataObject 15 | { 16 | private string mKey; 17 | public static Peanut.FieldInfo key = new Peanut.FieldInfo("Sequence", "Key"); 18 | private long mValue; 19 | public static Peanut.FieldInfo value = new Peanut.FieldInfo("Sequence", "Value"); 20 | /// 21 | ///Type:string 22 | /// 23 | [ID()] 24 | public virtual string Key 25 | { 26 | get 27 | { 28 | return mKey; 29 | 30 | } 31 | set 32 | { 33 | mKey = value; 34 | EntityState.FieldChange("Key"); 35 | 36 | } 37 | 38 | } 39 | /// 40 | ///Type:long 41 | /// 42 | [Column()] 43 | public virtual long Value 44 | { 45 | get 46 | { 47 | return mValue; 48 | 49 | } 50 | set 51 | { 52 | mValue = value; 53 | EntityState.FieldChange("Value"); 54 | 55 | } 56 | 57 | } 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/ISequence.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut; 5 | using Peanut.Mappings; 6 | namespace BeetleX.Blog.DBModules 7 | { 8 | [Table] 9 | public interface ISequence 10 | { 11 | [ID] 12 | string Key { get; set; } 13 | [Column] 14 | long Value { get; set; } 15 | } 16 | 17 | public class SequenceID : Peanut.Mappings.ValueAttribute 18 | { 19 | public SequenceID() : base(false) 20 | { 21 | 22 | } 23 | public override void Executing(IConnectinContext cc, object data, PropertyMapper pm, string table) 24 | { 25 | long id = DBHelper.Default.GetSequence(table); 26 | pm.Handler.Set(data, id); 27 | base.Executing(cc, data, pm, table); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/ISetting.Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut.Mappings; 5 | 6 | namespace BeetleX.Blog.DBModules 7 | { 8 | /// 9 | ///Peanut Generator Copyright @ henryfan 2018 email:henryfan@msn.com 10 | ///website:http://www.ikende.com 11 | /// 12 | [Table()] 13 | public partial class Option : Peanut.Mappings.DataObject 14 | { 15 | private string mName; 16 | public static Peanut.FieldInfo name = new Peanut.FieldInfo("Option", "Name"); 17 | private string mValue; 18 | public static Peanut.FieldInfo value = new Peanut.FieldInfo("Option", "Value"); 19 | /// 20 | ///Type:string 21 | /// 22 | [ID()] 23 | public virtual string Name 24 | { 25 | get 26 | { 27 | return mName; 28 | 29 | } 30 | set 31 | { 32 | mName = value; 33 | EntityState.FieldChange("Name"); 34 | 35 | } 36 | 37 | } 38 | /// 39 | ///Type:string 40 | /// 41 | [Column()] 42 | public virtual string Value 43 | { 44 | get 45 | { 46 | return mValue; 47 | 48 | } 49 | set 50 | { 51 | mValue = value; 52 | EntityState.FieldChange("Value"); 53 | 54 | } 55 | 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /BeetleX.Blog/DBModules/ISetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Peanut.Mappings; 5 | namespace BeetleX.Blog.DBModules 6 | { 7 | [Table] 8 | public interface IOption 9 | { 10 | [ID] 11 | string Name { get; set; } 12 | [Column] 13 | string Value { get; set; } 14 | } 15 | 16 | public class Setting 17 | { 18 | public const string USERNAME = "USERNAME"; 19 | 20 | public const string PASSWORD = "PASSWORD"; 21 | 22 | public const string BLOG_TITLE = "BLOG_TITLE"; 23 | 24 | public const string ES_HOST = "ES_HOST"; 25 | 26 | public const string ABOUT = "ABOUT"; 27 | 28 | public const string IMG_HOST = "IMG_HOST"; 29 | 30 | public const string JWTKEY = "JWT_KEY"; 31 | 32 | public const string TCLOUD_ID = "TCLOUD_ID"; 33 | 34 | public const string TCLOUD_KEY = "TCLOUD_KEY"; 35 | 36 | public const string TCLOUD_HOST = "TCLOUD_HOST"; 37 | 38 | public Option PassWord { get; private set; } 39 | 40 | public Option Title { get; private set; } 41 | 42 | public Option UserName { get; private set; } 43 | 44 | public Option About { get; private set; } 45 | 46 | public Option ElasticSearch { get; private set; } 47 | 48 | public Option TCloudID { get; private set; } 49 | 50 | public Option TCloudKey { get; private set; } 51 | 52 | public Option TCloudHost { get; private set; } 53 | 54 | public Option JwtKey { get; private set; } 55 | 56 | public Option ImgHost { get; private set; } 57 | 58 | public void Init() 59 | { 60 | Option option; 61 | 62 | if ((Option.name == IMG_HOST).Count