diff --git a/DISCLAIMER_CN.md b/DISCLAIMER_CN.md new file mode 100644 index 000000000..3721cf685 --- /dev/null +++ b/DISCLAIMER_CN.md @@ -0,0 +1,14 @@ + +# 免责申明(仅限中国用户) + +此项目及其配套组件均为免费开源的产品,仅用于学习交流,并且不直接向中国提供服务,中国用户请于下载后立即删除。 + +任何中国境内的组织及个人不得使用此项目及其配套组件构建任何形式的面向中国境内用户的网站或服务。 + +不可用于任何违反中华人民共和国(含台湾省)或使用者所在地区法律法规的用途。 + +因为作者即本人仅完成代码的开发和开源活动(开源即任何人都可以下载使用),从未参与用户的任何运营和盈利活动。 + +且不知晓用户后续将程序源代码用于何种用途,故用户使用过程中所带来的任何法律责任即由用户自己承担。 + +[《开源软件有漏洞,作者需要负责吗?是的!》](https://go.edi.wang/aka/os251) diff --git a/Deployment/install.sh b/Deployment/install.sh deleted file mode 100644 index 1750b6851..000000000 --- a/Deployment/install.sh +++ /dev/null @@ -1,140 +0,0 @@ -aiur() { arg="$( cut -d ' ' -f 2- <<< "$@" )" && curl -sL https://github.com/AiursoftWeb/AiurScript/raw/master/$1.sh | sudo bash -s $arg; } - -install_Moonglade() -{ - - aiur console/success "Updating..." - apt-get update --allow-releaseinfo-change - apt upgrade -y - server="$1" - db_type="$2" - - aiur console/success "Checking..." - # Valid domain is required - if [[ $(curl -sL ifconfig.me) == "$(dig +short $server)" ]]; - then - echo "IP is correct." - else - echo "$server is not your current machine IP!" - return 9 - fi - - # Valid database type mssql(default) and mysql 8.0 - if [ "$db_type" != "mssql" ] && [ "$db_type" != "mysql" ]; - then - echo "$db_type is not supported database in this script! try mssql or mysql." - return 9 - fi - - port=$(aiur network/get_port) - dbPassword=$(uuidgen) - - cd ~ - - # Enable BBR - aiur network/enable_bbr - - # Install basic packages - aiur console/success "Installing..." - - apt install -y git vim ufw - aiur install/jq - aiur install/dotnet - aiur install/caddy - if [ "$db_type" == "mssql" ]; - then - aiur install/sql_server $dbPassword - else - apt install mysql-server -y - fi - #aiur install/node - - aiur console/success "Cloning..." - ls | grep -q Moonglade && rm ./Moonglade -rf - mkdir Storage - chmod -R 777 ~/Storage/ - git clone -b release https://github.com/EdiWang/Moonglade.git - - # Build the code - aiur console/success 'Building...' - moonglade_path="$(pwd)/apps/moongladeApp" - #rm ./Moonglade/src/Moonglade.Web/libman.json # Remove libman because it is easy to crash. - dotnet publish -c Release -o $moonglade_path -r linux-x64 --no-self-contained ./Moonglade/src/Moonglade.Web/Moonglade.Web.csproj - cp ~/Moonglade/build/OpenSans-Regular.ttf /usr/share/fonts/OpenSans-Regular.ttf - rm ~/Moonglade -rf - cat $moonglade_path/appsettings.json > $moonglade_path/appsettings.Production.json - - # Configure appsettings.json - aiur console/success 'Configuring...' - - # Configure different database type - if [ "$db_type" == "mssql" ]; - then - connectionString="Server=tcp:127.0.0.1,1433;Database=Moonglade;uid=sa;Password=$dbPassword;MultipleActiveResultSets=True;" - db_name="SqlServer" - else - connectionString="Server=localhost;Port=3306;Database=Moonglade;uid=root;Password=$dbPassword;" - db_name="MySql" - fi - aiur text/edit_json "ConnectionStrings.DatabaseType" $db_name $moonglade_path/appsettings.Production.json - aiur text/edit_json "ConnectionStrings.MoongladeDatabase" "$connectionString" $moonglade_path/appsettings.Production.json - aiur text/edit_json "ImageStorage.FileSystemPath" '\/root\/Storage' $moonglade_path/appsettings.Production.json - aiur text/edit_json "ImageStorage.FileSystemSettings.Path" '\/root\/Storage' $moonglade_path/appsettings.Production.json - - #npm install web-push -g - - # Create database. - if [ "$db_type" == "mssql" ]; - then - aiur console/success 'Seeding...' - aiur mssql/create_db "Moonglade" $dbPassword - else - # Initiate mysql root password and create database Moonglade - mysql -uroot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password by '$dbPassword'" - mysql -uroot -e "create database Moonglade" -p"$dbPassword" - fi - - # Register Moonglade service - aiur console/success "Registering..." - aiur services/register_aspnet_service "moonglade" $port $moonglade_path "Moonglade.Web" - sleep 2 - - # Config caddy - aiur console/success 'Proxying...' - aiur caddy/add_proxy $server $port - sleep 2 - - # Config firewall - aiur console/success 'Porting...' - aiur firewall/open_port 443 - aiur firewall/open_port 80 - aiur firewall/enable_firewall - sleep 2 - - aiur console/success 'Finlization...' - # Finish the installation - if [ "$db_type" == "mssql" ]; - then - db_port="1433" - db_user="sa" - db_data_dir="/var/opt/mssql/" - else - db_port="3306" - db_user="root" - db_data_dir="/var/lib/mysql/" - fi - echo "Successfully installed Moonglade as a service in your machine! Please open https://$server to try it now!" - echo "Default management user name is "admin" and default password is "admin123". Please open https://$server/admin to try it now!" - echo "Successfully installed $db_type as a service in your machine! The port is not opened so you can't connect!" - echo "Successfully installed caddy as a service in your machine!" - sleep 1 - echo "You can open your database to public via: sudo ufw allow $db_port/tcp" - echo "You can access your database via: $server:$db_port with username: $db_user and password: $dbPassword" - echo "Your database data file is located at: $db_data_dir. Please back up them regularly." - echo "Your web data file is located at: $moonglade_path" - echo "Your web server config file is located at: /etc/caddy/Caddyfile" - echo "Strongly maintain your own configuration at $moonglade_path/appsettings.Production.json" - echo "Strongly suggest run 'sudo apt upgrade' and reboot when convience!" -} - -install_Moonglade "$@" diff --git a/Deployment/mssql-migration.sql b/Deployment/mssql-migration.sql new file mode 100644 index 000000000..e35ee1e7a --- /dev/null +++ b/Deployment/mssql-migration.sql @@ -0,0 +1,10 @@ +-- v14.1.0 + +ALTER TABLE FriendLink ADD [Rank] INT +GO + +UPDATE FriendLink SET [Rank] = 0 +GO + +ALTER TABLE FriendLink ALTER COLUMN [Rank] INT NOT NULL +GO \ No newline at end of file diff --git a/Deployment/uninstall.sh b/Deployment/uninstall.sh deleted file mode 100644 index ec4eb6f4a..000000000 --- a/Deployment/uninstall.sh +++ /dev/null @@ -1,29 +0,0 @@ - -delete_service() -{ - service="$1" - systemctl stop $service - systemctl disable $service - rm /etc/systemd/system/$service - rm /etc/systemd/system/$service # and symlinks that might be related - rm /usr/lib/systemd/system/$service - rm /usr/lib/systemd/system/$service # and symlinks that might be related - systemctl daemon-reload - systemctl reset-failed -} - -delete_service "mssql-server.service" -delete_service "caddy.service" -delete_service "moonglade.service" -delete_service "mysql.service" - -rm ~/apps/moongladeApp -rvf -rm ~/Moonglade -rvf -rm /etc/caddy -rvf -rm /var/opt/mssql/ -rvf - -apt remove caddy -y -apt remove mssql-server -y -apt remove mysql-server -y - -echo "Successfully uninstalled Kahla on your machine!" \ No newline at end of file diff --git a/README.md b/README.md index f38448421..5be90f883 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,17 @@ # Moonglade Blog [![Docker Linux x64](https://github.com/EdiWang/Moonglade/actions/workflows/docker.yml/badge.svg)](https://github.com/EdiWang/Moonglade/actions/workflows/docker.yml) +![Man hours](https://manhours.aiursoft.cn/r/github.com/ediwang/moonglade.svg) -The [.NET](https://dotnet.microsoft.com/) blog system that optimized for [**Microsoft Azure**](https://azure.microsoft.com/en-us/). Designed for developers, enabling most common blogging features including posts, comments, categories, archive, tags and pages. - -**IMPORTANT: Moonglade will move to .NET 8 LTS in November 2023 with v14.x release** +A personal blog system that optimized for [**Microsoft Azure**](https://azure.microsoft.com/en-us/). Designed for developers, enabling most common blogging features including posts, comments, categories, archive, tags and pages. ## 📦 Deployment -- Please use stable code from [Release](https://github.com/EdiWang/Moonglade/releases) branch rather than master branch. +- Ue stable code from [Release](https://github.com/EdiWang/Moonglade/releases) branch rather than master branch. - HTTPS is required, and it is recommended to enable HTTP/2 support on your web server. -### ☁ Full Deploy on Azure +### Full Deploy on Azure This is the way https://edi.wang is deployed, by taking advantage of as many Azure services as possible, the blog can run very fast and secure. @@ -20,11 +19,11 @@ There is no automated script to deploy it, you need to manually create all the r ![image](https://cdn-blog.edi.wang/web-assets/ediwang-azure-arch-visio-nov2022.png) -### 🐋 Quick Deploy on Azure (App Service on Linux) +### Quick Deploy on Azure (App Service on Linux) Use automated deployment script to get your Moonglade up and running in 10 minutes with minimal Azure components, follow instructions [here](https://github.com/EdiWang/Moonglade/wiki/Quick-Deploy-on-Azure) -### 🐋 Quick Deploy with Docker-Compose +### Quick Deploy with Docker-Compose Simply go the the root folder of this repo and run: @@ -35,50 +34,25 @@ docker-compose up That's it! Now open: [Browser: http://localhost:8080](http://localhost:8080) -### 🐧 Quick Deploy on Linux without Docker - -To quickly get it running on a new Linux machine without Docker, follow instructions [here](https://github.com/EdiWang/Moonglade/wiki/Quick-Install-on-Linux-Machine). You can watch video tutorial [here](https://anduins-site.player.aiur.site/moonglade-install.mp4). - ## 🐵 Development Tools | Alternative --- | --- -[Visual Studio 2022 v17.8+](https://visualstudio.microsoft.com/) | [Visual Studio Code](https://code.visualstudio.com/) with [.NET 8.0 SDK](http://dot.net) +[Visual Studio 2022](https://visualstudio.microsoft.com/) | [Visual Studio Code](https://code.visualstudio.com/) with [.NET 8.0 SDK](http://dot.net) [SQL Server 2022](https://www.microsoft.com/en-us/sql-server/sql-server-2022) | [SQL Server LocalDB](https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/sql-server-express-localdb?view=sql-server-ver16&WT.mc_id=AZ-MVP-5002809), PostgreSQL or MySQL -### 💾 Setup Database - -Moonglade supports three types of database. You can choose from SQL Server, PostgreSQL or MySQL. - -Update your database connection string in `appsettings.*.json` - -#### SQL Server - -```json -"ConnectionStrings": { - "MoongladeDatabase": "Server=(localdb)\\MSSQLLocalDB;Database=Moonglade;Trusted_Connection=True;", - "DatabaseType": "SqlServer" -} -``` -#### MySQL +### Setup Database -```json -"ConnectionStrings": { - "MoongladeDatabase": "Server=localhost;Port=3306;Database=moonglade;Uid=root;Pwd=******;", - "DatabaseType": "MySql" -} -``` +You can choose from SQL Server, PostgreSQL or MySQL. Update your database connection string in `appsettings.json`, `ConnectionStrings` section. -#### PostgreSql -```json -"ConnectionStrings": { - "MoongladeDatabase": "User ID=****;Password=****;Host=localhost;Port=5432;Database=****;Pooling=true;", - "DatabaseType": "PostgreSql" -} -``` +Database | `DatabaseType` | `MoongladeDatabase` Example +--- | --- | --- +Microsoft SQL Server | `SqlServer` | `Server=(localdb)\\MSSQLLocalDB;Database=moonglade;Trusted_Connection=True;` +MySQL | `MySql` | `Server=localhost;Port=3306;Database=moonglade;Uid=root;Pwd=***;` +PostgreSQL | `PostgreSql` | `User ID=***;Password=***;Host=localhost;Port=5432;Database=moonglade;Pooling=true;` -### 🔨 Build Source +### Build Source Build and run `./src/Moonglade.sln` - Admin: `https://localhost:1055/admin` @@ -87,9 +61,9 @@ Build and run `./src/Moonglade.sln` ## ⚙ Configuration -> This section discuss environment settings in **appsettings.[env].json**. For blog settings, please use "/admin/settings" UI. +> This section discuss environment settings in **appsettings.json**. For blog settings, please use "/admin/settings" UI. -### 🛡 Authentication +### Authentication > You can choose one authentication provider from below. @@ -101,7 +75,7 @@ See [Wiki document](https://github.com/EdiWang/Moonglade/wiki/Use-Microsoft-Entr Set `Authentication:Provider` to `"Local"`. You can manage accounts in `/admin/settings/account` -### 🖼 Image Storage +### Image Storage `ImageStorage` controls how blog post images are stored. #### [Azure Blob Storage](https://azure.microsoft.com/en-us/services/storage/blobs/) (Preferred) @@ -146,69 +120,39 @@ You can also choose File System for image storage if you don't have a cloud opti } ``` -### 🤬 Comment Moderator +### Comment Moderator See https://github.com/EdiWang/Moonglade.ContentSecurity -### 📧 Email Notification +### Email Notification If you need email notification for new comments, new replies and pingbacks, you have to setup the [Moonglade.Email Azure Function](https://github.com/EdiWang/Moonglade.Email) first, and then enable notification in admin portal. -### 🔩 Others +### Others - [System Settings](https://github.com/EdiWang/Moonglade/wiki/System-Settings) - [Security Headers (CSP, XSS, etc.)](https://github.com/EdiWang/Moonglade/wiki/Security-Headers-(CSP,-XSS,-etc.)) ## 🎉 Blog Protocols or Standards -- [X] RSS -- [X] Atom -- [X] OPML -- [X] Open Search -- [X] Pingback -- [X] Reader View -- [X] FOAF -- [X] RSD -- [X] MetaWeblog (Basic Support) -- [X] Dublin Core Metadata (Basic Support) -- [ ] BlogML - Not planned -- [ ] APML - Not planned -- [ ] Trackback - Not planned - -## ⚖️ Disclaimer (Global) - -The following disclaimer applies to the software named "Moonglade" developed by Edi Wang and other [contributors](https://github.com/EdiWang/Moonglade/graphs/contributors) (hereinafter referred to as "the software developer"): - -This project is not affiliated with Microsoft Corporation. All product names, logos, and brands are property of their respective owners. All company, product and service names used in this website are for identification purposes only. Use of these names, logos, and brands does not imply endorsement. - -The software developer does not provide any warranties or guarantees regarding the functionality, performance, or suitability of Moonglade for any specific purpose. The software is provided "as is," and the software developer shall not be held liable for any direct or indirect damages arising from the use or inability to use Moonglade. - -### Data Privacy - -Moonglade does not send any user data or information to any government, **including the Chinese government**. The software is designed to prioritize and respect user privacy. - -### Data Collection - -While using Moonglade, please note that the platform on which you deploy the software may collect data and usage information. This data collection is solely the responsibility of the platform and not the software developer. We encourage you to review thier privacy policy and terms of service of the platform to understand how your data is handled. - -### User Responsibility - -As a user of Moonglade, it is your responsibility to ensure compliance with applicable laws and regulations regarding data privacy and usage. The software developer shall not be held liable for any misuse, unauthorized access, or mishandling of data by the user or the platform on which Moonglade is deployed. - -### Updates and Modifications - -The software developer may release updates or modifications to Moonglade from time to time. It is recommended that users stay informed about these updates and apply them to ensure optimal performance and security. +Name | Feature | Status +--- | --- | --- +RSS | Subscription | Supported +Atom | Subscription | Supported +OPML | Subscription | Supported +Open Search | Search | Supported +Pingback | Social | Supported +Reader View | Reader mode | Supported +FOAF | Social | Supported +RSD | Service Discovery | Supported +MetaWeblog | Blogging | Basic Support +Dublin Core Metadata | SEO | Basic Support +BlogML | Blogging | Not planned +APML | Social | Not planned +Trackback | Social | Not planned ## 免责申明 -此项目(Moonglade)及其配套组件均为免费开源的产品,仅用于学习交流,并且不直接向中国提供服务,中国用户请于下载后立即删除。 - -任何中国境内的组织及个人不得使用此项目(Moonglade)及其配套组件构建任何形式的面向中国境内用户的网站或服务。 - -不可用于任何违反中华人民共和国(含台湾省)或使用者所在地区法律法规的用途。 - -因为作者即本人仅完成代码的开发和开源活动(开源即任何人都可以下载使用),从未参与用户的任何运营和盈利活动。 - -且不知晓用户后续将程序源代码用于何种用途,故用户使用过程中所带来的任何法律责任即由用户自己承担。 +对于中国用户,我们有一份特定的免责申明。请确保你已经阅读并理解其内容: -[《开源软件有漏洞,作者需要负责吗?是的!》](https://go.edi.wang/aka/os251) \ No newline at end of file +- [免责申明(仅限中国用户)](./DISCLAIMER_CN.md) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index f66061eeb..7f8e6f940 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -3,8 +3,8 @@ Edi Wang edi.wang (C) 2023 edi.wang@outlook.com - 14.0.1.0 - 14.0.1.0 - 14.0.1 + 14.1.0.0 + 14.1.0.0 + 14.1.0 \ No newline at end of file diff --git a/src/Moonglade.Auth/Moonglade.Auth.csproj b/src/Moonglade.Auth/Moonglade.Auth.csproj index abdd949f5..9c7db4b0a 100644 --- a/src/Moonglade.Auth/Moonglade.Auth.csproj +++ b/src/Moonglade.Auth/Moonglade.Auth.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/Moonglade.Comments/Moonglade.Comments.csproj b/src/Moonglade.Comments/Moonglade.Comments.csproj index a2f701a6f..37822f927 100644 --- a/src/Moonglade.Comments/Moonglade.Comments.csproj +++ b/src/Moonglade.Comments/Moonglade.Comments.csproj @@ -9,7 +9,7 @@ enable - + diff --git a/src/Moonglade.Configuration/AdvancedSettings.cs b/src/Moonglade.Configuration/AdvancedSettings.cs index 23d46304f..c8187f23c 100644 --- a/src/Moonglade.Configuration/AdvancedSettings.cs +++ b/src/Moonglade.Configuration/AdvancedSettings.cs @@ -10,6 +10,11 @@ public class AdvancedSettings : IBlogSettings [MaxLength(1024)] public string RobotsTxtContent { get; set; } + [Display(Name = "Foot JavaScript")] + [DataType(DataType.MultilineText)] + [MaxLength(256)] + public string FootScripts { get; set; } + [Display(Name = "Enable Pingback")] public bool EnablePingback { get; set; } = true; diff --git a/src/Moonglade.Configuration/JsonExtensions.cs b/src/Moonglade.Configuration/JsonExtensions.cs index 8a6984131..87f3452e2 100644 --- a/src/Moonglade.Configuration/JsonExtensions.cs +++ b/src/Moonglade.Configuration/JsonExtensions.cs @@ -20,7 +20,8 @@ public static class JsonExtensions UnicodeRanges.CjkUnifiedIdeographsExtensionA, UnicodeRanges.CjkSymbolsandPunctuation, UnicodeRanges.HalfwidthandFullwidthForms), - PropertyNameCaseInsensitive = true + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; // Workaround stupid: @@ -39,6 +40,7 @@ public static class JsonExtensions UnicodeRanges.CjkSymbolsandPunctuation, UnicodeRanges.HalfwidthandFullwidthForms), PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true }; diff --git a/src/Moonglade.Core/TagFeature/Tag.cs b/src/Moonglade.Core/TagFeature/Tag.cs index 904fb7d0a..55f1c6d86 100644 --- a/src/Moonglade.Core/TagFeature/Tag.cs +++ b/src/Moonglade.Core/TagFeature/Tag.cs @@ -41,6 +41,12 @@ public static string NormalizeName(string orgTagName, IDictionaryenable - + diff --git a/src/Moonglade.Data.PostgreSql/Moonglade.Data.PostgreSql.csproj b/src/Moonglade.Data.PostgreSql/Moonglade.Data.PostgreSql.csproj index fec024f67..778e4bcd5 100644 --- a/src/Moonglade.Data.PostgreSql/Moonglade.Data.PostgreSql.csproj +++ b/src/Moonglade.Data.PostgreSql/Moonglade.Data.PostgreSql.csproj @@ -10,7 +10,7 @@ enable - + diff --git a/src/Moonglade.Data/Entities/FriendLinkEntity.cs b/src/Moonglade.Data/Entities/FriendLinkEntity.cs index 36b942ffe..e3df8e362 100644 --- a/src/Moonglade.Data/Entities/FriendLinkEntity.cs +++ b/src/Moonglade.Data/Entities/FriendLinkEntity.cs @@ -9,6 +9,8 @@ public class FriendLinkEntity public string Title { get; set; } public string LinkUrl { get; set; } + + public int Rank { get; set; } } internal class FriendLinkConfiguration : IEntityTypeConfiguration diff --git a/src/Moonglade.FriendLink/AddLinkCommand.cs b/src/Moonglade.FriendLink/AddLinkCommand.cs index 286289a41..310ff6555 100644 --- a/src/Moonglade.FriendLink/AddLinkCommand.cs +++ b/src/Moonglade.FriendLink/AddLinkCommand.cs @@ -19,6 +19,9 @@ public class AddLinkCommand : IRequest, IValidatableObject [MaxLength(256)] public string LinkUrl { get; set; } + [Display(Name = "Rank")] + public int Rank { get; set; } + public IEnumerable Validate(ValidationContext validationContext) { if (!Uri.IsWellFormedUriString(LinkUrl, UriKind.Absolute)) @@ -36,7 +39,8 @@ public async Task Handle(AddLinkCommand request, CancellationToken ct) { Id = Guid.NewGuid(), LinkUrl = Helper.SterilizeLink(request.LinkUrl), - Title = request.Title + Title = request.Title, + Rank = request.Rank }; await repo.AddAsync(link, ct); diff --git a/src/Moonglade.FriendLink/UpdateLinkCommand.cs b/src/Moonglade.FriendLink/UpdateLinkCommand.cs index a6c5cfc57..743cc890e 100644 --- a/src/Moonglade.FriendLink/UpdateLinkCommand.cs +++ b/src/Moonglade.FriendLink/UpdateLinkCommand.cs @@ -24,6 +24,7 @@ public async Task Handle(UpdateLinkCommand request, CancellationToken ct) { link.Title = request.Title; link.LinkUrl = Helper.SterilizeLink(request.LinkUrl); + link.Rank = request.Rank; await repo.UpdateAsync(link, ct); } diff --git a/src/Moonglade.Syndication/Moonglade.Syndication.csproj b/src/Moonglade.Syndication/Moonglade.Syndication.csproj index 8f1223536..f6e244539 100644 --- a/src/Moonglade.Syndication/Moonglade.Syndication.csproj +++ b/src/Moonglade.Syndication/Moonglade.Syndication.csproj @@ -9,7 +9,7 @@ enable - + diff --git a/src/Moonglade.Utils/Helper.cs b/src/Moonglade.Utils/Helper.cs index b1902e495..21f4978fc 100644 --- a/src/Moonglade.Utils/Helper.cs +++ b/src/Moonglade.Utils/Helper.cs @@ -412,8 +412,9 @@ public static void ValidatePagingParameters(int pageSize, int pageIndex) public static Dictionary TagNormalizationDictionary => new() { - { ".", "dot" }, - { "#", "sharp" }, - { " ", "-" } + { ".", "-" }, + { "#", "-sharp" }, + { " ", "-" }, + { "+", "-plus" } }; } \ No newline at end of file diff --git a/src/Moonglade.Utils/Moonglade.Utils.csproj b/src/Moonglade.Utils/Moonglade.Utils.csproj index 38eb2a036..8b56a574c 100644 --- a/src/Moonglade.Utils/Moonglade.Utils.csproj +++ b/src/Moonglade.Utils/Moonglade.Utils.csproj @@ -10,7 +10,7 @@ - - + + \ No newline at end of file diff --git a/src/Moonglade.Web/IconGenerator.cs b/src/Moonglade.Web/IconGenerator.cs index cacb09bb4..3f1596397 100644 --- a/src/Moonglade.Web/IconGenerator.cs +++ b/src/Moonglade.Web/IconGenerator.cs @@ -45,9 +45,9 @@ public static void GenerateIcons(string base64Data, string webRootPath, ILogger var dic = new Dictionary { - { "android-icon-", new[] { 36, 48, 72, 96, 144, 192 } }, + { "android-icon-", new[] { 144, 192 } }, { "favicon-", new[] { 16, 32, 96 } }, - { "apple-icon-", new[] { 57, 60, 72, 76, 114, 120, 144, 152, 180 } } + { "apple-icon-", new[] { 180 } } }; foreach (var (key, value) in dic) @@ -61,17 +61,14 @@ public static void GenerateIcons(string base64Data, string webRootPath, ILogger } } - var icon1Bytes = ResizeImage(image, 192, 192); + var icon1Bytes = ResizeImage(image, 180, 180); SiteIconDictionary.TryAdd("apple-icon.png", icon1Bytes); - - var icon2Bytes = ResizeImage(image, 192, 192); - SiteIconDictionary.TryAdd("apple-icon-precomposed.png", icon2Bytes); } public static byte[] GetIcon(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) return null; - return SiteIconDictionary.ContainsKey(fileName) ? SiteIconDictionary[fileName] : null; + return SiteIconDictionary.GetValueOrDefault(fileName); } private static byte[] ResizeImage(Image image, int toWidth, int toHeight) diff --git a/src/Moonglade.Web/Middleware/RSDMiddleware.cs b/src/Moonglade.Web/Middleware/RSDMiddleware.cs index 72428f5a8..e03010711 100644 --- a/src/Moonglade.Web/Middleware/RSDMiddleware.cs +++ b/src/Moonglade.Web/Middleware/RSDMiddleware.cs @@ -2,6 +2,10 @@ namespace Moonglade.Web.Middleware; +// Really Simple Discovery (RSD) is a protocol or method that makes it easier for client software to automatically discover the API endpoint needed to interact with a web service. It's primarily used in the context of blog software and content management systems (CMS). +// +// RSD allows client applications, like blog editors and content aggregators, to find the services needed to read, edit, or work with the content of a website without the user having to manually input the details of the API endpoints. For example, if you're using a desktop blogging application, RSD would enable that application to find the endpoint for the XML-RPC API of your blog so you can post directly from your desktop. + public class RSDMiddleware(RequestDelegate next) { public async Task Invoke(HttpContext httpContext, IBlogConfig blogConfig) diff --git a/src/Moonglade.Web/Middleware/SiteMapMiddleware.cs b/src/Moonglade.Web/Middleware/SiteMapMiddleware.cs index 5ebb74fbb..851001927 100644 --- a/src/Moonglade.Web/Middleware/SiteMapMiddleware.cs +++ b/src/Moonglade.Web/Middleware/SiteMapMiddleware.cs @@ -15,22 +15,15 @@ public async Task Invoke( IRepository postRepo, IRepository pageRepo) { - if (blogConfig.AdvancedSettings.EnableSiteMap && httpContext.Request.Path == "/sitemap.xml") + var xml = await cache.GetOrCreateAsync(BlogCachePartition.General.ToString(), "sitemap", async _ => { - var xml = await cache.GetOrCreateAsync(BlogCachePartition.General.ToString(), "sitemap", async _ => - { - var url = Helper.ResolveRootUrl(httpContext, blogConfig.GeneralSettings.CanonicalPrefix, true, true); - var data = await GetSiteMapData(url, postRepo, pageRepo, httpContext.RequestAborted); - return data; - }); + var url = Helper.ResolveRootUrl(httpContext, blogConfig.GeneralSettings.CanonicalPrefix, true, true); + var data = await GetSiteMapData(url, postRepo, pageRepo, httpContext.RequestAborted); + return data; + }); - httpContext.Response.ContentType = "text/xml"; - await httpContext.Response.WriteAsync(xml, httpContext.RequestAborted); - } - else - { - await next(httpContext); - } + httpContext.Response.ContentType = "text/xml"; + await httpContext.Response.WriteAsync(xml, httpContext.RequestAborted); } private static async Task GetSiteMapData( diff --git a/src/Moonglade.Web/Middleware/WebManifestMiddleware.cs b/src/Moonglade.Web/Middleware/WebManifestMiddleware.cs index 95c69e5d2..7280e0906 100644 --- a/src/Moonglade.Web/Middleware/WebManifestMiddleware.cs +++ b/src/Moonglade.Web/Middleware/WebManifestMiddleware.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Options; -using System.Text.Json; using System.Text.Json.Serialization; namespace Moonglade.Web.Middleware; @@ -11,32 +10,25 @@ public class WebManifestMiddleware(RequestDelegate next) public async Task Invoke( HttpContext context, IBlogConfig blogConfig, IOptions> manifestIcons) { - if (context.Request.Path == "/manifest.webmanifest") + var model = new ManifestModel { - var model = new ManifestModel - { - ShortName = blogConfig.GeneralSettings.SiteTitle, - Name = blogConfig.GeneralSettings.SiteTitle, - Description = blogConfig.GeneralSettings.SiteTitle, - StartUrl = "/", - Icons = manifestIcons?.Value, - BackgroundColor = Options.ThemeColor, - ThemeColor = Options.ThemeColor, - Display = "standalone", - Orientation = "portrait" - }; - - context.Response.StatusCode = StatusCodes.Status200OK; - context.Response.ContentType = "application/manifest+json"; - context.Response.Headers.TryAdd("cache-control", "public,max-age=3600"); - - // Do not use `WriteAsJsonAsync` because it will override ContentType header - await context.Response.WriteAsync(JsonSerializer.Serialize(model), context.RequestAborted); - } - else - { - await next(context); - } + ShortName = blogConfig.GeneralSettings.SiteTitle, + Name = blogConfig.GeneralSettings.SiteTitle, + Description = blogConfig.GeneralSettings.Description, + StartUrl = "/", + Icons = manifestIcons?.Value, + BackgroundColor = Options.ThemeColor, + ThemeColor = Options.ThemeColor, + Display = "standalone", + Orientation = "portrait" + }; + + context.Response.StatusCode = StatusCodes.Status200OK; + context.Response.ContentType = "application/manifest+json"; + context.Response.Headers.TryAdd("cache-control", "public,max-age=3600"); + + // Do not use `WriteAsJsonAsync` because it will override ContentType header + await context.Response.WriteAsync(model.ToJson(true), context.RequestAborted); } } @@ -83,7 +75,13 @@ public static partial class ApplicationBuilderExtensions public static IApplicationBuilder UseManifest(this IApplicationBuilder app, Action options) { options(WebManifestMiddleware.Options); - return app.UseMiddleware(); + + app.UseWhen( + ctx => ctx.Request.Path == "/manifest.webmanifest", + appBuilder => appBuilder.UseMiddleware() + ); + + return app; } } diff --git a/src/Moonglade.Web/Moonglade.Web.csproj b/src/Moonglade.Web/Moonglade.Web.csproj index b14a447f8..01a766758 100644 --- a/src/Moonglade.Web/Moonglade.Web.csproj +++ b/src/Moonglade.Web/Moonglade.Web.csproj @@ -35,12 +35,12 @@ - + + - - + diff --git a/src/Moonglade.Web/Pages/Admin/About.cshtml b/src/Moonglade.Web/Pages/Admin/About.cshtml index c00400e02..6b98595fb 100644 --- a/src/Moonglade.Web/Pages/Admin/About.cshtml +++ b/src/Moonglade.Web/Pages/Admin/About.cshtml @@ -65,6 +65,10 @@ @SharedLocalizer["User Name"] @Environment.UserDomainName\@Environment.UserName + + @SharedLocalizer["Server Time Zone"] + @TimeZoneInfo.Local.Id + @SharedLocalizer[".NET Version"] @Environment.Version @@ -89,12 +93,76 @@ @SharedLocalizer["Docker Container"] @(Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true") + + @if (!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"))) + { + + @SharedLocalizer["Azure App Service"] + + WEBSITE_SKU : @Environment.GetEnvironmentVariable("WEBSITE_SKU")
+ WEBSITE_SITE_NAME: @Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME")
+ WEBSITE_HOSTNAME : @Environment.GetEnvironmentVariable("WEBSITE_HOSTNAME")
+ REGION_NAME : @Environment.GetEnvironmentVariable("REGION_NAME")
+ + + } - + @SharedLocalizer["Legal Infomation"] + + Report an issue - \ No newline at end of file + + + diff --git a/src/Moonglade.Web/Pages/Admin/FriendLink.cshtml b/src/Moonglade.Web/Pages/Admin/FriendLink.cshtml index 4096bd6f9..3bd0c801d 100644 --- a/src/Moonglade.Web/Pages/Admin/FriendLink.cshtml +++ b/src/Moonglade.Web/Pages/Admin/FriendLink.cshtml @@ -4,7 +4,7 @@ ViewBag.Title = "Friend Links"; } -@section scripts{ +@section scripts { } -@section admintoolbar{ +@section admintoolbar {
@@ -84,13 +86,13 @@ }
- @foreach (var item in Model.Links.OrderBy(m => m.Title)) + @foreach (var item in Model.Links.OrderBy(m => m.Rank).ThenBy(m => m.Title)) {
- @item.Title + @item.Rank @item.Title
@item.LinkUrl @@ -124,6 +126,10 @@
+
+ + +
diff --git a/src/Moonglade.Web/Pages/Components/FriendLink/Default.cshtml b/src/Moonglade.Web/Pages/Components/FriendLink/Default.cshtml index d9fc1b377..efa07e78b 100644 --- a/src/Moonglade.Web/Pages/Components/FriendLink/Default.cshtml +++ b/src/Moonglade.Web/Pages/Components/FriendLink/Default.cshtml @@ -5,9 +5,9 @@ { -

@Html.DisplayNameFor(m => settings.RobotsTxtContent)

-
- -
-
-
-
-

- MetaWeblog -

+

+ MetaWeblog +

-
-
- -
-
- -
- @SharedLocalizer["* Requires restarting application"] -
+
+
+ +
+
+ +
+ @SharedLocalizer["* Requires restarting application"]
-
-
- - -
+
+
+
+ +
+
-
-
- + +
+
+

@Html.DisplayNameFor(m => settings.RobotsTxtContent)

+
+ +
+ +

@Html.DisplayNameFor(m => settings.FootScripts)

+
+
+ Using a third party script may cause your website to be blocked by some browsers or ad blockers, it can have security risks too. Please use with caution.
-
- - @SharedLocalizer["Generate password"] + + +
+ * Global script that will be injected into every page's footer, before the ending of body tag. Typically used for third party analytics services.
+ + * Please use valid <script>...</script> code.
diff --git a/src/Moonglade.Web/Pages/Settings/General.cshtml b/src/Moonglade.Web/Pages/Settings/General.cshtml index a85b8d143..c5f14480e 100644 --- a/src/Moonglade.Web/Pages/Settings/General.cshtml +++ b/src/Moonglade.Web/Pages/Settings/General.cshtml @@ -238,7 +238,7 @@
-
@SharedLocalizer["Use [c] for copyright mark: ©, [year] for current year."]
+
@Html.Raw(@SharedLocalizer["Use [c] for copyright mark: ©, [year] for current year."])
diff --git a/src/Moonglade.Web/Pages/Shared/_Favicons.cshtml b/src/Moonglade.Web/Pages/Shared/_Favicons.cshtml index ef8778079..27f6208a5 100644 --- a/src/Moonglade.Web/Pages/Shared/_Favicons.cshtml +++ b/src/Moonglade.Web/Pages/Shared/_Favicons.cshtml @@ -1,17 +1,7 @@ - - - - - - - - - + - - \ No newline at end of file diff --git a/src/Moonglade.Web/Pages/Shared/_Layout.cshtml b/src/Moonglade.Web/Pages/Shared/_Layout.cshtml index 67fc6deb9..cd49c7cb6 100644 --- a/src/Moonglade.Web/Pages/Shared/_Layout.cshtml +++ b/src/Moonglade.Web/Pages/Shared/_Layout.cshtml @@ -32,8 +32,8 @@ @if (BlogConfig.GeneralSettings.UseDublinCoreMetaData) { - - + + } @if (IsSectionDefined("keywords")) { @@ -95,8 +95,8 @@ } - - + + @@ -106,13 +106,14 @@ { } + + @if (!(bool)Context.Items["DNT"]) { @Html.Raw(JavaScriptSnippet.FullScript) } - @if (BlogConfig.ContentSettings.ShowCalloutSection) @@ -194,8 +195,8 @@
@BlogConfig.GeneralSettings.OwnerName + alt="@BlogConfig.GeneralSettings.OwnerName" + class="rounded-circle blogger-head-pic" />

@@ -250,5 +251,10 @@ } @await RenderSectionAsync("scripts", false) + + @if (!string.IsNullOrWhiteSpace(BlogConfig.AdvancedSettings.FootScripts)) + { + @Html.Raw(BlogConfig.AdvancedSettings.FootScripts) + } diff --git a/src/Moonglade.Web/Pages/Shared/_LayoutAdmin.cshtml b/src/Moonglade.Web/Pages/Shared/_LayoutAdmin.cshtml index 36c68f66e..8a0b49142 100644 --- a/src/Moonglade.Web/Pages/Shared/_LayoutAdmin.cshtml +++ b/src/Moonglade.Web/Pages/Shared/_LayoutAdmin.cshtml @@ -16,7 +16,7 @@ - + diff --git a/src/Moonglade.Web/Pages/Shared/_MonacoLoaderScript.cshtml b/src/Moonglade.Web/Pages/Shared/_MonacoLoaderScript.cshtml index 4ea0e36f3..bd919b40f 100644 --- a/src/Moonglade.Web/Pages/Shared/_MonacoLoaderScript.cshtml +++ b/src/Moonglade.Web/Pages/Shared/_MonacoLoaderScript.cshtml @@ -1,8 +1,9 @@ - +