├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── docfx.yml │ └── gitee-mirror.yml ├── .gitignore ├── Delete BIN OBJ Folders.bat ├── Directory.Build.props ├── LICENSE ├── LinCms.Scaffolding.sln ├── LinCms.sln ├── README.md ├── azure-pipelines.yml ├── build-all.ps1 ├── build_push.sh ├── docs ├── README.md ├── api │ └── index.md ├── articles │ ├── intro.md │ └── toc.yml ├── docfx.json ├── images │ ├── qq.png │ ├── wechat.png │ ├── 使用Bearer.PNG │ ├── 登录接口.PNG │ └── 返回access_token.PNG ├── index.md ├── sql │ └── README.md └── toc.yml ├── publish.bat ├── run.sh ├── src ├── LinCms.Application.Contracts │ ├── Base │ │ ├── BaseItems │ │ │ ├── BaseItemDto.cs │ │ │ ├── CreateUpdateBaseItemDto.cs │ │ │ └── IBaseItemService.cs │ │ └── BaseTypes │ │ │ ├── BaseTypeDto.cs │ │ │ ├── CreateUpdateBaseTypeDto.cs │ │ │ └── IBaseTypeService.cs │ ├── Blog │ │ ├── ArticleDrafts │ │ │ ├── ArticleDraftDto.cs │ │ │ ├── IArticleDraftService.cs │ │ │ └── UpdateArticleDraftDto.cs │ │ ├── Articles │ │ │ ├── ArticleDto.cs │ │ │ ├── ArticleListDto.cs │ │ │ ├── ArticleSearchDto.cs │ │ │ ├── CreateUpdateArticleDto.cs │ │ │ └── IArticleService.cs │ │ ├── AuthorCenter │ │ │ ├── ArticleCardDto.cs │ │ │ └── IAuthorCenterService.cs │ │ ├── Channels │ │ │ ├── ChannelDto.cs │ │ │ ├── ChannelSearchDto.cs │ │ │ ├── CreateUpdateChannelDto.cs │ │ │ ├── IChannelService.cs │ │ │ └── NavChannelListDto.cs │ │ ├── Classifys │ │ │ ├── ClassifyDto.cs │ │ │ ├── ClassifySearchDto.cs │ │ │ ├── CreateUpdateClassifyDto.cs │ │ │ └── IClassifyService.cs │ │ ├── Collections │ │ │ ├── CollectionDto.cs │ │ │ ├── CollectionSearchDto.cs │ │ │ ├── CreateCancelArticleCollectionDto.cs │ │ │ ├── CreateUpdateCollectionDto.cs │ │ │ ├── IArticleCollectionService.cs │ │ │ └── ICollectionService.cs │ │ ├── Comments │ │ │ ├── CommentDto.cs │ │ │ ├── CommentSearchDto.cs │ │ │ ├── CreateCommentDto.cs │ │ │ └── ICommentService.cs │ │ ├── Notifications │ │ │ ├── ArticleEntry.cs │ │ │ ├── CommentEntry.cs │ │ │ ├── CreateNotificationDto.cs │ │ │ ├── IEventService.cs │ │ │ ├── INotificationService.cs │ │ │ ├── NotificationDto.cs │ │ │ └── NotificationSearchDto.cs │ │ ├── Tags │ │ │ ├── CreateUpdateTagDto.cs │ │ │ ├── ITagService.cs │ │ │ ├── IUserTagService.cs │ │ │ ├── TagDto.cs │ │ │ ├── TagListDto.cs │ │ │ ├── TagSearchDto.cs │ │ │ └── UserTagDto.cs │ │ ├── UserLikes │ │ │ ├── CreateUpdateUserLikeDto.cs │ │ │ └── IUserLikeService.cs │ │ └── UserSubscribes │ │ │ ├── IUserSubscribeService.cs │ │ │ ├── SubscribeCountDto.cs │ │ │ ├── UserSubscribeDto.cs │ │ │ └── UserSubscribeSearchDto.cs │ ├── Cms │ │ ├── Account │ │ │ ├── IAccountService.cs │ │ │ ├── ITokenService.cs │ │ │ ├── LoginCaptchaDto.cs │ │ │ ├── LoginInputDto.cs │ │ │ ├── RegisterDto.cs │ │ │ ├── ResetEmailPasswordDto.cs │ │ │ └── SendEmailCodeInput.cs │ │ ├── Admins │ │ │ ├── ResetPasswordDto.cs │ │ │ ├── UpdateUserDto.cs │ │ │ └── UserSearchDto.cs │ │ ├── Files │ │ │ ├── FileDto.cs │ │ │ └── IFileService.cs │ │ ├── Groups │ │ │ ├── CreateGroupDto.cs │ │ │ ├── GroupDto.cs │ │ │ ├── IGroupService.cs │ │ │ └── UpdateGroupDto.cs │ │ ├── Logs │ │ │ ├── ILogService.cs │ │ │ ├── ISerilogService.cs │ │ │ ├── LogDashboard.cs │ │ │ ├── LogDto.cs │ │ │ ├── LogSearchDto.cs │ │ │ ├── SerilogSearchDto.cs │ │ │ └── VisitLogUserDto.cs │ │ ├── Permissions │ │ │ ├── DispatchPermissionsDto.cs │ │ │ ├── IPermissionService.cs │ │ │ ├── PermissioCreateUpdateDto.cs │ │ │ ├── PermissionDto.cs │ │ │ └── RemovePermissionDto.cs │ │ ├── Settings │ │ │ ├── CreateUpdateSettingDto.cs │ │ │ ├── ISettingService.cs │ │ │ └── SettingDto.cs │ │ └── Users │ │ │ ├── ChangePasswordDto.cs │ │ │ ├── CreateUserDto.cs │ │ │ ├── IOAuth2Service.cs │ │ │ ├── IUserIdentityService.cs │ │ │ ├── IUserService.cs │ │ │ ├── OAuthService.cs │ │ │ ├── OpenUserDto.cs │ │ │ ├── UpdateAvatarDto.cs │ │ │ ├── UpdateNickNameDto.cs │ │ │ ├── UpdateProfileDto.cs │ │ │ ├── UserDto.cs │ │ │ ├── UserIdentityDto.cs │ │ │ ├── UserInformation.cs │ │ │ └── UserNoviceDto.cs │ ├── IApplicationService.cs │ ├── ICrudAppService.cs │ ├── LinCms.Application.Contracts.csproj │ └── LinCms.Application.Contracts.xml ├── LinCms.Application │ ├── AppliactionService.cs │ ├── Base │ │ ├── BaseItems │ │ │ ├── BaseItemProfile.cs │ │ │ └── BaseItemService.cs │ │ └── BaseTypes │ │ │ ├── BaseTypeProfile.cs │ │ │ └── BaseTypeService.cs │ ├── Blog │ │ ├── Articles │ │ │ ├── ArticleDraftService.cs │ │ │ ├── ArticleProfile.cs │ │ │ └── ArticleService.cs │ │ ├── AuthorCenter │ │ │ └── AuthorCenterService.cs │ │ ├── Channels │ │ │ ├── ChannelProfile.cs │ │ │ └── ChannelService.cs │ │ ├── Classifies │ │ │ ├── ClassifyProfile.cs │ │ │ └── ClassifyService.cs │ │ ├── Collections │ │ │ ├── ArticleCollectionService.cs │ │ │ ├── CollectionProfile.cs │ │ │ └── CollectionService.cs │ │ ├── Comments │ │ │ ├── CommentProfile.cs │ │ │ └── CommentService.cs │ │ ├── Notifications │ │ │ ├── EventService.cs │ │ │ ├── NotificationProfile.cs │ │ │ └── NotificationService.cs │ │ ├── Tags │ │ │ ├── TagProfile.cs │ │ │ ├── TagService.cs │ │ │ └── UserTagService.cs │ │ ├── UserLikes │ │ │ ├── UserLikeProfile.cs │ │ │ └── UserLikeService.cs │ │ └── UserSubscribes │ │ │ ├── UserSubscribeProfile.cs │ │ │ └── UserSubscribeService.cs │ ├── CapUnitOfWorkExtensions.cs │ ├── Cms │ │ ├── Account │ │ │ ├── AccountContracts.cs │ │ │ ├── AccountService.cs │ │ │ └── JwtTokenService.cs │ │ ├── Files │ │ │ ├── LocalFileService.cs │ │ │ └── QiniuService.cs │ │ ├── Groups │ │ │ ├── GroupProfile.cs │ │ │ └── GroupService.cs │ │ ├── Logs │ │ │ ├── LogService.cs │ │ │ └── SerilogService.cs │ │ ├── Permissions │ │ │ ├── PermissionProfile.cs │ │ │ ├── PermissionService.cs │ │ │ └── TreeBuilder.cs │ │ ├── Settings │ │ │ ├── SettingProfile.cs │ │ │ └── SettingService.cs │ │ └── Users │ │ │ ├── GiteeOAuth2Service.cs │ │ │ ├── GithubOAuth2Serivice.cs │ │ │ ├── UserIdentityProfile.cs │ │ │ ├── UserIdentityService.cs │ │ │ ├── UserProfile.cs │ │ │ └── UserService.cs │ ├── CrudAppService.cs │ └── LinCms.Application.csproj ├── LinCms.Core │ ├── Aop │ │ ├── Attributes │ │ │ ├── CacheableAttribute.cs │ │ │ ├── DisableAuditingAttribute.cs │ │ │ ├── IgnoreMemberAttribute.cs │ │ │ └── LoggerAttribute.cs │ │ └── Filter │ │ │ ├── LinCmsAuthorizeAttribute.cs │ │ │ ├── LinCmsExceptionFilter.cs │ │ │ └── LogActionFilterAttribute.cs │ ├── Common │ │ ├── EncryptUtil.cs │ │ ├── LinCmsUtils.cs │ │ └── LinConsts.cs │ ├── Data │ │ ├── Authorization │ │ │ ├── PermissionAuthorizationRequirement.cs │ │ │ └── ValidJtiRequirement.cs │ │ ├── Enums │ │ │ ├── CapMessageQueueType.cs │ │ │ ├── CapStorageType.cs │ │ │ ├── ErrorCode.cs │ │ │ ├── Status.cs │ │ │ ├── TokenType.cs │ │ │ └── UserStatus.cs │ │ ├── Options │ │ │ ├── FileStorageOption.cs │ │ │ ├── LocalFileOption.cs │ │ │ ├── QiniuOption.cs │ │ │ └── SiteOption.cs │ │ ├── PagedAndSortedRequestDto.cs │ │ ├── PermissionDefinition.cs │ │ └── UnifyResponseDto.cs │ ├── Domain │ │ ├── Captcha │ │ │ ├── CaptchaBO.cs │ │ │ ├── CaptchaManager.cs │ │ │ ├── CaptchaOption.cs │ │ │ ├── ICaptchaManager.cs │ │ │ └── ImgHelper.cs │ │ ├── ITokenManager.cs │ │ └── TokenManager.cs │ ├── Entities │ │ ├── Base │ │ │ ├── BaseItem.cs │ │ │ └── BaseType.cs │ │ ├── BlackRecord.cs │ │ ├── Blog │ │ │ ├── Article.cs │ │ │ ├── ArticleCollection.cs │ │ │ ├── ArticleDraft.cs │ │ │ ├── Channel.cs │ │ │ ├── ChannelTag.cs │ │ │ ├── Classify.cs │ │ │ ├── Collection.cs │ │ │ ├── Comment.cs │ │ │ ├── Notification.cs │ │ │ ├── Tag.cs │ │ │ ├── TagArticle.cs │ │ │ ├── UserLike.cs │ │ │ ├── UserSubscribe.cs │ │ │ └── UserTag.cs │ │ ├── LinFile.cs │ │ ├── LinGroup.cs │ │ ├── LinGroupPermission.cs │ │ ├── LinLog.cs │ │ ├── LinPermission.cs │ │ ├── LinUser.cs │ │ ├── LinUserGroup.cs │ │ ├── LinUserIdentity.cs │ │ ├── SerilogDO.cs │ │ └── Settings │ │ │ └── LinSetting.cs │ ├── Exceptions │ │ └── LinCmsException.cs │ ├── Extensions │ │ ├── CollectionsExtensions.cs │ │ ├── HttpContextExtensions.cs │ │ └── LinCmsTimeConverter.cs │ ├── IRepositories │ │ ├── IFileRepository.cs │ │ ├── ILogRepository.cs │ │ ├── ISettingRepository.cs │ │ └── IUserRepository.cs │ ├── LinCms.Core.csproj │ ├── LinCms.Core.xml │ ├── Middleware │ │ └── CustomExceptionMiddleWare.cs │ └── Security │ │ ├── CurrentUserExtensions.cs │ │ └── LinCmsClaimTypes.cs ├── LinCms.Infrastructure │ ├── FreeSql │ │ ├── CodeFirstExtension.cs │ │ ├── DataSeedContributor.cs │ │ ├── FreeSqlExtension.cs │ │ └── IDataSeedContributor.cs │ ├── LinCms.Infrastructure.csproj │ └── Repositories │ │ ├── FileRepository.cs │ │ ├── LogRepository.cs │ │ ├── SettingRepository.cs │ │ └── UserRepository.cs ├── LinCms.Plugins │ ├── LinCms.Plugins.csproj │ └── Poem │ │ ├── Controllers │ │ └── PoemController.cs │ │ ├── Domain │ │ └── LinPoem.cs │ │ ├── Models │ │ ├── CreateUpdatePoemDto.cs │ │ └── PoemDto.cs │ │ ├── PoemModule.cs │ │ └── Services │ │ ├── IPoemService.cs │ │ ├── PoemProfile.cs │ │ └── PoemService.cs ├── LinCms.Scaffolding │ ├── App.cs │ ├── CodeScaffolding.cs │ ├── Entities │ │ ├── CommandOption.cs │ │ ├── EntityInfo.cs │ │ ├── ProjectInfo.cs │ │ ├── PropertyInfo.cs │ │ └── SettingOptions.cs │ ├── Extensions.cs │ ├── LinCms.Scaffolding.csproj │ ├── Program.cs │ ├── Templates │ │ ├── lin-cms-vue │ │ │ ├── model │ │ │ │ └── {{EntityInfo.NameCamelize}}.js.txt │ │ │ ├── stage-config.js.txt │ │ │ └── view │ │ │ │ └── {{EntityInfo.NameCamelize}} │ │ │ │ ├── {{EntityInfo.NameCamelize}}-form.vue.txt │ │ │ │ └── {{EntityInfo.NameCamelize}}-list.vue.txt │ │ ├── {{ProjectInfo.FullName}}.Application.Contracts │ │ │ └── {{SettingOptions.Areas}} │ │ │ │ └── {{EntityInfo.NamePluralized}} │ │ │ │ ├── CreateUpdate{{EntityInfo.Name}}Dto.cs.txt │ │ │ │ ├── I{{EntityInfo.Name}}Service.cs.txt │ │ │ │ └── {{EntityInfo.Name}}Dto.cs.txt │ │ ├── {{ProjectInfo.FullName}}.Application │ │ │ └── {{SettingOptions.Areas}} │ │ │ │ └── {{EntityInfo.NamePluralized}} │ │ │ │ ├── {{EntityInfo.Name}}Profile.cs.txt │ │ │ │ └── {{EntityInfo.Name}}Service.cs.txt │ │ ├── {{ProjectInfo.FullName}}.Core │ │ │ └── IRepositories │ │ │ │ └── I{{EntityInfo.Name}}Repository.cs.txt │ │ ├── {{ProjectInfo.FullName}}.Infrastructure │ │ │ └── Repositories │ │ │ │ └── {{EntityInfo.Name}}Repository.cs.txt │ │ └── {{ProjectInfo.FullName}}.Web │ │ │ └── Controllers │ │ │ └── {{SettingOptions.Areas}} │ │ │ └── {{EntityInfo.Name}}Controller.cs.txt │ ├── Util.cs │ └── appsettings.json └── LinCms.Web │ ├── Controllers │ ├── ApiControllerBase.cs │ ├── Base │ │ ├── BaseItemController.cs │ │ └── BaseTypeController.cs │ ├── Blog │ │ ├── ArticleController.cs │ │ ├── ArticleDraftController.cs │ │ ├── AuthorCenterController.cs │ │ ├── ChannelController.cs │ │ ├── ClassifyController.cs │ │ ├── CollectionController.cs │ │ ├── CommentController.cs │ │ ├── NotificationController.cs │ │ ├── TagController.cs │ │ ├── UserLikeController.cs │ │ ├── UserSubscribeController.cs │ │ └── UserTagController.cs │ ├── Cms │ │ ├── AccountController.cs │ │ ├── AdminController.cs │ │ ├── FileController.cs │ │ ├── GroupController.cs │ │ ├── LogController.cs │ │ ├── Oauth2Controller.cs │ │ ├── PermissionController.cs │ │ ├── SettingController.cs │ │ └── UserController.cs │ └── v1 │ │ ├── MonitorController.cs │ │ └── QiniuController.cs │ ├── Data │ ├── Authorization │ │ ├── PermissionAuthorizationHandler.cs │ │ └── ValidJtiHandler.cs │ └── MigrationStartupTask.cs │ ├── Dockerfile │ ├── Fonts │ └── JetBrainsMono-Bold.ttf │ ├── LinCms.Web.csproj │ ├── LinCms.Web.xml │ ├── Middleware │ ├── AopCacheAsyncIntercept.cs │ ├── AopCacheIntercept.cs │ ├── AopCacheableActionFilter.cs │ ├── BasicAuthenticationMiddleware.cs │ ├── CacheableMethodInfoExtensions.cs │ ├── IpLimitMiddleware.cs │ └── RecaptchaVerifyActionFilter.cs │ ├── Models │ └── Options │ │ └── GooglereCAPTCHAOptions.cs │ ├── Properties │ └── launchSettings.json │ ├── RateLimitConfig.json │ ├── Startup │ ├── Configuration │ │ ├── AutofacModule.cs │ │ ├── RepositoryModule.cs │ │ └── ServiceModule.cs │ ├── JwtExtensions.cs │ ├── Program.cs │ ├── ServiceCollectionExtensions.cs │ ├── ServiceProviderExtensions.cs │ └── SwaggerExtensions.cs │ ├── Utils │ ├── LogHelper.cs │ ├── MultipartRequestHelper.cs │ ├── ReflexHelper.cs │ ├── StopWords.cs │ └── ToolGoodUtils.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ └── _Illegal.zip └── test └── LinCms.Test ├── Core └── EmailSenderTest.cs ├── EnumTest.cs ├── ExpandObjTest.cs ├── LinCms.Test.csproj ├── LinCmsTest.cs ├── Md5CommonTest.cs ├── Properties └── launchSettings.json ├── ReflexTest.cs ├── Repositories └── Blog │ ├── ArticleRepositoryTest.cs │ ├── CommentRepositoryTest.cs │ ├── TagRepositoryTest.cs │ └── UserSubscribeRepositoryTest.cs ├── Service ├── Base │ └── BaseTypeServiceTest.cs ├── Blog │ └── ArticleServiceTest.cs └── Cms │ ├── LogServiceTest.cs │ └── UserServiceTest.cs ├── Startup.cs ├── Utils └── ToolWordTest.cs ├── appsettings.Development.json └── appsettings.json /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # CS1570: XML 注释出现 XML 格式错误 4 | dotnet_diagnostic.CS1570.severity = none 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **重现步骤(可选):** 11 | 12 | **期望的结果是什么?** 13 | 14 | **实际的结果是什么?** 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **描述你希望的支持的新功能?** 11 | 12 | **你期望的 API 是怎样的?** 13 | -------------------------------------------------------------------------------- /.github/workflows/docfx.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core Deploy Docfx 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | - name: Setup .NET Core 17 | uses: actions/setup-dotnet@v1 18 | with: 19 | dotnet-version: 7.0.101 20 | - name: Install dependencies 21 | run: dotnet restore LinCms.sln 22 | - name: Build solution 23 | run: dotnet build LinCms.sln --configuration Release --no-restore 24 | 25 | generate-docs: 26 | runs-on: windows-latest 27 | needs: build 28 | 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v2 32 | - name: Setup .NET Core 33 | uses: actions/setup-dotnet@v1 34 | with: 35 | dotnet-version: 7.0.101 36 | - name: Install dependencies 37 | run: dotnet restore LinCms.sln 38 | - name: Setup DocFX 39 | uses: crazy-max/ghaction-chocolatey@v1 40 | with: 41 | args: install docfx 42 | - name: DocFX Build 43 | working-directory: docs 44 | run: docfx docfx.json 45 | continue-on-error: false 46 | - name: Publish 47 | if: github.event_name == 'push' 48 | uses: peaceiris/actions-gh-pages@v3 49 | with: 50 | github_token: ${{ secrets.GITHUB_TOKEN }} 51 | publish_dir: docs/_site 52 | force_orphan: true 53 | -------------------------------------------------------------------------------- /.github/workflows/gitee-mirror.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - gh-pages 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Sync to Gitee 💕 14 | uses: wearerequired/git-mirror-action@master 15 | env: 16 | SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} 17 | with: 18 | source-repo: "git@github.com:luoyunchong/lin-cms-dotnetcore.git" 19 | destination-repo: "git@gitee.com:igeekfan/lin-cms-dotnetcore.git" 20 | -------------------------------------------------------------------------------- /Delete BIN OBJ Folders.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | @echo Deleting all BIN, OBJ folders... 3 | for /d /r . %%d in (bin,obj) do @if exist "%%d" rd /s/q "%%d" 4 | @echo. 5 | @echo BIN and OBJ folders successfully deleted :) Close the window. 6 | @echo. 7 | @echo. 8 | pause > nul -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://github.com/luoyunchong/lin-cms-dotnetcore 5 | true 6 | true 7 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 IGeekFan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LinCms.Scaffolding.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30223.230 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinCms.Scaffolding", "src\LinCms.Scaffolding\LinCms.Scaffolding.csproj", "{FC1AC12F-338B-4608-ABF3-F301BF631F21}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {FC1AC12F-338B-4608-ABF3-F301BF631F21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {FC1AC12F-338B-4608-ABF3-F301BF631F21}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {FC1AC12F-338B-4608-ABF3-F301BF631F21}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {FC1AC12F-338B-4608-ABF3-F301BF631F21}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {60090452-8177-4B47-B59D-CE49B7D519F9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | 2 | trigger: 3 | - master 4 | 5 | pool: 6 | vmImage: 'ubuntu-latest' 7 | 8 | variables: 9 | dockerId: luoyunchong@foxmail.com 10 | namespace: igeekfan 11 | webimageName: lincms-web 12 | registry: registry.cn-hangzhou.aliyuncs.com 13 | linCmsWebdockerfilepath: src/LinCms.Web/Dockerfile 14 | 15 | steps: 16 | - script: | 17 | docker build -f $(linCmsWebdockerfilepath) -t $(webimageName) . 18 | echo $(pwd) | docker login --username $(dockerId) $(registry) --password-stdin 19 | docker tag $(webimageName) $(registry)/$(namespace)/$(webimageName) 20 | docker push $(registry)/$(namespace)/$(webimageName) 21 | 22 | displayName: push to lincms-web -------------------------------------------------------------------------------- /build-all.ps1: -------------------------------------------------------------------------------- 1 | # COMMON PATHS 2 | 3 | $rootFolder = (Get-Item -Path "./" -Verbose).FullName 4 | 5 | # List of solutions 6 | 7 | $solutionPaths = ( 8 | "" 9 | ) 10 | 11 | # Build all solutions 12 | 13 | foreach ($solutionPath in $solutionPaths) { 14 | $solutionAbsPath = (Join-Path $rootFolder $solutionPath) 15 | Set-Location $solutionAbsPath 16 | dotnet build 17 | if (-Not $?) { 18 | Write-Host ("Build failed for the solution: " + $solutionPath) 19 | Set-Location $rootFolder 20 | exit $LASTEXITCODE 21 | } 22 | } 23 | 24 | Set-Location $rootFolder -------------------------------------------------------------------------------- /build_push.sh: -------------------------------------------------------------------------------- 1 | SERVER_NAME=lincms-web 2 | SERVER_Dockerfile=src/LinCms.Web/Dockerfile 3 | CID=$(docker ps | grep "${SERVER_NAME}" | awk '{print $1}') 4 | IID=$(docker images | grep "${SERVER_NAME}" | awk '{print $3}') 5 | 6 | docker rmi ${SERVER_NAME} 7 | docker build -f ${SERVER_Dockerfile} -t "${SERVER_NAME}":latest . 8 | docker tag ${SERVER_NAME} registry.cn-hangzhou.aliyuncs.com/igeekfan/${SERVER_NAME} 9 | docker push registry.cn-hangzhou.aliyuncs.com/igeekfan/${SERVER_NAME} 10 | docker image prune -f 11 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoyunchong/lin-cms-dotnetcore/e00f7c6e7a0a6c187a10d5ecda90ed9c911a55ff/docs/README.md -------------------------------------------------------------------------------- /docs/api/index.md: -------------------------------------------------------------------------------- 1 | # PLACEHOLDER 2 | TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*! 3 | -------------------------------------------------------------------------------- /docs/articles/intro.md: -------------------------------------------------------------------------------- 1 | # Add your introductions here! 2 | -------------------------------------------------------------------------------- /docs/articles/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Introduction 2 | href: intro.md 3 | -------------------------------------------------------------------------------- /docs/docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "files": [ 7 | "**/*.csproj" 8 | ], 9 | "exclude": [ 10 | "**/bin/**", 11 | "**/obj/**" 12 | ], 13 | "src": "../src" 14 | } 15 | ], 16 | "dest": "api", 17 | "disableGitFeatures": false, 18 | "disableDefaultFilter": false 19 | } 20 | ], 21 | "build": { 22 | "content": [ 23 | { 24 | "files": [ 25 | "api/**.yml", 26 | "api/index.md" 27 | ] 28 | }, 29 | { 30 | "files": [ 31 | "articles/**.md", 32 | "articles/**/toc.yml", 33 | "toc.yml", 34 | "*.md" 35 | ] 36 | } 37 | ], 38 | "resource": [ 39 | { 40 | "files": [ 41 | "images/**" 42 | ] 43 | } 44 | ], 45 | "overwrite": [ 46 | { 47 | "files": [ 48 | "apidoc/**.md" 49 | ], 50 | "exclude": [ 51 | "obj/**", 52 | "_site/**" 53 | ] 54 | } 55 | ], 56 | "dest": "_site", 57 | "globalMetadataFiles": [], 58 | "fileMetadataFiles": [], 59 | "template": [ 60 | "default" 61 | ], 62 | "postProcessors": [], 63 | "markdownEngineName": "markdig", 64 | "noLangKeyword": false, 65 | "keepFileLink": false, 66 | "cleanupCacheHistory": false, 67 | "disableGitFeatures": false 68 | } 69 | } -------------------------------------------------------------------------------- /docs/images/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoyunchong/lin-cms-dotnetcore/e00f7c6e7a0a6c187a10d5ecda90ed9c911a55ff/docs/images/qq.png -------------------------------------------------------------------------------- /docs/images/wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoyunchong/lin-cms-dotnetcore/e00f7c6e7a0a6c187a10d5ecda90ed9c911a55ff/docs/images/wechat.png -------------------------------------------------------------------------------- /docs/images/使用Bearer.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoyunchong/lin-cms-dotnetcore/e00f7c6e7a0a6c187a10d5ecda90ed9c911a55ff/docs/images/使用Bearer.PNG -------------------------------------------------------------------------------- /docs/images/登录接口.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoyunchong/lin-cms-dotnetcore/e00f7c6e7a0a6c187a10d5ecda90ed9c911a55ff/docs/images/登录接口.PNG -------------------------------------------------------------------------------- /docs/images/返回access_token.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoyunchong/lin-cms-dotnetcore/e00f7c6e7a0a6c187a10d5ecda90ed9c911a55ff/docs/images/返回access_token.PNG -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # This is the **HOMEPAGE**. 2 | Refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. 3 | ## Quick Start Notes: 4 | 1. Add images to the *images* folder if the file is referencing an image. 5 | -------------------------------------------------------------------------------- /docs/sql/README.md: -------------------------------------------------------------------------------- 1 | ## Code First 2 | 3 | 会自动创建数据库和初始化数据。 4 | 5 | - 默认账号:admin 6 | 7 | - 默认密码123qwe -------------------------------------------------------------------------------- /docs/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Articles 2 | href: articles/ 3 | - name: Api Documentation 4 | href: api/ 5 | homepage: api/index.md 6 | -------------------------------------------------------------------------------- /publish.bat: -------------------------------------------------------------------------------- 1 | 2 | @echo off 3 | 4 | dotnet clean 5 | dotnet restore 6 | dotnet build 7 | 8 | DEL /F/Q/S "D:\Publishes\lin-cms-dotnetcore" > NUL && RMDIR /Q/S "D:\Publishes\lin-cms-dotnetcore" 9 | 10 | ::dotnet publish -c Release -r win-x64 --self-contained false -o "D:\Publishes\lin-cms-dotnetcore\win-x64" 11 | ::dotnet publish -c Release -r win-x86 --self-contained false -o "D:\Publishes\lin-cms-dotnetcore\win-x86" 12 | ::dotnet publish -c Release -r osx-x64 --self-contained false -o "D:\Publishes\lin-cms-dotnetcore\osx-x64" 13 | dotnet publish -c Release -r linux-x64 --self-contained false -o "D:\Publishes\lin-cms-dotnetcore\linux-x64" -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | SERVER_NAME=lincms-web 2 | 3 | #判断是否存在webnotebook容器 4 | docker ps | grep lincms-web &> /dev/null 5 | #如果不存在,则Remove 6 | if [ $? -ne 0 ] 7 | then 8 | echo "${SERVER_NAME} container not exist continue.. " 9 | else 10 | echo "remove ${SERVER_NAME} container" 11 | docker rm ${SERVER_NAME} -f 12 | fi 13 | 14 | docker images | grep registry.cn-hangzhou.aliyuncs.com/igeekfan/${SERVER_NAME} &> /dev/null 15 | 16 | if [ $? -ne 0 ] 17 | then 18 | echo "image does not exist , continue..." 19 | else 20 | echo "image exists !!! remove it" 21 | docker rmi --force registry.cn-hangzhou.aliyuncs.com/igeekfan/${SERVER_NAME} 22 | fi 23 | #从阿里云拉取刚刚push的镜像 24 | docker pull registry.cn-hangzhou.aliyuncs.com/igeekfan/${SERVER_NAME} 25 | 26 | sudo docker run --restart \ 27 | unless-stopped \ 28 | -p 5011:8080 \ 29 | -v /var/www/lin-cms-dotnetcore/wwwroot/:/app/wwwroot:rw \ 30 | -v /var/www/lin-cms-dotnetcore/appsettings.Production.json/:/app/appsettings.Production.json:rw \ 31 | --privileged=true \ 32 | --name ${SERVER_NAME} \ 33 | -d registry.cn-hangzhou.aliyuncs.com/igeekfan/${SERVER_NAME} -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Base/BaseItems/BaseItemDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Base.BaseItems; 5 | 6 | public class BaseItemDto : EntityDto 7 | { 8 | public long BaseTypeId { get; set; } 9 | public string ItemCode { get; set; } 10 | public string ItemName { get; set; } 11 | public bool Status { get; set; } 12 | public int? SortCode { get; set; } 13 | public DateTime CreateTime { get; set; } 14 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Base/BaseItems/CreateUpdateBaseItemDto.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace LinCms.Base.BaseItems; 5 | 6 | public class CreateUpdateBaseItemDto : IValidatableObject 7 | { 8 | public int BaseTypeId { get; set; } 9 | [Required(ErrorMessage = "编码为必填项")] 10 | public string ItemCode { get; set; } 11 | [Required(ErrorMessage = "字典类别为必填项")] 12 | public string ItemName { get; set; } 13 | public bool Status { get; set; } 14 | public int? SortCode { get; set; } 15 | public IEnumerable Validate(ValidationContext validationContext) 16 | { 17 | if (BaseTypeId == 0) 18 | { 19 | yield return new ValidationResult("请选择类别", new List() { "BaseTypeId" }); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Base/BaseItems/IBaseItemService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace LinCms.Base.BaseItems; 5 | 6 | public interface IBaseItemService 7 | { 8 | Task DeleteAsync(int id); 9 | 10 | Task> GetListAsync(string typeCode); 11 | 12 | Task GetAsync(int id); 13 | 14 | Task CreateAsync(CreateUpdateBaseItemDto createBaseItem); 15 | 16 | Task UpdateAsync(int id, CreateUpdateBaseItemDto updateBaseItem); 17 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Base/BaseTypes/BaseTypeDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Base.BaseTypes; 5 | 6 | public class BaseTypeDto : EntityDto 7 | { 8 | public string TypeCode { get; set; } 9 | public string FullName { get; set; } 10 | public int? SortCode { get; set; } 11 | public DateTime CreateTime { get; set; } 12 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Base/BaseTypes/CreateUpdateBaseTypeDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Base.BaseTypes; 4 | 5 | public class CreateUpdateBaseTypeDto 6 | { 7 | [Required(ErrorMessage = "类别编码为必填项")] 8 | public string TypeCode { get; set; } 9 | [Required(ErrorMessage = "类别名称为必填项")] 10 | public string FullName { get; set; } 11 | public int? SortCode { get; set; } 12 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Base/BaseTypes/IBaseTypeService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | 4 | namespace LinCms.Base.BaseTypes; 5 | 6 | public interface IBaseTypeService 7 | { 8 | Task DeleteAsync(long id); 9 | 10 | Task> GetListAsync(); 11 | 12 | Task GetAsync(int id); 13 | 14 | Task CreateAsync(CreateUpdateBaseTypeDto createBaseType); 15 | 16 | Task UpdateAsync(int id, CreateUpdateBaseTypeDto updateBaseType); 17 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/ArticleDrafts/ArticleDraftDto.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Blog.ArticleDrafts; 2 | 3 | public class ArticleDraftDto 4 | { 5 | public string Title { get; set; } 6 | public string Content { get; set; } 7 | public int Editor { get; set; } 8 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/ArticleDrafts/IArticleDraftService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace LinCms.Blog.ArticleDrafts; 5 | 6 | public interface IArticleDraftService 7 | { 8 | Task UpdateAsync(Guid id, UpdateArticleDraftDto updateArticleDto); 9 | 10 | Task GetAsync(Guid id); 11 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/ArticleDrafts/UpdateArticleDraftDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Blog.ArticleDrafts; 4 | 5 | public class UpdateArticleDraftDto 6 | { 7 | [MaxLength(200)] 8 | public string Title { get; set; } 9 | 10 | [Required(ErrorMessage = "随笔内容不能为空")] 11 | public string Content { get; set; } 12 | 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Articles/ArticleListDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | using LinCms.Blog.Tags; 5 | using LinCms.Cms.Users; 6 | using LinCms.Common; 7 | using LinCms.Entities.Blog; 8 | 9 | namespace LinCms.Blog.Articles; 10 | 11 | public class ArticleListDto : Entity, ICreateAuditEntity 12 | { 13 | /// 14 | /// 技术频道Id 15 | /// 16 | public Guid? ChannelId { get; set; } 17 | /// 18 | /// 几小时/秒前 19 | /// 20 | public string TimeSpan => LinCmsUtils.GetTimeDifferNow(CreateTime.ToDateTime()); 21 | 22 | private readonly DateTime _now = DateTime.Now; 23 | public bool IsNew => DateTime.Compare(_now.AddDays(-2), CreateTime.ToDateTime()) <= 0; 24 | 25 | public string Title { get; set; } 26 | public string Keywords { get; set; } 27 | public string Excerpt { get; set; } 28 | public int ViewHits { get; set; } 29 | public int CommentQuantity { get; set; } 30 | public int LikesQuantity { get; set; } 31 | public string Thumbnail { get; set; } 32 | public string ThumbnailDisplay { get; set; } 33 | public bool IsAudit { get; set; } 34 | public bool Recommend { get; set; } 35 | public bool IsStickie { get; set; } 36 | public string Archive { get; set; } 37 | public ArticleType ArticleType { get; set; } 38 | public long? CreateUserId { get; set; } 39 | public string CreateUserName { get; set; } 40 | 41 | public DateTime CreateTime { get; set; } 42 | public string Author { get; set; } 43 | public bool IsLiked { get; set; } 44 | 45 | public OpenUserDto UserInfo { get; set; } 46 | 47 | public List Tags { get; set; } 48 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Articles/ArticleSearchDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LinCms.Data; 3 | 4 | namespace LinCms.Blog.Articles; 5 | 6 | public class ArticleSearchDto : PageDto 7 | { 8 | /// 9 | /// 分类Id 10 | /// 11 | public Guid? ClassifyId { get; set; } 12 | public Guid? ChannelId { get; set; } 13 | public Guid? TagId { get; set; } 14 | public string Title { get; set; } 15 | public Guid? ArticleId { get; set; } 16 | public long? UserId { get; set; } 17 | 18 | /// 19 | /// 收藏集合Id 20 | /// 21 | public Guid? CollectionId { get; set; } 22 | 23 | public ArticleSearchTypeEnum? ArticleSearchType { get; set; } 24 | public override string ToString() 25 | { 26 | return $"{ClassifyId}:{ChannelId}:{TagId}:{Title}:{UserId}:{Count}:{Page}:{Sort}"; 27 | } 28 | 29 | } 30 | 31 | 32 | public enum ArticleSearchTypeEnum 33 | { 34 | /// 35 | /// 点赞 36 | /// 37 | Like, 38 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Articles/CreateUpdateArticleDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using LinCms.Entities.Blog; 5 | 6 | namespace LinCms.Blog.Articles; 7 | 8 | public class CreateUpdateArticleDto 9 | { 10 | public Guid? ClassifyId { get; set; } 11 | public Guid? ChannelId { get; set; } 12 | [MaxLength(200)] 13 | public string Title { get; set; } 14 | [MaxLength(400)] 15 | public string Keywords { get; set; } 16 | [MaxLength(400)] 17 | public string Source { get; set; } 18 | [MaxLength(400)] 19 | public string Excerpt { get; set; } 20 | [Required(ErrorMessage = "随笔内容不能为空")] 21 | public string Content { get; set; } 22 | [MaxLength(400)] 23 | public string Thumbnail { get; set; } 24 | public bool IsAudit { get; set; } 25 | public bool Recommend { get; set; } 26 | public bool IsStickie { get; set; } 27 | [MaxLength(50)] 28 | public string Archive { get; set; } 29 | 30 | public ArticleType ArticleType { get; set; } 31 | 32 | public int Editor { get; set; } = 1; 33 | 34 | public List TagIds { get; set; } 35 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Articles/IArticleService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.Dto; 4 | using LinCms.Data; 5 | 6 | namespace LinCms.Blog.Articles; 7 | 8 | public interface IArticleService 9 | { 10 | #region CRUD 11 | Task CreateAsync(CreateUpdateArticleDto createArticle); 12 | 13 | Task UpdateAsync(Guid id, CreateUpdateArticleDto updateArticleDto); 14 | 15 | Task> GetArticleAsync(ArticleSearchDto searchDto); 16 | 17 | Task DeleteAsync(Guid id); 18 | 19 | Task GetAsync(Guid id); 20 | #endregion 21 | 22 | 23 | Task> GetAllArticleAsync(ArticleSearchDto searchDto); 24 | 25 | /// 26 | /// 得到我关注的人发布的随笔 27 | /// 28 | /// 29 | /// 30 | Task> GetSubscribeArticleAsync(PageDto pageDto); 31 | 32 | /// 33 | /// 更新随笔点赞量 34 | /// 35 | /// 36 | /// 37 | /// 38 | Task UpdateLikeQuantityAysnc(Guid subjectId, int likesQuantity); 39 | 40 | Task UpdateCollectQuantityAysnc(Guid articleId, int collectQuantity); 41 | 42 | /// 43 | /// 修改随笔是否允许其他人评论 44 | /// 45 | /// 46 | /// 47 | /// 48 | Task UpdateCommentable(Guid id, bool commentable); 49 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/AuthorCenter/ArticleCardDto.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Blog.AuthorCenter; 2 | 3 | /// 4 | /// 文章统计Card 5 | /// 6 | public class ArticleCardDto 7 | { 8 | /// 9 | /// 总文章数 10 | /// 11 | public long AllArticle { get; set; } 12 | 13 | /// 14 | /// 文章收藏数 15 | /// 16 | public long AllArticleCollect { get; set; } 17 | 18 | /// 19 | /// 文章评论数 20 | /// 21 | public long AllArticleComment { get; set; } 22 | 23 | /// 24 | /// 文章点赞数 25 | /// 26 | public long AllArticleStar { get; set; } 27 | 28 | /// 29 | /// 文章阅读数 30 | /// 31 | public long AllArticleView { get; set; } 32 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/AuthorCenter/IAuthorCenterService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace LinCms.Blog.AuthorCenter; 4 | 5 | /// 6 | /// 创建者中心 7 | /// 8 | public interface IAuthorCenterService : IApplicationService 9 | { 10 | /// 11 | /// 获取文章统计 12 | /// 13 | /// 14 | Task GetArtcileCardAsync(); 15 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Channels/ChannelDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | using LinCms.Blog.Tags; 5 | 6 | namespace LinCms.Blog.Channels; 7 | 8 | public class ChannelDto : Entity 9 | { 10 | /// 11 | /// 封面图 12 | /// 13 | public string Thumbnail { get; set; } 14 | 15 | public string ThumbnailDisplay { get; set; } 16 | /// 17 | /// 排序 18 | /// 19 | public int SortCode { get; set; } 20 | /// 21 | /// 技术频道名称 22 | /// 23 | 24 | public string ChannelName { get; set; } 25 | 26 | /// 27 | /// 编码 28 | /// 29 | public string ChannelCode { get; set; } 30 | 31 | /// 32 | /// 备注描述 33 | /// 34 | public string Remark { get; set; } 35 | 36 | public bool Status { get; set; } 37 | 38 | 39 | public List Tags { get; set; } 40 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Channels/ChannelSearchDto.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Data; 2 | 3 | namespace LinCms.Blog.Channels; 4 | 5 | public class ChannelSearchDto : PageDto 6 | { 7 | public string ChannelName { get; set; } 8 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Channels/CreateUpdateChannelDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace LinCms.Blog.Channels; 5 | 6 | public class CreateUpdateChannelDto 7 | { 8 | /// 9 | /// 封面图 10 | /// 11 | public string Thumbnail { get; set; } 12 | /// 13 | /// 排序 14 | /// 15 | public int SortCode { get; set; } 16 | /// 17 | /// 技术频道名称 18 | /// 19 | 20 | public string ChannelName { get; set; } 21 | 22 | /// 23 | /// 编码 24 | /// 25 | public string ChannelCode { get; set; } 26 | 27 | /// 28 | /// 备注描述 29 | /// 30 | public string Remark { get; set; } 31 | /// 32 | /// 是否有效 33 | /// 34 | public bool Status { get; set; } 35 | 36 | public List TagIds { get; set; } 37 | 38 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Channels/IChannelService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.Dto; 4 | using LinCms.Data; 5 | 6 | namespace LinCms.Blog.Channels; 7 | 8 | /// 9 | /// 技术频道 10 | /// 11 | public interface IChannelService 12 | { 13 | #region CRUD 14 | Task> GetListAsync(ChannelSearchDto searchDto); 15 | 16 | Task GetAsync(Guid id); 17 | 18 | Task CreateAsync(CreateUpdateChannelDto createChannel); 19 | 20 | Task UpdateAsync(Guid id, CreateUpdateChannelDto updateChannel); 21 | Task DeleteAsync(Guid id); 22 | #endregion 23 | 24 | /// 25 | /// 首页减少不必要的字段后,流量字节更少 26 | /// 27 | /// 28 | /// 29 | Task> GetNavListAsync(PageDto pageDto); 30 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Channels/NavChannelListDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | using LinCms.Blog.Tags; 5 | 6 | namespace LinCms.Blog.Channels; 7 | 8 | public class NavChannelListDto : Entity 9 | { 10 | /// 11 | /// 技术频道名称 12 | /// 13 | 14 | public string ChannelName { get; set; } 15 | 16 | /// 17 | /// 编码 18 | /// 19 | public string ChannelCode { get; set; } 20 | 21 | 22 | public List Tags { get; set; } 23 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Classifys/ClassifyDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Blog.Classifys; 5 | 6 | public class ClassifyDto : EntityDto, ICreateAuditEntity 7 | { 8 | public string Thumbnail { get; set; } 9 | public string ThumbnailDisplay { get; set; } 10 | public int SortCode { get; set; } 11 | public string ClassifyName { get; set; } 12 | public int ArticleCount { get; set; } = 0; 13 | public long? CreateUserId { get; set; } 14 | public string CreateUserName { get; set; } 15 | public DateTime CreateTime { get; set; } 16 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Classifys/ClassifySearchDto.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Data; 2 | 3 | namespace LinCms.Blog.Classifys; 4 | 5 | public class ClassifySearchDto : PageDto 6 | { 7 | public long? UserId { get; set; } 8 | public string ClassifyName { get; set; } 9 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Classifys/CreateUpdateClassifyDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Blog.Classifys; 4 | 5 | public class CreateUpdateClassifyDto 6 | { 7 | [Required(ErrorMessage = "请上传专栏图")] 8 | public string Thumbnail { get; set; } 9 | public int SortCode { get; set; } 10 | [Required(ErrorMessage = "分类专栏为必填项")] 11 | public string ClassifyName { get; set; } 12 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Classifys/IClassifyService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | 5 | namespace LinCms.Blog.Classifys; 6 | 7 | /// 8 | /// 用户自己的分类 9 | /// 10 | public interface IClassifyService : ICrudAppService 11 | { 12 | Task UpdateArticleCountAsync(Guid? id, int inCreaseCount); 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Collections/CollectionDto.cs: -------------------------------------------------------------------------------- 1 | using IGeekFan.FreeKit.Extras.AuditEntity; 2 | using LinCms.Entities.Blog; 3 | using System; 4 | 5 | namespace LinCms.Blog.Collections; 6 | 7 | public class CollectionDto : EntityDto, ICreateAuditEntity 8 | { 9 | /// 10 | /// 名称 11 | /// 12 | public string Name { get; set; } 13 | 14 | /// 15 | /// 描述 16 | /// 17 | public string Remark { get; set; } 18 | 19 | /// 20 | /// 公开 当其他人关注此收藏集后不可再更改为隐私 21 | /// 隐私 仅自己可见此收藏集 22 | /// 23 | public PrivacyType PrivacyType { get; set; } 24 | 25 | public long? CreateUserId { get; set; } 26 | public string CreateUserName { get; set; } 27 | public DateTime CreateTime { get; set; } 28 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Collections/CollectionSearchDto.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Data; 2 | using System; 3 | 4 | namespace LinCms.Blog.Collections; 5 | 6 | public class CollectionSearchDto : PageDto 7 | { 8 | public string Name { get; set; } 9 | 10 | public long? UserId { get; set; } 11 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Collections/CreateCancelArticleCollectionDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Blog.Collections; 4 | 5 | public class CreateCancelArticleCollectionDto 6 | { 7 | public Guid ArticleId { get; set; } 8 | public Guid? CollectionId { get; set; } 9 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Collections/CreateUpdateCollectionDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using JetBrains.Annotations; 3 | using LinCms.Entities.Blog; 4 | 5 | namespace LinCms.Blog.Collections; 6 | 7 | public class CreateUpdateCollectionDto 8 | { 9 | public string Name { get; set; } 10 | 11 | /// 12 | /// 描述 13 | /// 14 | [CanBeNull] 15 | [StringLength(200,ErrorMessage = "描述最长为200")] 16 | public string Remark { get; set; } 17 | 18 | /// 19 | /// 公开 当其他人关注此收藏集后不可再更改为隐私 20 | /// 隐私 仅自己可见此收藏集 21 | /// 22 | public PrivacyType PrivacyType { get; set; } 23 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Collections/IArticleCollectionService.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoyunchong/lin-cms-dotnetcore/e00f7c6e7a0a6c187a10d5ecda90ed9c911a55ff/src/LinCms.Application.Contracts/Blog/Collections/IArticleCollectionService.cs -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Collections/ICollectionService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.Dto; 4 | using LinCms.Blog.Collections; 5 | using LinCms.Entities.Blog; 6 | 7 | namespace LinCms.Blog.Collections; 8 | 9 | /// 10 | /// 收藏夹服务 11 | /// 12 | public interface ICollectionService : ICrudAppService 13 | { 14 | 15 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Comments/CommentDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | using LinCms.Cms.Users; 5 | 6 | namespace LinCms.Blog.Comments; 7 | 8 | public class CommentDto : EntityDto, ICreateAuditEntity 9 | { 10 | /// 11 | /// 回复评论Id 12 | /// 13 | public Guid? RespId { get; set; } 14 | /// 15 | /// 回复的文本内容 16 | /// 17 | public string Text { get; set; } 18 | 19 | /// 20 | /// 关联随笔id 21 | /// 22 | public Guid? SubjectId { get; set; } 23 | 24 | public long? CreateUserId { get; set; } 25 | public string CreateUserName { get; set; } 26 | public DateTime CreateTime { get; set; } 27 | 28 | /// 29 | /// 评论的用户 30 | /// 31 | public OpenUserDto UserInfo { get; set; } 32 | 33 | /// 34 | /// 回复的用户 35 | /// 36 | public OpenUserDto RespUserInfo { get; set; } 37 | 38 | public bool IsLiked { get; set; } 39 | 40 | public bool? IsAudit { get; set; } 41 | 42 | public int LikesQuantity { get; set; } 43 | 44 | public Guid? RootCommentId { get; set; } 45 | /// 46 | /// 最新的二条回复 47 | /// 48 | public List TopComment { get; set; } 49 | 50 | 51 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Comments/CommentSearchDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LinCms.Data; 3 | 4 | namespace LinCms.Blog.Comments; 5 | 6 | public class CommentSearchDto : PageDto 7 | { 8 | public Guid? RootCommentId { get; set; } 9 | public Guid? SubjectId { get; set; } 10 | 11 | public String Text { get; set; } 12 | 13 | public bool? IsAudit { get; set; } 14 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Comments/CreateCommentDto.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | 4 | namespace LinCms.Blog.Comments; 5 | 6 | public class CreateCommentDto 7 | { 8 | /// 9 | /// 回复评论Id 10 | /// 11 | public Guid? RespId { get; set; } 12 | /// 13 | /// 根回复id 14 | /// 15 | public Guid? RootCommentId { get; set; } 16 | /// 17 | /// 回复的文本内容 18 | /// 19 | public string Text { get; set; } 20 | /// 21 | /// 关联随笔id 22 | /// 23 | public Guid? SubjectId { get; set; } 24 | /// 25 | /// 被回复的用户Id 26 | /// 27 | public long RespUserId { get; set; } 28 | 29 | public int SubjectType { get; set; } 30 | } 31 | -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Comments/ICommentService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.Dto; 4 | using LinCms.Entities.Blog; 5 | 6 | namespace LinCms.Blog.Comments; 7 | 8 | /// 9 | /// 评论 10 | /// 11 | public interface ICommentService 12 | { 13 | /// 14 | /// 随笔下的评论列表 15 | /// 16 | /// 17 | /// 18 | Task> GetListByArticleAsync(CommentSearchDto commentSearchDto); 19 | 20 | /// 21 | /// 评论分页项 22 | /// 23 | /// 24 | /// 25 | Task> GetListAsync(CommentSearchDto commentSearchDto); 26 | 27 | /// 28 | /// 发表评论 29 | /// 30 | /// 31 | /// 32 | Task CreateAsync(CreateCommentDto createCommentDto); 33 | 34 | /// 35 | /// 删除评论并同步随笔数量 36 | /// 37 | /// 38 | Task DeleteAsync(Comment comment); 39 | 40 | /// 41 | /// 删除评论,先查一次 42 | /// 43 | /// 评论表Id 44 | Task DeleteAsync(Guid id); 45 | 46 | /// 47 | /// 只删除自己的评论 48 | /// 49 | /// 50 | /// 51 | Task DeleteMyComment(Guid id); 52 | 53 | /// 54 | /// 修改评论的点赞的数量 55 | /// 56 | /// 57 | /// 58 | /// 59 | Task UpdateLikeQuantityAysnc(Guid subjectId, int likesQuantity); 60 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Notifications/ArticleEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Blog.Notifications; 5 | 6 | public class ArticleEntry : EntityDto 7 | { 8 | public string Title { get; set; } 9 | 10 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Notifications/CommentEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Blog.Notifications; 5 | 6 | public class CommentEntry : EntityDto 7 | { 8 | public Guid? RespId { get; set; } 9 | public string Text { get; set; } 10 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Notifications/CreateNotificationDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LinCms.Entities.Blog; 3 | 4 | namespace LinCms.Blog.Notifications; 5 | 6 | public class CreateNotificationDto 7 | { 8 | public const string CreateOrCancelAsync = "CreateNotificationDto.CreateOrCancelAsync"; 9 | public NotificationType NotificationType { get; set; } 10 | public Guid? ArticleId { get; set; } 11 | public Guid? CommentId { get; set; } 12 | public long NotificationRespUserId { get; set; } 13 | public long UserInfoId { get; set; } 14 | 15 | public bool IsCancel { get; set; } 16 | public DateTime CreateTime { get; set; } 17 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Notifications/IEventService.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Blog.Notifications; 2 | 3 | public interface IEventService 4 | { 5 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Notifications/INotificationService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.Dto; 4 | 5 | namespace LinCms.Blog.Notifications; 6 | 7 | /// 8 | /// 消息通知 9 | /// 10 | public interface INotificationService 11 | { 12 | Task> GetListAsync(NotificationSearchDto pageDto); 13 | 14 | /// 15 | /// 新增一个消息通知,或取消消息通知 16 | /// 17 | /// 18 | Task CreateOrCancelAsync(CreateNotificationDto createNotificationDto); 19 | 20 | /// 21 | /// 设置消息通知为已读状态 22 | /// 23 | /// 24 | Task SetNotificationReadAsync(Guid id); 25 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Notifications/NotificationDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | using LinCms.Cms.Users; 4 | using LinCms.Entities.Blog; 5 | 6 | namespace LinCms.Blog.Notifications; 7 | 8 | public class NotificationDto : EntityDto 9 | { 10 | public NotificationType NotificationType { get; set; } 11 | public OpenUserDto UserInfo { get; set; } 12 | public bool IsRead { get; set; } 13 | public long UserInfoId { get; set; } 14 | public long MessageRespUserId { get; set; } 15 | public DateTime CreateTime { get; set; } 16 | public ArticleEntry ArticleEntry { get; set; } 17 | public CommentEntry CommentEntry { get; set; } 18 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Notifications/NotificationSearchDto.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Data; 2 | 3 | namespace LinCms.Blog.Notifications; 4 | 5 | public class NotificationSearchDto : PageDto 6 | { 7 | public NotificationSearchType? NotificationSearchType { get; set; } 8 | } 9 | 10 | public enum NotificationSearchType 11 | { 12 | /// 13 | /// 用户点赞随笔、点赞评论 14 | /// 15 | UserLike = 0, 16 | /// 17 | /// 用户评论随笔、回复别人的评论 18 | /// 19 | UserComment = 1, 20 | /// 21 | /// 用户关注用户 22 | /// 23 | UserLikeUser = 2 24 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Tags/CreateUpdateTagDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Blog.Tags; 4 | 5 | public class CreateUpdateTagDto 6 | { 7 | [Required(ErrorMessage = "请上传标签封面")] 8 | public string Thumbnail { get; set; } 9 | [Required(ErrorMessage = "标签为必填项")] 10 | public string TagName { get; set; } 11 | 12 | public string Remark { get; set; } 13 | 14 | /// 15 | /// 别名 16 | /// 17 | [MaxLength(300, ErrorMessage = "请少于300个字符")] 18 | public string Alias { get; set; } 19 | 20 | public bool Status { get; set; } 21 | 22 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Tags/IUserTagService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace LinCms.Blog.Tags; 5 | 6 | public interface IUserTagService 7 | { 8 | /// 9 | /// 用户关注标签 10 | /// 11 | /// 12 | Task CreateUserTagAsync(Guid tagId); 13 | 14 | /// 15 | /// 当前用户取消关注标签 16 | /// 17 | /// 18 | /// 19 | Task DeleteUserTagAsync(Guid tagId); 20 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Tags/TagDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Blog.Tags; 5 | 6 | public class TagDto : EntityDto 7 | { 8 | public TagDto(Guid id, string tagName) 9 | { 10 | Id = id; 11 | TagName = tagName; 12 | } 13 | 14 | public string TagName { get; set; } 15 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Tags/TagListDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Blog.Tags; 5 | 6 | /// 7 | /// 后台列表List 8 | /// 9 | public class TagListDto : EntityDto 10 | { 11 | public string Thumbnail { get; set; } 12 | public string ThumbnailDisplay { get; set; } 13 | public string TagName { get; set; } 14 | public long CreateUserId { get; set; } 15 | public DateTime? CreateTime { get; set; } 16 | public string Alias { get; set; } 17 | public int ArticleCount { get; set; } 18 | public int SubscribersCount { get; set; } 19 | public int ViewHits { get; set; } 20 | public bool Status { get; set; } 21 | public bool IsSubscribe { get; set; } 22 | public string Remark { get; set; } 23 | 24 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Tags/TagSearchDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using LinCms.Data; 4 | 5 | namespace LinCms.Blog.Tags; 6 | 7 | public class TagSearchDto : PageDto 8 | { 9 | public List TagIds { get; set; } 10 | public string TagName { get; set; } 11 | 12 | public bool? Status { get; set; } 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/Tags/UserTagDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Blog.Tags; 4 | 5 | public class UserTagDto 6 | { 7 | public Guid TagId { get; set; } 8 | public long CreateUserId { get; set; } 9 | public bool IsSubscribeed { get; set; } 10 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/UserLikes/CreateUpdateUserLikeDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LinCms.Entities.Blog; 3 | 4 | namespace LinCms.Blog.UserLikes; 5 | 6 | public class CreateUpdateUserLikeDto 7 | { 8 | public Guid SubjectId { get; set; } 9 | /// 10 | /// 1.随笔 2 评论 11 | /// 12 | public UserLikeSubjectType SubjectType { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/UserLikes/IUserLikeService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace LinCms.Blog.UserLikes; 4 | 5 | /// 6 | /// 用户点赞 7 | /// 8 | public interface IUserLikeService 9 | { 10 | /// 11 | /// 点赞/取消点赞随笔、评论 12 | /// 13 | /// 14 | /// 15 | Task CreateOrCancelAsync(CreateUpdateUserLikeDto createUpdateUserLike); 16 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/UserSubscribes/IUserSubscribeService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.Dto; 4 | 5 | namespace LinCms.Blog.UserSubscribes; 6 | 7 | /// 8 | /// 用户关注(订阅)服务接口 9 | /// 10 | public interface IUserSubscribeService 11 | { 12 | /// 13 | /// 得到某用户的关注的用户Id 14 | /// 15 | /// 16 | /// 17 | Task> GetSubscribeUserIdAsync(long userId); 18 | 19 | /// 20 | /// 得到某个用户的关注 21 | /// 22 | /// 23 | /// 24 | PagedResultDto GetUserSubscribeeeList(UserSubscribeSearchDto searchDto); 25 | 26 | /// 27 | /// 获取某个用户的粉丝 28 | /// 29 | /// 30 | /// 31 | PagedResultDto GetUserFansList(UserSubscribeSearchDto searchDto); 32 | 33 | /// 34 | /// 关注用户 35 | /// 36 | /// 37 | /// 38 | Task CreateAsync(long subscribeUserId); 39 | 40 | /// 41 | /// 取消关注 42 | /// 43 | /// 44 | /// 45 | Task DeleteAsync(long subscribeUserId); 46 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/UserSubscribes/SubscribeCountDto.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Blog.UserSubscribes; 2 | 3 | public class SubscribeCountDto 4 | { 5 | public long SubscribeCount { get; set; } 6 | public long FansCount { get; set; } 7 | 8 | public long TagCount { get; set; } 9 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/UserSubscribes/UserSubscribeDto.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Cms.Users; 2 | 3 | namespace LinCms.Blog.UserSubscribes; 4 | 5 | public class UserSubscribeDto 6 | { 7 | /// 8 | /// 被关注的用户Id 9 | /// 10 | public long SubscribeUserId { get; set; } 11 | /// 12 | /// 关注的用户Id 13 | /// 14 | public long CreateUserId { get; set; } 15 | 16 | /// 17 | /// 关注者 18 | /// 19 | public OpenUserDto Subscribeer { get; set; } 20 | 21 | public bool IsSubscribeed { get; set; } 22 | 23 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Blog/UserSubscribes/UserSubscribeSearchDto.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Data; 2 | 3 | namespace LinCms.Blog.UserSubscribes; 4 | 5 | public class UserSubscribeSearchDto : PageDto 6 | { 7 | public long UserId { get; set; } 8 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Account/IAccountService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using LinCms.Cms.Users; 4 | 5 | namespace LinCms.Cms.Account; 6 | 7 | /// 8 | /// 账号服务 9 | /// 10 | public interface IAccountService 11 | { 12 | 13 | /// 14 | /// 生成无状态的登录验证码 15 | /// 16 | /// 17 | LoginCaptchaDto GenerateCaptcha(); 18 | 19 | /// 20 | /// 校验登录验证码 21 | /// 22 | /// 23 | /// 24 | /// 25 | bool VerifyCaptcha(String captcha, String tag); 26 | 27 | /// 28 | /// 注册前先发送邮件才能正常注册 29 | /// 30 | /// 31 | /// 32 | Task SendEmailCodeAsync(RegisterEmailCodeInput registerDto); 33 | 34 | /// 35 | /// 发送邮件:重置密码的验证码 36 | /// 37 | /// 38 | /// 39 | Task SendPasswordResetCodeAsync(SendEmailCodeInput sendEmailCode); 40 | 41 | /// 42 | /// 重置密码:根据邮件验证码 43 | /// 44 | /// 45 | /// 46 | 47 | Task ResetPasswordAsync(ResetEmailPasswordDto resetPassword); 48 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Account/ITokenService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using IGeekFan.FreeKit.Extras.Security; 3 | 4 | namespace LinCms.Cms.Account; 5 | 6 | /// 7 | /// Token维护 8 | /// 9 | public interface ITokenService 10 | { 11 | /// 12 | /// 登录 13 | /// 14 | /// 15 | /// 16 | Task LoginAsync(LoginInputDto loginInputDto); 17 | 18 | /// 19 | /// 刷新token 20 | /// 21 | /// 22 | /// 23 | Task GetRefreshTokenAsync(string refreshToken); 24 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Account/LoginCaptchaDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Cms.Account 4 | { 5 | public class LoginCaptchaDto 6 | { 7 | public LoginCaptchaDto() 8 | { 9 | } 10 | 11 | public LoginCaptchaDto(string tag, string image) 12 | { 13 | Tag = tag ?? throw new ArgumentNullException(nameof(tag)); 14 | Image = image ?? throw new ArgumentNullException(nameof(image)); 15 | } 16 | 17 | /// 18 | /// 验证码图片地址,可使用base64 19 | /// 20 | public string Tag { get; set; } 21 | /// 22 | /// 加密后的验证码 23 | /// 24 | public string Image { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Account/LoginInputDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using JetBrains.Annotations; 4 | 5 | namespace LinCms.Cms.Account; 6 | 7 | public class LoginInputDto 8 | { 9 | /// 10 | /// 登录名:admin 11 | /// 12 | [Required(ErrorMessage = "登录名为必填项")] 13 | [DefaultValue("admin")] 14 | public string Username { get; set; } 15 | /// 16 | /// 密码:123qwe 17 | /// 18 | [Required(ErrorMessage = "密码为必填项")] 19 | [DefaultValue("123qwe")] 20 | public string Password { get; set; } 21 | 22 | /// 23 | /// 验证码 24 | /// 25 | [CanBeNull] 26 | public string Captcha { get; set; } 27 | 28 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Account/ResetEmailPasswordDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Cms.Account; 4 | 5 | public class ResetEmailPasswordDto 6 | { 7 | [Required(ErrorMessage = "非法请求")] 8 | public string Email { get; set; } 9 | [Required(ErrorMessage = "非法请求")] 10 | public string PasswordResetCode { get; set; } 11 | 12 | [Required(ErrorMessage = "请输入验证码")] 13 | public string ResetCode { get; set; } 14 | [Required(ErrorMessage = "请输入你的新密码")] 15 | [RegularExpression(AccountContract.PasswordRegex, ErrorMessage = AccountContract.PasswordErrorMessage)] 16 | public string Password { get; set; } 17 | } 18 | 19 | public class AccountContract 20 | { 21 | public const string PasswordRegex = "^(?![a-zA-Z]+$)(?!\\d+$)(?![^\\da-zA-Z\\s]+$).{6,20}$"; 22 | public const string PasswordErrorMessage = "密码由字母、数字、特殊字符,任意2种组成,长度在6-20个字符之间"; 23 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Account/SendEmailCodeInput.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.Net.Mail; 4 | 5 | namespace LinCms.Cms.Account; 6 | 7 | public class SendEmailCodeInput : IValidatableObject 8 | { 9 | [Required(ErrorMessage = "请输入邮件")] 10 | public string Email { get; set; } 11 | 12 | public IEnumerable Validate(ValidationContext validationContext) 13 | { 14 | if (!Email.IsNullOrEmpty()) 15 | { 16 | 17 | string address = null; 18 | try 19 | { 20 | address = new MailAddress(Email).Address; 21 | } 22 | catch 23 | { 24 | // ignored 25 | } 26 | 27 | if (address.IsNullOrEmpty()) 28 | { 29 | yield return new ValidationResult("电子邮箱不符合规范,请输入正确的邮箱", new[] { "Email" }); 30 | } 31 | 32 | } 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Admins/ResetPasswordDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Cms.Admins; 4 | 5 | public class ResetPasswordDto 6 | { 7 | [Required(ErrorMessage = "新密码不可为空")] 8 | [Compare("ConfirmPassword", ErrorMessage = "两次输入的密码不一致,请输入相同的密码")] 9 | //密码规则太麻烦, 记不住 10 | //[RegularExpression(@"^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{8,24}", ErrorMessage = "密码长度必须在8~24位之间,包含字母、数字、特殊字符")] 11 | [RegularExpression(@"^(?![a-zA-Z]+$)(?!\d+$)(?![^\da-zA-Z\s]+$).{6,16}$", ErrorMessage = "密码长度必须在6~16位之间,包含字母、数字、特殊字符中的二种")] 12 | public string NewPassword { get; set; } 13 | [Required(ErrorMessage = "请确认密码")] 14 | public string ConfirmPassword { get; set; } 15 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Admins/UpdateUserDto.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using LinCms.Data.Enums; 3 | 4 | namespace LinCms.Cms.Admins; 5 | 6 | public class UpdateUserDto 7 | { 8 | public string Email { get; set; } 9 | public string Nickname { get; set; } 10 | public string Username { get; set; } 11 | public UserStatus Active { get; set; } 12 | public List GroupIds { get; set; } 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Admins/UserSearchDto.cs: -------------------------------------------------------------------------------- 1 | using JetBrains.Annotations; 2 | using LinCms.Data; 3 | 4 | namespace LinCms.Cms.Admins; 5 | 6 | public class UserSearchDto : PageDto 7 | { 8 | public int? GroupId { get; set; } 9 | 10 | [CanBeNull] public string Email { get; set; } 11 | [CanBeNull] public string Nickname { get; set; } 12 | [CanBeNull] public string Username { get; set; } 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Files/FileDto.cs: -------------------------------------------------------------------------------- 1 | using IGeekFan.FreeKit.Extras.AuditEntity; 2 | 3 | namespace LinCms.Cms.Files; 4 | 5 | public class FileDto : Entity 6 | { 7 | public string Key { get; set; } 8 | public string Path { get; set; } 9 | public string Url { get; set; } 10 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Files/IFileService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.AspNetCore.Http; 3 | 4 | namespace LinCms.Cms.Files; 5 | 6 | /// 7 | /// 文件服务 8 | /// 9 | public interface IFileService 10 | { 11 | /// 12 | /// 单文件上传,键为file 13 | /// 14 | /// 15 | /// 16 | /// 17 | Task UploadAsync(IFormFile file, int key = 0); 18 | 19 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Groups/CreateGroupDto.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Data; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace LinCms.Cms.Groups; 6 | 7 | public class CreateGroupDto : UpdateGroupDto, IValidatableObject 8 | { 9 | public List PermissionIds { get; set; } 10 | 11 | public IEnumerable Validate(ValidationContext validationContext) 12 | { 13 | if (PermissionIds.Count == 0) 14 | { 15 | yield return new ValidationResult("请选择权限", new List { "PermissionIds" }); 16 | } 17 | } 18 | } 19 | 20 | public class GroupQuery:PageDto 21 | { 22 | public string Name { get; set; } 23 | 24 | /// 25 | /// 权限组描述 26 | /// 27 | public string Info { get; set; } 28 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Groups/GroupDto.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | using LinCms.Entities; 4 | 5 | namespace LinCms.Cms.Groups; 6 | 7 | public class GroupDto : Entity 8 | { 9 | public List Permissions { get; set; } 10 | public string Name { get; set; } 11 | public string Info { get; set; } 12 | public bool IsStatic { get; set; } 13 | 14 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Groups/IGroupService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.Dto; 4 | using LinCms.Entities; 5 | 6 | namespace LinCms.Cms.Groups; 7 | 8 | public interface IGroupService 9 | { 10 | Task> GetListAsync(GroupQuery query); 11 | 12 | Task GetAsync(long id); 13 | 14 | Task CreateAsync(CreateGroupDto inputDto); 15 | 16 | Task UpdateAsync(long id, UpdateGroupDto inputDto); 17 | 18 | /// 19 | /// 管理员删除一个权限分组 20 | /// 21 | /// 22 | /// 23 | Task DeleteAsync(long id); 24 | 25 | /// 26 | /// 根据用户Id删除用户分组 27 | /// 28 | /// 29 | /// 30 | Task DeleteUserGroupAsync(long userId); 31 | 32 | /// 33 | /// 检查该用户是否在root分组中 34 | /// 35 | /// 36 | /// 37 | bool CheckIsRootByUserId(long userId); 38 | 39 | /// 40 | /// 根据用户Id得到获得用户的所有分组id 41 | /// 42 | /// 43 | /// 44 | Task> GetGroupIdsByUserIdAsync(long userId); 45 | 46 | /// 47 | /// 删除用户与分组直接的关联 48 | /// 49 | /// 用户Id 50 | /// 删除的分组Id 51 | /// 52 | Task DeleteUserGroupAsync(long userId, List deleteGroupIds); 53 | 54 | /// 55 | /// 添加用户与分组直接的关联 56 | /// 57 | /// 用户Id 58 | /// 要新增的分组Id 59 | /// 60 | Task AddUserGroupAsync(long userId, List addGroupIds); 61 | 62 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Groups/UpdateGroupDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Cms.Groups; 4 | 5 | public class UpdateGroupDto 6 | { 7 | [Required(ErrorMessage = "请输入分组名称")] 8 | public string Name { get; set; } 9 | public string Info { get; set; } 10 | public int SortCode { get; set; } 11 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Logs/ILogService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.Dto; 4 | using LinCms.Data; 5 | using LinCms.Entities; 6 | 7 | namespace LinCms.Cms.Logs; 8 | 9 | public interface ILogService 10 | { 11 | Task CreateAsync(LinLog linlog); 12 | PagedResultDto GetUserLogs(LogSearchDto searchDto); 13 | 14 | List GetLoggedUsers(PageDto searchDto); 15 | 16 | /// 17 | /// 管理端访问与用户统计 18 | /// 19 | /// 20 | VisitLogUserDto GetUserAndVisits(); 21 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Logs/ISerilogService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using IGeekFan.FreeKit.Extras.Dto; 3 | using LinCms.Entities; 4 | 5 | namespace LinCms.Cms.Logs; 6 | 7 | public interface ISerilogService 8 | { 9 | Task GetLogDashboard(); 10 | Task> GetListAsync(SerilogSearchDto searchDto); 11 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Logs/LogDashboard.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Cms.Logs; 2 | 3 | public class LogDashboard 4 | { 5 | public long TodayCount { get; set; } 6 | public long HourCount { get; set; } 7 | public long AllCount { get; set; } 8 | public long UniqueCount { get; set; } 9 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Logs/LogDto.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Cms.Logs; 2 | 3 | public class LogDto 4 | { 5 | /// 6 | /// 访问哪个权限 7 | /// 8 | public string Authority { get; set; } 9 | 10 | /// 11 | /// 日志信息 12 | /// 13 | public string Message { get; set; } 14 | 15 | /// 16 | /// 请求方法 17 | /// 18 | public string Method { get; set; } 19 | 20 | /// 21 | /// 请求路径 22 | /// 23 | public string Path { get; set; } 24 | 25 | /// 26 | /// 请求的http返回码 27 | /// 28 | public int? StatusCode { get; set; } 29 | 30 | /// 31 | /// 用户id 32 | /// 33 | public long UserId { get; set; } 34 | 35 | /// 36 | /// 用户当时的昵称 37 | /// 38 | public string Username { get; set; } 39 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Logs/LogSearchDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LinCms.Data; 3 | 4 | namespace LinCms.Cms.Logs; 5 | 6 | public class LogSearchDto : PageDto 7 | { 8 | public string Keyword { get; set; } 9 | /// 10 | /// 用户昵称 11 | /// 12 | public string Name { get; set; } 13 | /// 14 | /// 起始时间 15 | /// 16 | public DateTime? Start { get; set; } 17 | /// 18 | /// 结束时间 19 | /// 20 | public DateTime? End { get; set; } 21 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Logs/SerilogSearchDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LinCms.Data; 3 | 4 | namespace LinCms.Cms.Logs; 5 | 6 | public class SerilogSearchDto : PageDto 7 | { 8 | public string Keyword { get; set; } 9 | public int? LogLevel { get; set; } 10 | /// 11 | /// 起始时间 12 | /// 13 | public DateTime? Start { get; set; } 14 | /// 15 | /// 结束时间 16 | /// 17 | public DateTime? End { get; set; } 18 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Logs/VisitLogUserDto.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Cms.Logs; 2 | 3 | public class VisitLogUserDto 4 | { 5 | /// 6 | /// 总访问量 7 | /// 8 | public long TotalVisitsCount { get; set; } 9 | /// 10 | /// 总用户数 11 | /// 12 | public long TotalUserCount { get; set; } 13 | /// 14 | /// 新增访问量 (月) 15 | /// 16 | public long MonthVisitsCount { get; set; } 17 | 18 | /// 19 | /// 新增用户数(月) 20 | /// 21 | public long MonthUserCount { get; set; } 22 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Permissions/DispatchPermissionsDto.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace LinCms.Cms.Permissions; 5 | 6 | public class DispatchPermissionsDto : IValidatableObject 7 | { 8 | public long GroupId { get; set; } 9 | public List PermissionIds { get; set; } 10 | public IEnumerable Validate(ValidationContext validationContext) 11 | { 12 | if (GroupId <= 0) 13 | { 14 | yield return new ValidationResult("分组id必须大于0", new List() { "GroupId" }); 15 | } 16 | if (PermissionIds.Count == 0) 17 | { 18 | yield return new ValidationResult("请输入PermissionIds字段", new List() { "Permission" }); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Permissions/IPermissionService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using LinCms.Data; 4 | using LinCms.Entities; 5 | 6 | namespace LinCms.Cms.Permissions; 7 | 8 | public interface IPermissionService 9 | { 10 | Task> GetPermissionTreeNodes(); 11 | Task CheckPermissionAsync(string permission); 12 | Task DeletePermissionsAsync(RemovePermissionDto permissionDto); 13 | 14 | Task DispatchPermissions(DispatchPermissionsDto permissionDto, List permissionDefinition); 15 | 16 | Task> GetPermissionByGroupIds(List groupIds); 17 | 18 | List> StructuringPermissions(List permissions); 19 | 20 | Task UpdateAsync(int id,PermissioCreateUpdateDto createUpdateDto); 21 | Task CreateAsync(PermissioCreateUpdateDto createUpdateDto); 22 | 23 | Task DeleteAsync(int id); 24 | 25 | Task GetAsync(string permissionName); 26 | 27 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Permissions/PermissioCreateUpdateDto.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Entities; 2 | 3 | namespace LinCms.Cms.Permissions; 4 | 5 | public class PermissioCreateUpdateDto 6 | { 7 | 8 | public PermissionType PermissionType { get; set; } 9 | 10 | /// 11 | /// 父级Id 12 | /// 13 | public long ParentId { get; set; } 14 | 15 | /// 16 | /// 所属权限、权限名称,例如:访问首页 17 | /// 18 | public string Name { get; set; } 19 | 20 | /// 21 | /// 后台路由 22 | /// 23 | public string Router { get; set; } 24 | 25 | /// 26 | /// 排序 27 | /// 28 | public int SortCode { get; set; } 29 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Permissions/PermissionDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | using LinCms.Entities; 5 | 6 | namespace LinCms.Cms.Permissions; 7 | 8 | public class PermissionDto : EntityDto 9 | { 10 | /// 11 | /// 父级Id 12 | /// 13 | public long ParentId { get; set; } 14 | public string Name { get; set; } 15 | 16 | public PermissionType PermissionType { get; set; } 17 | 18 | public string Router { get; set; } 19 | 20 | } 21 | 22 | public class PermissionTreeNode : TreeNode 23 | { 24 | public int SortCode { get; set; } 25 | public string Router { get; set; } 26 | public PermissionType PermissionType { get; set; } 27 | public DateTime? CreateTime { get; set; } 28 | public List Children { get; set; } 29 | 30 | public PermissionTreeNode() 31 | { 32 | Children = new List(); 33 | } 34 | 35 | } 36 | 37 | public class TreeNode 38 | { 39 | public long Id { get; set; } 40 | public long ParentId { get; set; } 41 | public string Name { get; set; } 42 | public List Children { get; set; } 43 | 44 | public TreeNode() 45 | { 46 | Children = new List(); 47 | } 48 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Permissions/RemovePermissionDto.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace LinCms.Cms.Permissions; 5 | 6 | public class RemovePermissionDto : IValidatableObject 7 | { 8 | public long GroupId { get; set; } 9 | public List PermissionIds { get; set; } 10 | public IEnumerable Validate(ValidationContext validationContext) 11 | { 12 | if (GroupId <= 0) 13 | { 14 | yield return new ValidationResult("分组id必须大于0", new List() { "GroupId" }); 15 | } 16 | if (PermissionIds.Count == 0) 17 | { 18 | yield return new ValidationResult("请输入Permission字段", new List() { "Permission" }); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Settings/CreateUpdateSettingDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Cms.Settings; 4 | 5 | public class CreateUpdateSettingDto 6 | { 7 | /// 8 | /// 键 9 | /// 10 | [StringLength(128)] 11 | public string Name { get; set; } 12 | 13 | /// 14 | /// 值 15 | /// 16 | [StringLength(2048)] 17 | public string Value { get; set; } 18 | 19 | /// 20 | /// 提供者键 21 | /// 22 | [StringLength(64)] 23 | public string ProviderName { get; set; } 24 | 25 | /// 26 | /// 提供者值 27 | /// 28 | [StringLength(64)] 29 | public string ProviderKey { get; set; } 30 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Settings/ISettingService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using IGeekFan.FreeKit.Extras.Dto; 5 | using LinCms.Data; 6 | 7 | namespace LinCms.Cms.Settings; 8 | 9 | /// 10 | /// 通用配置项 11 | /// 12 | public interface ISettingService 13 | { 14 | Task> GetPagedListAsync(PageDto pageDto); 15 | 16 | Task GetAsync(Guid id); 17 | 18 | Task Delete(string name, string providerName, string providerKey); 19 | 20 | Task> GetListAsync(string providerName, string providerKey); 21 | 22 | Task GetOrNullAsync(string name, string providerName, string providerKey); 23 | 24 | /// 25 | /// 用户设置自己的一些配置 26 | /// 27 | /// 28 | /// 29 | Task SetAsync(CreateUpdateSettingDto createSetting); 30 | 31 | Task CreateAsync(CreateUpdateSettingDto createSettingDto); 32 | 33 | Task UpdateAsync(Guid id, CreateUpdateSettingDto updateSettingDto); 34 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Settings/SettingDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Cms.Settings; 5 | 6 | public class SettingDto : EntityDto 7 | { 8 | /// 9 | /// 键 10 | /// 11 | public string Name { get; set; } 12 | /// 13 | /// 值 14 | /// 15 | public string Value { get; set; } 16 | /// 17 | /// 提供者键 18 | /// 19 | public string ProviderName { get; set; } 20 | /// 21 | /// 提供者值 22 | /// 23 | public string ProviderKey { get; set; } 24 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/ChangePasswordDto.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Cms.Admins; 2 | 3 | namespace LinCms.Cms.Users; 4 | 5 | public class ChangePasswordDto : ResetPasswordDto 6 | { 7 | 8 | // [Required(ErrorMessage = "原密码不可为空")] 9 | public string OldPassword { get; set; } 10 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/IOAuth2Service.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | using System.Threading.Tasks; 3 | using LinCms.Data; 4 | 5 | namespace LinCms.Cms.Users; 6 | 7 | /// 8 | /// OAuath2.0登录绑定授权 9 | /// 10 | public interface IOAuth2Service 11 | { 12 | /// 13 | /// 第三方登录后,自动注册用户信息 14 | /// 15 | /// 16 | /// 17 | /// 18 | Task SaveUserAsync(ClaimsPrincipal principal, string openId); 19 | 20 | /// 21 | /// 用户账号绑定第三方账号 22 | /// 23 | /// 24 | /// 25 | /// 26 | /// 27 | /// 28 | Task BindAsync(ClaimsPrincipal principal, string identityType, string openId, long userId); 29 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/OAuthService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Claims; 3 | using System.Threading.Tasks; 4 | using IGeekFan.FreeKit.Extras.FreeSql; 5 | using LinCms.Data; 6 | using LinCms.Entities; 7 | 8 | namespace LinCms.Cms.Users; 9 | 10 | public abstract class OAuthService : IOAuth2Service 11 | { 12 | private readonly IAuditBaseRepository _userIdentityRepository; 13 | 14 | public OAuthService(IAuditBaseRepository userIdentityRepository) 15 | { 16 | _userIdentityRepository = userIdentityRepository; 17 | } 18 | private async Task BindAsync(string identityType, string name, string openId, long userId) 19 | { 20 | LinUserIdentity linUserIdentity = await _userIdentityRepository.Where(r => r.IdentityType == identityType && r.Credential == openId).FirstAsync(); 21 | if (linUserIdentity == null) 22 | { 23 | var userIdentity = new LinUserIdentity(identityType, name, openId, DateTime.Now) 24 | { 25 | CreateUserId = userId 26 | }; 27 | await _userIdentityRepository.InsertAsync(userIdentity); 28 | return UnifyResponseDto.Success("绑定成功"); 29 | } 30 | else 31 | { 32 | return UnifyResponseDto.Error("绑定失败,该用户已绑定其他账号"); 33 | } 34 | } 35 | 36 | public abstract Task SaveUserAsync(ClaimsPrincipal principal, string openId); 37 | 38 | public virtual async Task BindAsync(ClaimsPrincipal principal, string identityType, string openId, long userId) 39 | { 40 | string nickname = principal.FindFirst(ClaimTypes.Name)?.Value; 41 | return await BindAsync(identityType, nickname, openId, userId); 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/OpenUserDto.cs: -------------------------------------------------------------------------------- 1 | using IGeekFan.FreeKit.Extras.AuditEntity; 2 | 3 | namespace LinCms.Cms.Users; 4 | 5 | public class OpenUserDto : EntityDto 6 | { 7 | public OpenUserDto(string nickname) 8 | { 9 | Nickname = nickname; 10 | } 11 | 12 | public OpenUserDto() 13 | { 14 | } 15 | 16 | public string Introduction { get; set; } 17 | public string Username { get; set; } 18 | public string Nickname { get; set; } 19 | public string Avatar { get; set; } 20 | public string BlogAddress { get; set; } 21 | public string JobTitle { get; set; } 22 | public string Company { get; set; } 23 | 24 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/UpdateAvatarDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Cms.Users; 4 | 5 | public class UpdateAvatarDto 6 | { 7 | [Required(ErrorMessage = "请输入头像url")] 8 | public string Avatar { get; set; } 9 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/UpdateNickNameDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Cms.Users; 4 | 5 | public class UpdateNicknameDto 6 | { 7 | [Required(ErrorMessage = "请输入昵称")] 8 | [StringLength(24, ErrorMessage = "昵称应在24个字符内")] 9 | public string Nickname { get; set; } 10 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/UpdateProfileDto.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace LinCms.Cms.Users; 4 | 5 | public class UpdateProfileDto 6 | { 7 | [Required(ErrorMessage = "请输入昵称")] 8 | [StringLength(24, ErrorMessage = "昵称应在24个字符内")] 9 | 10 | public string Nickname { get; set; } 11 | [StringLength(100, ErrorMessage = "个人介绍应在100个字符内")] 12 | 13 | public string Introduction { get; set; } 14 | 15 | [StringLength(100, ErrorMessage = "博客应在100个字符内")] 16 | public string BlogAddress { get; set; } 17 | 18 | /// 19 | /// 职位 20 | /// 21 | [StringLength(50, ErrorMessage = "职位应在50个字符内")] 22 | public string JobTitle { get; set; } 23 | 24 | /// 25 | /// 公司 26 | /// 27 | [StringLength(50, ErrorMessage = "公司应在50个字符内")] 28 | public string Company { get; set; } 29 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/UserDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | using LinCms.Cms.Groups; 5 | 6 | namespace LinCms.Cms.Users; 7 | 8 | public class UserDto : EntityDto 9 | { 10 | public string Username { get; set; } 11 | public string Nickname { get; set; } 12 | public string Avatar { get; set; } 13 | public string Email { get; set; } 14 | public int Admin { get; set; } = 1; 15 | public int Active { get; set; } 16 | public List Groups { get; set; } 17 | public DateTime CreateTime { get; set; } 18 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/UserIdentityDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Cms.Users; 5 | 6 | public class UserIdentityDto : EntityDto 7 | { 8 | public string IdentityType { get; set; } 9 | 10 | public string Identifier { get; set; } 11 | 12 | public string ExtraProperties { get; set; } 13 | 14 | public DateTime CreateTime { get; set; } 15 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/UserInformation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | using LinCms.Cms.Groups; 5 | using LinCms.Data.Enums; 6 | 7 | namespace LinCms.Cms.Users; 8 | 9 | public class UserInformation : EntityDto 10 | { 11 | /// 12 | /// 昵称 13 | /// 14 | public string Nickname { get; set; } 15 | /// 16 | /// 用户默认生成图像,为null、头像url 17 | /// 18 | public string Avatar { get; set; } 19 | /// 20 | /// 电子邮箱 21 | /// 22 | public string Email { get; set; } 23 | /// 24 | /// 是否为超级管理员 25 | /// 26 | public bool Admin { get; set; } = false; 27 | /// 28 | /// 当前用户是否为激活状态,非激活状态默认失去用户权限 ; 1 -> 激活 | 2 -> 非激活 29 | /// 30 | public UserStatus Active { get; set; } 31 | /// 32 | /// 用户所属的权限组id 33 | /// 34 | public List Groups { get; set; } 35 | 36 | public string Introduction { get; set; } 37 | public string BlogAddress { get; set; } 38 | public string Username { get; set; } 39 | public DateTime UpdateTime { get; set; } 40 | public DateTime CreateTime { get; set; } 41 | 42 | public List> Permissions { get; set; } 43 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/Cms/Users/UserNoviceDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Cms.Users; 5 | 6 | public class UserNoviceDto : EntityDto 7 | { 8 | public string Introduction { get; set; } 9 | public string Username { get; set; } 10 | public string Nickname { get; set; } 11 | public string Avatar { get; set; } 12 | public DateTime CreateTime { get; set; } 13 | public DateTime LastLoginTime { get; set; } 14 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/IApplicationService.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms; 2 | 3 | public interface IApplicationService 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/ICrudAppService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | using IGeekFan.FreeKit.Extras.Dto; 5 | 6 | namespace LinCms; 7 | 8 | public interface ICrudAppService 9 | where TGetOutputDto : IEntityDto 10 | where TKey : IEquatable 11 | where TGetListOutputDto : class, IEntityDto 12 | { 13 | Task> GetListAsync(TGetListInput input); 14 | 15 | Task GetAsync(TKey id); 16 | 17 | Task CreateAsync(TCreateInput createInput); 18 | 19 | Task UpdateAsync(TKey id, TUpdateInput updateInput); 20 | 21 | Task DeleteAsync(TKey id); 22 | } -------------------------------------------------------------------------------- /src/LinCms.Application.Contracts/LinCms.Application.Contracts.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | LinCms.Application.Contracts 6 | LinCms 7 | 8 | 9 | 10 | LinCms.Application.Contracts.xml 11 | bin\Debug 12 | 1701;1702;1591 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Never 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/LinCms.Application/Base/BaseItems/BaseItemProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities.Base; 3 | 4 | namespace LinCms.Base.BaseItems; 5 | 6 | public class BaseItemProfile : Profile 7 | { 8 | public BaseItemProfile() 9 | { 10 | CreateMap(); 11 | CreateMap(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Base/BaseTypes/BaseTypeProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities.Base; 3 | 4 | namespace LinCms.Base.BaseTypes; 5 | 6 | public class BaseTypeProfile : Profile 7 | { 8 | public BaseTypeProfile() 9 | { 10 | CreateMap(); 11 | CreateMap(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Articles/ArticleDraftService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.FreeSql; 4 | using LinCms.Blog.ArticleDrafts; 5 | using LinCms.Entities.Blog; 6 | using LinCms.Exceptions; 7 | using LinCms.Security; 8 | 9 | namespace LinCms.Blog.Articles; 10 | /// 11 | /// 文章草稿箱 12 | /// 13 | public class ArticleDraftService : ApplicationService, IArticleDraftService 14 | { 15 | private readonly IAuditBaseRepository _articleDraftRepository; 16 | public ArticleDraftService(IAuditBaseRepository articleDraftRepository) 17 | { 18 | _articleDraftRepository = articleDraftRepository; 19 | } 20 | 21 | public async Task GetAsync(Guid id) 22 | { 23 | ArticleDraft articleDraft = await _articleDraftRepository.Where(r => r.Id == id && r.CreateUserId == CurrentUser.FindUserId()).ToOneAsync(); 24 | return Mapper.Map(articleDraft); 25 | } 26 | 27 | public async Task UpdateAsync(Guid id, UpdateArticleDraftDto updateArticleDto) 28 | { 29 | ArticleDraft articleDraft = await _articleDraftRepository.Select.Where(r => r.Id == id).ToOneAsync(); 30 | if (articleDraft != null && articleDraft.CreateUserId != CurrentUser.FindUserId()) 31 | { 32 | throw new LinCmsException("您无权修改他人的随笔"); 33 | } 34 | if (articleDraft == null) 35 | { 36 | articleDraft = new ArticleDraft { Id = id, CreateUserId = CurrentUser.FindUserId() ?? 0, CreateTime = DateTime.Now }; 37 | } 38 | Mapper.Map(updateArticleDto, articleDraft); 39 | await _articleDraftRepository.InsertOrUpdateAsync(articleDraft); 40 | } 41 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Articles/ArticleProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Blog.ArticleDrafts; 3 | using LinCms.Entities.Blog; 4 | 5 | namespace LinCms.Blog.Articles; 6 | 7 | public class ArticleProfile : Profile 8 | { 9 | public ArticleProfile() 10 | { 11 | CreateMap(); 12 | CreateMap(); 13 | CreateMap(); 14 | 15 | CreateMap(); 16 | CreateMap(); 17 | 18 | CreateMap(); 19 | } 20 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/AuthorCenter/AuthorCenterService.cs: -------------------------------------------------------------------------------- 1 | using IGeekFan.FreeKit.Extras.FreeSql; 2 | using LinCms.Entities.Blog; 3 | using LinCms.Security; 4 | using System.Threading.Tasks; 5 | 6 | namespace LinCms.Blog.AuthorCenter 7 | { 8 | /// 9 | /// 创建者中心统计 10 | /// 11 | public class AuthorCenterService(IAuditBaseRepository
articleRepository, 12 | IAuditBaseRepository userLikeRepository) 13 | : ApplicationService, IAuthorCenterService 14 | { 15 | public async Task GetArtcileCardAsync() 16 | { 17 | long? userid = CurrentUser.FindUserId(); 18 | var allArticle = await articleRepository.Select.Where(r => r.CreateUserId == userid.Value).CountAsync(); 19 | var allArticleView = (long) await articleRepository.Select.Where(r => r.CreateUserId == userid.Value) 20 | .SumAsync(r => r.ViewHits); 21 | var allArticleStar = await userLikeRepository.Select.Where(r => 22 | r.CreateUserId == userid.Value && r.SubjectType == UserLikeSubjectType.UserLikeArticle).CountAsync(); 23 | var allArticleComment = (long) await articleRepository.Select.Where(r => r.CreateUserId == userid.Value) 24 | .SumAsync(r => r.CommentQuantity); 25 | var allArticleCollect = (long) await articleRepository.Select.Where(r => r.CreateUserId == userid.Value) 26 | .SumAsync(r => r.CollectQuantity); 27 | 28 | return new ArticleCardDto() 29 | { 30 | AllArticle = allArticle, 31 | AllArticleView = allArticleView, 32 | AllArticleStar = allArticleStar, 33 | AllArticleComment = allArticleComment, 34 | AllArticleCollect = allArticleCollect 35 | }; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Channels/ChannelProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities.Blog; 3 | 4 | namespace LinCms.Blog.Channels; 5 | 6 | public class ChannelProfile : Profile 7 | { 8 | public ChannelProfile() 9 | { 10 | CreateMap(); 11 | CreateMap(); 12 | CreateMap(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Classifies/ClassifyProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Blog.Classifys; 3 | using LinCms.Entities.Blog; 4 | 5 | namespace LinCms.Blog.Classifies; 6 | 7 | public class ClassifyProfile : Profile 8 | { 9 | public ClassifyProfile() 10 | { 11 | CreateMap(); 12 | CreateMap(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Collections/CollectionProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Blog.Collections; 3 | using LinCms.Entities.Blog; 4 | 5 | namespace LinCms.Blog.Comments; 6 | 7 | public class CollectionProfile:Profile 8 | { 9 | public CollectionProfile() 10 | { 11 | CreateMap(); 12 | CreateMap(); 13 | CreateMap(); 14 | } 15 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Comments/CommentProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities.Blog; 3 | 4 | namespace LinCms.Blog.Comments; 5 | 6 | public class CommentProfile : Profile 7 | { 8 | public CommentProfile() 9 | { 10 | CreateMap(); 11 | CreateMap().ForMember(d => d.TopComment, opts => opts.Ignore()); 12 | } 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Notifications/EventService.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Blog.Notifications; 2 | 3 | public class EventService 4 | { 5 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Notifications/NotificationProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities.Blog; 3 | 4 | namespace LinCms.Blog.Notifications; 5 | 6 | public class NotificationProfile : Profile 7 | { 8 | public NotificationProfile() 9 | { 10 | CreateMap(); 11 | CreateMap(); 12 | CreateMap(); 13 | CreateMap(); 14 | } 15 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Tags/TagProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities.Blog; 3 | 4 | namespace LinCms.Blog.Tags; 5 | 6 | public class TagProfile : Profile 7 | { 8 | public TagProfile() 9 | { 10 | CreateMap(); 11 | CreateMap(); 12 | CreateMap(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/Tags/UserTagService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.FreeSql; 4 | using LinCms.Entities.Blog; 5 | using LinCms.Exceptions; 6 | using LinCms.Security; 7 | 8 | namespace LinCms.Blog.Tags; 9 | 10 | public class UserTagService(ITagService tagService, IAuditBaseRepository tagRepository, 11 | IAuditBaseRepository userTagRepository) 12 | : ApplicationService, IUserTagService 13 | { 14 | [Transactional] 15 | public async Task CreateUserTagAsync(Guid tagId) 16 | { 17 | Tag tag = await tagRepository.Select.Where(r => r.Id == tagId).ToOneAsync(); 18 | if (tag == null) 19 | { 20 | throw new LinCmsException("该标签不存在"); 21 | } 22 | 23 | if (!tag.Status) 24 | { 25 | throw new LinCmsException("该标签已被拉黑"); 26 | } 27 | 28 | bool any = await userTagRepository.Select.AnyAsync(r => r.CreateUserId == CurrentUser.FindUserId() && r.TagId == tagId); 29 | if (any) 30 | { 31 | throw new LinCmsException("您已关注该标签"); 32 | } 33 | 34 | UserTag userTag = new() { TagId = tagId }; 35 | await userTagRepository.InsertAsync(userTag); 36 | await tagService.UpdateSubscribersCountAsync(tagId, 1); 37 | } 38 | 39 | [Transactional] 40 | public async Task DeleteUserTagAsync(Guid tagId) 41 | { 42 | bool any = await userTagRepository.Select.AnyAsync(r => r.CreateUserId == CurrentUser.FindUserId() && r.TagId == tagId); 43 | if (!any) 44 | { 45 | throw new LinCmsException("已取消关注"); 46 | } 47 | await userTagRepository.DeleteAsync(r => r.TagId == tagId && r.CreateUserId == CurrentUser.FindUserId()); 48 | await tagService.UpdateSubscribersCountAsync(tagId, -1); 49 | } 50 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/UserLikes/UserLikeProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities.Blog; 3 | 4 | namespace LinCms.Blog.UserLikes; 5 | 6 | public class UserLikeProfile : Profile 7 | { 8 | public UserLikeProfile() 9 | { 10 | CreateMap(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Blog/UserSubscribes/UserSubscribeProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities.Blog; 3 | 4 | namespace LinCms.Blog.UserSubscribes; 5 | 6 | public class UserSubscribeProfile : Profile 7 | { 8 | public UserSubscribeProfile() 9 | { 10 | CreateMap(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Cms/Account/AccountContracts.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Cms.Account; 2 | 3 | public class AccountContracts 4 | { 5 | /// 6 | /// 注册返回的uuid值 7 | /// 8 | public static string SendEmailCode_EmailCode = "AccountService.SendEmailCode.EmailCode.{0}"; 9 | 10 | /// 11 | /// 注册时缓存的邮件验证码 12 | /// 13 | public static string SendEmailCode_VerificationCode = "AccountService.SendEmailCode.VerificationCode.{0}"; 14 | 15 | /// 16 | /// 重置密码时邮件验证码 17 | /// 18 | public static string SendPasswordResetCode_VerificationCode = 19 | "AccountService.SendPasswordResetCode.VerificationCode.{0}"; 20 | 21 | /// 22 | /// 重置密码验证码可使用次数 23 | /// 24 | public static string SendPasswordResetCode_VerificationCode_Count = 25 | "AccountService.SendPasswordResetCode.VerificationCode.{0}.Count"; 26 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Cms/Groups/GroupProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities; 3 | 4 | namespace LinCms.Cms.Groups; 5 | 6 | public class GroupProfile : Profile 7 | { 8 | public GroupProfile() 9 | { 10 | CreateMap(); 11 | CreateMap(); 12 | CreateMap(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Cms/Permissions/PermissionProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities; 3 | 4 | namespace LinCms.Cms.Permissions; 5 | 6 | public class PermissionProfile : Profile 7 | { 8 | public PermissionProfile() 9 | { 10 | CreateMap(); 11 | CreateMap(); 12 | CreateMap(); 13 | CreateMap(); 14 | } 15 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Cms/Permissions/TreeBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace LinCms.Cms.Permissions; 5 | 6 | public record TreeBuilder 7 | { 8 | public List BuildPermissionTree(List nodes) 9 | { 10 | var nodeDict = nodes.ToDictionary(n => n.Id); 11 | List roots = new List(); 12 | 13 | foreach (var node in nodes) 14 | { 15 | if (node.ParentId == 0) // 假定ParentId为0表示根节点 16 | { 17 | roots.Add(node); 18 | } 19 | else 20 | { 21 | if (nodeDict.TryGetValue(node.ParentId, out PermissionTreeNode parentNode)) 22 | { 23 | parentNode.Children.Add(node); 24 | } 25 | } 26 | } 27 | return roots; // 返回森林中所有根节点的列表 28 | } 29 | 30 | public List BuildTree(List nodes) 31 | { 32 | var nodeDict = nodes.ToDictionary(n => n.Id); 33 | List roots = new List(); 34 | 35 | foreach (var node in nodes) 36 | { 37 | if (node.ParentId == 0) // 假定ParentId为0表示根节点 38 | { 39 | roots.Add(node); 40 | } 41 | else 42 | { 43 | if (nodeDict.TryGetValue(node.ParentId, out TreeNode parentNode)) 44 | { 45 | parentNode.Children.Add(node); 46 | } 47 | } 48 | } 49 | return roots; // 返回森林中所有根节点的列表 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/LinCms.Application/Cms/Settings/SettingProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities.Settings; 3 | 4 | namespace LinCms.Cms.Settings; 5 | 6 | public class SettingProfile : Profile 7 | { 8 | public SettingProfile() 9 | { 10 | CreateMap(); 11 | CreateMap(); 12 | } 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Cms/Users/UserIdentityProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Entities; 3 | 4 | namespace LinCms.Cms.Users; 5 | 6 | public class UserIdentityProfile : Profile 7 | { 8 | public UserIdentityProfile() 9 | { 10 | CreateMap(); 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /src/LinCms.Application/Cms/Users/UserProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using LinCms.Cms.Account; 3 | using LinCms.Cms.Admins; 4 | using LinCms.Entities; 5 | 6 | namespace LinCms.Cms.Users; 7 | 8 | public class UserProfile : Profile 9 | { 10 | public UserProfile() 11 | { 12 | CreateMap(); 13 | CreateMap(); 14 | CreateMap(); 15 | CreateMap(); 16 | CreateMap(); 17 | CreateMap(); 18 | CreateMap(); 19 | } 20 | } -------------------------------------------------------------------------------- /src/LinCms.Application/LinCms.Application.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | LinCms.Application 6 | LinCms 7 | True 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/LinCms.Core/Aop/Attributes/CacheableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Aop.Attributes; 4 | 5 | [AttributeUsage(AttributeTargets.Method)] 6 | public class CacheableAttribute : Attribute 7 | { 8 | public CacheableAttribute() 9 | { 10 | } 11 | 12 | public CacheableAttribute(string cacheKey) 13 | { 14 | CacheKey = cacheKey; 15 | } 16 | 17 | public string CacheKey { get; set; } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/LinCms.Core/Aop/Attributes/DisableAuditingAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Aop.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property)] 6 | public class DisableAuditingAttribute : Attribute 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/LinCms.Core/Aop/Attributes/IgnoreMemberAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Aop.Attributes 4 | { 5 | // source: https://github.com/jhewlett/ValueObject 6 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] 7 | public class IgnoreMemberAttribute : Attribute 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/LinCms.Core/Aop/Attributes/LoggerAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Aop.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Method)] 6 | public class LoggerAttribute(string template) : Attribute 7 | { 8 | public string Template { get; } = template ?? throw new ArgumentNullException(nameof(template)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/LinCms.Core/Common/EncryptUtil.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Cryptography; 2 | using System.Text; 3 | 4 | namespace LinCms.Common 5 | { 6 | public class EncryptUtil 7 | { 8 | /// 9 | /// 通过创建哈希字符串适用于任何 MD5 哈希函数 (在任何平台) 上创建 32 个字符的十六进制格式哈希字符串 10 | /// 11 | /// 12 | /// 13 | public static string Encrypt(string source) 14 | { 15 | using MD5 md5Hash = MD5.Create(); 16 | byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(source)); 17 | StringBuilder sBuilder = new StringBuilder(); 18 | foreach (byte t in data) 19 | { 20 | sBuilder.Append(t.ToString("x2")); 21 | } 22 | 23 | string hash = sBuilder.ToString(); 24 | return hash.ToUpper(); 25 | } 26 | 27 | /// 28 | /// 验证source加密码后是否生成mdPwd 29 | /// 30 | /// Md5生成的代码 31 | /// 32 | /// 33 | public static bool Verify(string mdPwd, string source) 34 | { 35 | return mdPwd == Encrypt(source).ToUpper(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/LinCms.Core/Common/LinConsts.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Common 2 | { 3 | public static class LinConsts 4 | { 5 | public static class Group 6 | { 7 | public const int Admin = 1; 8 | public const int CmsAdmin = 2; 9 | public const int User = 3; 10 | } 11 | 12 | public static class Claims 13 | { 14 | public const string Bio = "urn:github:bio"; 15 | public const string AvatarUrl = "urn:github:avatar_url"; 16 | public const string HtmlUrl = "urn:github:html_url"; 17 | public const string BlogAddress = "urn:github:blog"; 18 | } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Authorization/PermissionAuthorizationRequirement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Authorization.Infrastructure; 3 | 4 | namespace LinCms.Data.Authorization 5 | { 6 | public class ModuleAuthorizationRequirement : OperationAuthorizationRequirement 7 | { 8 | public ModuleAuthorizationRequirement(string module, string permission) 9 | { 10 | Module = module ?? throw new ArgumentNullException(nameof(module)); 11 | Name = permission ?? throw new ArgumentNullException(nameof(permission)); 12 | } 13 | 14 | public string Module { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Authorization/ValidJtiRequirement.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | 3 | namespace LinCms.Data.Authorization 4 | { 5 | public class ValidJtiRequirement : IAuthorizationRequirement 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Enums/CapMessageQueueType.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Data.Enums 2 | { 3 | public enum CapMessageQueueType 4 | { 5 | InMemoryQueue = 0, 6 | RabbitMQ = 1, 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Enums/CapStorageType.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Data.Enums 2 | { 3 | public enum CapStorageType 4 | { 5 | /// 6 | /// 引用包 DotNetCore.CAP.InMemoryStorage 7 | /// 8 | InMemoryStorage = 0, 9 | /// 10 | /// 引用包 DotNetCore.CAP.MySql 11 | /// 12 | Mysql = 1, 13 | /// 14 | /// 引用包 DotNetCore.CAP.SqlServer 15 | /// 16 | SqlServer = 2 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Enums/Status.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Data.Enums 2 | { 3 | public enum Status 4 | { 5 | /// 6 | /// 启用 7 | /// 8 | Enable = 1, 9 | /// 10 | /// 禁用 11 | /// 12 | Forbidden = 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Enums/TokenType.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Data.Enums 2 | { 3 | /* 4 | * 令牌类型静态类 5 | */ 6 | public class TokenType 7 | { 8 | /// 9 | /// access token 10 | /// 11 | public static string Access = "access"; 12 | /// 13 | /// refresh token 14 | /// 15 | public static string Refresh = "refresh"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Enums/UserStatus.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Data.Enums 2 | { 3 | /** 4 | * 当前用户是否为激活状态的枚举 5 | * ACTIVE 代表 激活状态 6 | * NOT_ACTIVE 代表 非激活状态 7 | */ 8 | public enum UserStatus 9 | { 10 | /// 11 | /// 激活状态 12 | /// 13 | Active = 1, 14 | /// 15 | /// 非激活状态 16 | /// 17 | NotActive = 2 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Options/FileStorageOption.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Data.Options 2 | { 3 | public class FileStorageOption 4 | { 5 | /// 6 | /// 上传文件总大小 7 | /// 8 | public long MaxFileSize { get; set; } 9 | /// 10 | /// 多文件上传时,支持的最大文件数量 11 | /// 12 | public int NumLimit { get; set; } 13 | /// 14 | /// 允许某些类型文件上传,文件格式以,隔开 15 | /// 16 | public string Include { get; set; } 17 | /// 18 | /// 禁止某些类型文件上传,文件格式以,隔开 19 | /// 20 | public string Exclude { get; set; } 21 | 22 | public string ServiceName { get; set; } 23 | public LocalFileOption LocalFile { get; set; } 24 | public QiniuOptions Qiniu { get; set; } 25 | } 26 | } -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Options/LocalFileOption.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace LinCms.Data.Options 3 | { 4 | public class LocalFileOption 5 | { 6 | public string PrefixPath { get; set; } 7 | public string Host { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Options/QiniuOption.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Data.Options 2 | { 3 | public class QiniuOptions 4 | { 5 | public string AK { get; set; } 6 | public string SK { get; set; } 7 | public string Bucket { get; set; } 8 | public string PrefixPath { get; set; } 9 | public string Host { get; set; } 10 | public bool UseHttps { get; set; } 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/Options/SiteOption.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Data.Options 2 | { 3 | public class SiteOption 4 | { 5 | public string Domain { get; set; } 6 | public string VVLogDomain { get; set; } 7 | public string CMSDomain { get; set; } 8 | public string ApiDomain { get; set; } 9 | public string IdentityServer4Domain { get; set; } 10 | public string Email { get; set; } 11 | public string BlogUrl { get; set; } 12 | public string DocUrl { get; set; } 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/LinCms.Core/Data/PagedAndSortedRequestDto.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace LinCms.Data 6 | { 7 | public class PagedAndSortedRequestDto : PageDto, ISortedResultRequest 8 | { 9 | public string Sorting { get; set; } 10 | } 11 | 12 | 13 | /// 14 | /// 分页 15 | /// 16 | public class PageDto : IPageDto 17 | { 18 | /// 19 | /// 每页个数 20 | /// 21 | [Range(1, int.MaxValue, ErrorMessage = "每页个数最小为1")] 22 | public int Count { get; set; } = 15; 23 | 24 | /// 25 | /// 从0开始,0时取第1页,1时取第二页 26 | /// 27 | public int Page { get; set; } 28 | 29 | public string Sort { get; set; } 30 | } 31 | 32 | public interface IPageDto : ILimitedResultRequest 33 | { 34 | int Page { get; set; } 35 | } 36 | 37 | public interface ILimitedResultRequest 38 | { 39 | /// 40 | /// Maximum result count should be returned. 41 | /// This is generally used to limit result count on paging. 42 | /// 43 | int Count { get; set; } 44 | } 45 | 46 | /// 47 | /// This interface is defined to standardize to request a sorted result. 48 | /// 49 | public interface ISortedResultRequest 50 | { 51 | /// 52 | /// Sorting information. 53 | /// Should include sorting field and optionally a direction (ASC or DESC) 54 | /// Can contain more than one field separated by comma (,). 55 | /// 56 | /// 57 | /// Examples: 58 | /// "Name" 59 | /// "Name DESC" 60 | /// "Name ASC, Age DESC" 61 | /// 62 | string Sorting { get; set; } 63 | } 64 | } -------------------------------------------------------------------------------- /src/LinCms.Core/Data/PermissionDefinition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Data 4 | { 5 | public class PermissionDefinition(string permission, string module, string router) 6 | { 7 | public string Permission { get; set; } = permission ?? throw new ArgumentNullException(nameof(permission)); 8 | public string Module { get; set; } = module ?? throw new ArgumentNullException(nameof(module)); 9 | public string Router { get; set; } = router ?? throw new ArgumentNullException(nameof(router)); 10 | 11 | public override string ToString() 12 | { 13 | return base.ToString() + $" Permission:{Permission}、Module:{Module}、Router:{Router}"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/LinCms.Core/Domain/Captcha/CaptchaBO.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Domain.Captcha; 4 | 5 | public class CaptchaBO 6 | { 7 | public CaptchaBO() 8 | { 9 | } 10 | 11 | public CaptchaBO(string captcha, long expired) 12 | { 13 | Captcha = captcha ?? throw new ArgumentNullException(nameof(captcha)); 14 | Expired = expired; 15 | } 16 | 17 | public string Captcha { get; set; } 18 | public long Expired { get; set; } 19 | } 20 | -------------------------------------------------------------------------------- /src/LinCms.Core/Domain/Captcha/CaptchaOption.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Domain.Captcha 2 | { 3 | /// 4 | /// 验证码配置 5 | /// 6 | public class CaptchaOption 7 | { 8 | /// 9 | /// 是否启用验证码 10 | /// 11 | public bool Enabled { get; set; } 12 | 13 | /// 14 | /// 盐值 15 | /// 16 | public string Salt { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/LinCms.Core/Domain/Captcha/ICaptchaManager.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Domain.Captcha; 2 | 3 | public interface ICaptchaManager 4 | { 5 | 6 | /// 7 | /// 获取加密后验证码 8 | /// 9 | /// 原验证码 10 | /// 盐值 11 | /// 过期时间(单位秒) 12 | /// 13 | string GetTag(string captcha, string salt = "cryptography_salt", int seconds = 300); 14 | 15 | /// 16 | /// 获取时间戳(13位) 17 | /// 18 | /// 19 | /// 20 | long GetTimeStamp(int seconds=0); 21 | /// 22 | /// 随机字符的获取 23 | /// 24 | /// 25 | /// 26 | string GetRandomString(int num); 27 | 28 | /// 29 | /// 生成随机图片的base64编码字符串 30 | /// 31 | /// 32 | /// 33 | string GetRandomCaptchaBase64(string captcha); 34 | 35 | /// 36 | /// 解密出验证码 37 | /// 38 | /// 39 | /// 40 | /// 41 | CaptchaBO DecodeTag(string tag, string salt = "cryptography_salt"); 42 | } -------------------------------------------------------------------------------- /src/LinCms.Core/Domain/ITokenManager.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using IGeekFan.FreeKit.Extras.Security; 3 | using LinCms.Entities; 4 | 5 | namespace LinCms.Domain; 6 | 7 | /// 8 | /// Token 处理类 9 | /// 10 | public interface ITokenManager 11 | { 12 | Task CreateTokenAsync(LinUser user); 13 | } -------------------------------------------------------------------------------- /src/LinCms.Core/Domain/TokenManager.cs: -------------------------------------------------------------------------------- 1 | using DotNetCore.Security; 2 | using IGeekFan.FreeKit.Extras.Dependency; 3 | using IGeekFan.FreeKit.Extras.Security; 4 | using LinCms.Entities; 5 | using LinCms.IRepositories; 6 | using LinCms.Security; 7 | using Microsoft.Extensions.Logging; 8 | using System.Collections.Generic; 9 | using System.Security.Claims; 10 | using System.Threading.Tasks; 11 | 12 | namespace LinCms.Domain; 13 | 14 | public class TokenManager(IJwtService jsonWebTokenService, ILogger logger, IUserRepository userRepository) 15 | : ITokenManager, ITransientDependency 16 | { 17 | public async Task CreateTokenAsync(LinUser user) 18 | { 19 | List claims = new() 20 | { 21 | new Claim(FreeKitClaimTypes.NameIdentifier, user.Id.ToString()), 22 | new Claim(FreeKitClaimTypes.Email, user.Email ?? ""), 23 | new Claim(FreeKitClaimTypes.Name, user.Nickname ?? ""), 24 | new Claim(FreeKitClaimTypes.UserName, user.Username ?? ""), 25 | }; 26 | user.LinGroups?.ForEach(r => 27 | { 28 | claims.Add(new Claim(FreeKitClaimTypes.Role, r.Name)); 29 | claims.Add(new Claim(LinCmsClaimTypes.GroupIds, r.Id.ToString())); 30 | }); 31 | 32 | string token = jsonWebTokenService.Encode(claims); 33 | 34 | user.AddRefreshToken(); 35 | await userRepository.UpdateAsync(user); 36 | 37 | return new UserAccessToken(token, user.RefreshToken, 24 * 60 * 60, "Bearer", 24 * 60 * 60 * 30); 38 | } 39 | } -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Base/BaseItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities.Base 6 | { 7 | /// 8 | /// 数据字典-详情项 9 | /// 10 | [Table(Name = "base_item")] 11 | public class BaseItem : FullAuditEntity 12 | { 13 | public BaseItem() 14 | { 15 | } 16 | 17 | public BaseItem(string itemCode, string itemName, int? sortCode, bool status) 18 | { 19 | ItemCode = itemCode ?? throw new ArgumentNullException(nameof(itemCode)); 20 | ItemName = itemName ?? throw new ArgumentNullException(nameof(itemName)); 21 | SortCode = sortCode; 22 | Status = status; 23 | } 24 | 25 | public BaseItem(string itemCode, string itemName, int? sortCode, int baseTypeId, bool status) : this(itemCode, itemName, sortCode, status) 26 | { 27 | BaseTypeId = baseTypeId; 28 | } 29 | 30 | /// 31 | /// 数据字典-分类Id 32 | /// 33 | public long BaseTypeId { get; set; } 34 | 35 | /// 36 | /// 数据字典-编码 37 | /// 38 | 39 | [Column(StringLength = 50)] 40 | public string ItemCode { get; set; } 41 | 42 | /// 43 | /// 数据字典-名称 44 | /// 45 | 46 | [Column(StringLength = 50)] 47 | public string ItemName { get; set; } 48 | 49 | /// 50 | /// 排序码 51 | /// 52 | 53 | public int? SortCode { get; set; } 54 | 55 | /// 56 | /// 状态 57 | /// 58 | public bool Status { get; set; } 59 | 60 | public virtual BaseType BaseType { get; set; } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Base/BaseType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FreeSql.DataAnnotations; 4 | using IGeekFan.FreeKit.Extras.AuditEntity; 5 | 6 | namespace LinCms.Entities.Base 7 | { 8 | /// 9 | /// 数据字典-分类 10 | /// 11 | [Table(Name = "base_type")] 12 | public class BaseType : FullAuditEntity 13 | { 14 | public BaseType() 15 | { 16 | } 17 | 18 | public BaseType(string typeCode, string fullName, int? sortCode) 19 | { 20 | TypeCode = typeCode ?? throw new ArgumentNullException(nameof(typeCode)); 21 | FullName = fullName ?? throw new ArgumentNullException(nameof(fullName)); 22 | SortCode = sortCode; 23 | } 24 | 25 | /// 26 | /// 分类编码 27 | /// 28 | [Column(StringLength = 50)] 29 | public string TypeCode { get; set; } 30 | 31 | /// 32 | /// 分类名称 33 | /// 34 | [Column(StringLength = 50)] 35 | public string FullName { get; set; } 36 | 37 | /// 38 | /// 排序码 39 | /// 40 | public int? SortCode { get; set; } 41 | 42 | public virtual ICollection BaseItems { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/BlackRecord.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities 6 | { 7 | /// 8 | /// 黑名单,实现登录Token的过期 9 | /// 10 | public class BlackRecord : Entity, ICreateAuditEntity 11 | { 12 | /// 13 | /// 用户Token 14 | /// 15 | [StringLength(-2)] 16 | public string Jti { get; set; } 17 | 18 | /// 19 | /// 登录名 20 | /// 21 | [StringLength(50)] 22 | public string UserName { get; set; } 23 | 24 | /// 25 | public long? CreateUserId { get; set; } 26 | 27 | /// 28 | public string CreateUserName { get; set; } 29 | 30 | /// 31 | public DateTime CreateTime { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Blog/ArticleCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities.Blog; 6 | 7 | /// 8 | /// 用户文章收藏 9 | /// 10 | [Table(Name = "blog_article_collection")] 11 | public class ArticleCollection : Entity, ICreateAuditEntity 12 | { 13 | public Guid ArticleId { get; set; } 14 | public Guid CollectionId { get; set; } 15 | public long? CreateUserId { get; set; } 16 | public string CreateUserName { get; set; } 17 | public DateTime CreateTime { get; set; } 18 | 19 | public Article Article { get; set; } 20 | public Collection Collection { get; set; } 21 | } -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Blog/ArticleDraft.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities.Blog 6 | { 7 | /// 8 | /// 随笔草稿箱 9 | /// 10 | [Table(Name = "blog_article_draft")] 11 | public class ArticleDraft : FullAuditEntity 12 | { 13 | public ArticleDraft() 14 | { 15 | } 16 | 17 | public ArticleDraft(Guid id, string content, string title, int editor) 18 | { 19 | Id = id; 20 | Content = content ?? throw new ArgumentNullException(nameof(content)); 21 | Title = title ?? throw new ArgumentNullException(nameof(title)); 22 | Editor = editor; 23 | } 24 | 25 | /// 26 | /// 正文 27 | /// 28 | [Column(StringLength = -2)] 29 | public string Content { get; set; } 30 | 31 | [Column(StringLength = 200)] 32 | public string Title { get; set; } 33 | 34 | /// 35 | ///1:MarkDown编辑器 2:富文本编辑器, 36 | /// 37 | public int Editor { get; set; } = 1; 38 | 39 | public virtual Article Article { get; set; } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Blog/Channel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FreeSql.DataAnnotations; 4 | using IGeekFan.FreeKit.Extras.AuditEntity; 5 | 6 | namespace LinCms.Entities.Blog 7 | { 8 | /// 9 | /// 技术频道,官方分类。标签的分类。 10 | /// 11 | [Table(Name = "blog_channel")] 12 | public class Channel : FullAuditEntity 13 | { 14 | /// 15 | /// 封面图 16 | /// 17 | [Column(StringLength = 100)] 18 | public string Thumbnail { get; set; } 19 | 20 | /// 21 | /// 排序 22 | /// 23 | public int SortCode { get; set; } 24 | 25 | /// 26 | /// 技术频道名称 27 | /// 28 | [Column(StringLength = 50)] 29 | public string ChannelName { get; set; } 30 | 31 | /// 32 | /// 编码 33 | /// 34 | [Column(StringLength = 50)] 35 | public string ChannelCode { get; set; } 36 | 37 | /// 38 | /// 备注描述 39 | /// 40 | [Column(StringLength = 500)] 41 | public string Remark { get; set; } 42 | 43 | /// 44 | /// 是否有效 45 | /// 46 | public bool Status { get; set; } 47 | 48 | public virtual ICollection Tags { get; set; } 49 | public virtual List
Articles { get; set; } 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Blog/ChannelTag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities.Blog 6 | { 7 | /// 8 | /// 频道标签 9 | /// 10 | [Table(Name = "blog_channel_tag")] 11 | public class ChannelTag : FullAuditEntity 12 | { 13 | 14 | public ChannelTag() 15 | { 16 | } 17 | 18 | public ChannelTag(Guid tagId) 19 | { 20 | TagId = tagId; 21 | } 22 | 23 | public ChannelTag(Guid channelId, Guid tagId) 24 | { 25 | ChannelId = channelId; 26 | TagId = tagId; 27 | } 28 | 29 | /// 30 | /// 频道Id 31 | /// 32 | public Guid ChannelId { get; set; } 33 | 34 | /// 35 | /// 标签Id 36 | /// 37 | public Guid TagId { get; set; } 38 | 39 | [Navigate("ChannelId")] 40 | public virtual Channel Channel { get; set; } 41 | [Navigate("TagId")] 42 | public virtual Tag Tag { get; set; } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Blog/Collection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | using JetBrains.Annotations; 5 | 6 | namespace LinCms.Entities.Blog; 7 | 8 | /// 9 | /// 收藏集 10 | /// 11 | [Table(Name = "blog_collection")] 12 | public class Collection : FullAuditEntity 13 | { 14 | /// 15 | /// 名称 16 | /// 17 | [Column(StringLength = 50)] 18 | public string Name { get; set; } 19 | 20 | /// 21 | /// 描述 22 | /// 23 | [Column(StringLength = 200)] 24 | [CanBeNull] 25 | public string Remark { get; set; } 26 | 27 | /// 28 | /// 收藏数量 29 | /// 30 | public int Quantity { get; set; } 31 | 32 | /// 33 | /// 公开 当其他人关注此收藏集后不可再更改为隐私 34 | /// 隐私 仅自己可见此收藏集 35 | /// 36 | public PrivacyType PrivacyType { get; set; } 37 | 38 | public void UpdateQuantity(int quantity) 39 | { 40 | if (quantity < 0 && Quantity < -quantity) return; 41 | Quantity += quantity; 42 | } 43 | } 44 | 45 | public enum PrivacyType 46 | { 47 | /// 48 | /// 公开可见 49 | /// 50 | Public = 0, 51 | 52 | /// 53 | /// 仅自己可见 54 | /// 55 | VisibleOnlyMySelf = 1 56 | } -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Blog/TagArticle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities.Blog 6 | { 7 | /// 8 | /// 随笔标签 9 | /// 10 | [Table(Name = "blog_tag_article")] 11 | public class TagArticle : Entity 12 | { 13 | public Guid TagId { get; set; } 14 | 15 | public Guid ArticleId { get; set; } 16 | 17 | public virtual Tag Tag { get; set; } 18 | 19 | public virtual Article Article { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Blog/UserLike.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities.Blog 6 | { 7 | /// 8 | /// 用户点赞:点赞随笔、评论内容 9 | /// 10 | [Table(Name = "blog_user_like")] 11 | public class UserLike : Entity, ICreateAuditEntity 12 | { 13 | /// 14 | /// 点赞对象 15 | /// 16 | public Guid SubjectId { get; set; } 17 | 18 | /// 19 | /// 点赞类型 1 是随笔,2 是评论 20 | /// 21 | [Column(MapType = typeof(int))] 22 | public UserLikeSubjectType SubjectType { get; set; } 23 | 24 | public long? CreateUserId { get; set; } 25 | 26 | public DateTime CreateTime { get; set; } 27 | 28 | [Navigate("CreateUserId")] 29 | public virtual LinUser LinUser { get; set; } 30 | 31 | [Navigate("SubjectId")] 32 | public virtual Comment Comment { get; set; } 33 | 34 | [Navigate("SubjectId")] 35 | public virtual Article Article { get; set; } 36 | public string CreateUserName { get; set; } 37 | } 38 | 39 | public enum UserLikeSubjectType 40 | { 41 | /// 42 | /// 点赞随笔 43 | /// 44 | UserLikeArticle = 1, 45 | /// 46 | /// 点赞评论 47 | /// 48 | UserLikeComment = 2 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Blog/UserSubscribe.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities.Blog 6 | { 7 | /// 8 | /// 用户关注用户 9 | /// 10 | [Table(Name = "blog_user_subscribe")] 11 | public class UserSubscribe : Entity, ICreateAuditEntity 12 | { 13 | /// 14 | /// 被关注的用户Id 15 | /// 16 | public long SubscribeUserId { get; set; } 17 | 18 | /// 19 | /// 关注的用户Id 20 | /// 21 | public long? CreateUserId { get; set; } 22 | public string CreateUserName { get; set; } 23 | 24 | public DateTime CreateTime { get; set; } 25 | 26 | [Navigate("CreateUserId")] 27 | public virtual LinUser LinUser { get; set; } 28 | 29 | [Navigate("SubscribeUserId")] 30 | public virtual LinUser SubscribeUser { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Blog/UserTag.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities.Blog 6 | { 7 | /// 8 | /// 用户关注的标签 9 | /// 10 | [Table(Name = "blog_user_tag")] 11 | public class UserTag : Entity, ICreateAuditEntity 12 | { 13 | public Guid TagId { get; set; } 14 | 15 | public long? CreateUserId { get; set; } 16 | public string CreateUserName { get; set; } 17 | 18 | 19 | public DateTime CreateTime { get; set; } 20 | 21 | [Navigate("CreateUserId")] 22 | public virtual LinUser LinUser { get; set; } 23 | 24 | [Navigate("TagId")] 25 | public virtual Tag Tag { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/LinFile.cs: -------------------------------------------------------------------------------- 1 | using FreeSql.DataAnnotations; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Entities 5 | { 6 | /// 7 | /// 文件 8 | /// 9 | [Table(Name = "lin_file")] 10 | public class LinFile : FullAuditEntity 11 | { 12 | /// 13 | /// 文件后缀 14 | /// 15 | [Column(StringLength = 50)] 16 | public string Extension { get; set; } = string.Empty; 17 | 18 | /// 19 | /// 图片md5值,防止上传重复图片 20 | /// 21 | [Column(StringLength = 40)] 22 | public string Md5 { get; set; } = string.Empty; 23 | 24 | /// 25 | /// 名称 26 | /// 27 | [Column(StringLength = 300)] 28 | public string Name { get; set; } = string.Empty; 29 | 30 | /// 31 | /// 路径 32 | /// 33 | [Column(StringLength = 500)] 34 | public string Path { get; set; } = string.Empty; 35 | 36 | /// 37 | /// 大小 38 | /// 39 | public long? Size { get; set; } 40 | 41 | /// 42 | /// 1 local,2 代表七牛云 3 其他表示其他地方 43 | /// 44 | public short? Type { get; set; } 45 | 46 | public const string LocalFileService = "LocalFileService"; 47 | public const string QiniuService = "QiniuService"; 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/LinGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using FreeSql.DataAnnotations; 4 | using IGeekFan.FreeKit.Extras.AuditEntity; 5 | 6 | namespace LinCms.Entities 7 | { 8 | /// 9 | /// 分组 10 | /// 11 | [Table(Name = "lin_group")] 12 | public class LinGroup : FullAuditEntity 13 | { 14 | public LinGroup() 15 | { 16 | } 17 | 18 | public LinGroup(string name, string info, bool isStatic) 19 | { 20 | Name = name ?? throw new ArgumentNullException(nameof(name)); 21 | Info = info ?? throw new ArgumentNullException(nameof(info)); 22 | IsStatic = isStatic; 23 | } 24 | 25 | /// 26 | /// 权限组唯一标识字符 27 | /// 28 | [Column(StringLength = 60)] 29 | public string Name { get; set; } 30 | 31 | /// 32 | /// 权限组描述 33 | /// 34 | [Column(StringLength = 100)] 35 | public string Info { get; set; } 36 | 37 | /// 38 | /// 是否是静态分组,是静态时无法删除此分组 39 | /// 40 | public bool IsStatic { get; set; } = false; 41 | 42 | /// 43 | /// 排序码,升序 44 | /// 45 | public int SortCode { get; set; } 46 | 47 | [Navigate(ManyToMany = typeof(LinUserGroup))] 48 | public virtual ICollection LinUsers { get; set; } 49 | 50 | /// 51 | /// 超级管理员 52 | /// 53 | public const string Admin = "Admin"; 54 | /// 55 | /// Cms管理员 56 | /// 57 | public const string CmsAdmin = "CmsAdmin"; 58 | 59 | /// 60 | /// 普通用户 61 | /// 62 | public const string User = "User"; 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/LinGroupPermission.cs: -------------------------------------------------------------------------------- 1 | using FreeSql.DataAnnotations; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Entities 5 | { 6 | /// 7 | /// 分组权限中间表 8 | /// 9 | [Table(Name = "lin_group_permission")] 10 | public class LinGroupPermission : Entity 11 | { 12 | public LinGroupPermission() 13 | { 14 | } 15 | 16 | public LinGroupPermission(long groupId, long permissionId) 17 | { 18 | GroupId = groupId; 19 | PermissionId = permissionId; 20 | } 21 | 22 | public LinGroupPermission(long permissionId) 23 | { 24 | PermissionId = permissionId; 25 | } 26 | 27 | /// 28 | /// 分组id 29 | /// 30 | public long GroupId { get; set; } 31 | 32 | /// 33 | /// 权限Id 34 | /// 35 | public long PermissionId { get; set; } 36 | 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/LinLog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities 6 | { 7 | /// 8 | /// 日志表 9 | /// 10 | [Table(Name = "lin_log")] 11 | public class LinLog : Entity 12 | { 13 | /// 14 | /// 访问哪个权限 15 | /// 16 | [Column(StringLength = 100)] 17 | public string Authority { get; set; } 18 | 19 | /// 20 | /// 日志信息 21 | /// 22 | [Column(StringLength = 500)] 23 | public string Message { get; set; } 24 | 25 | /// 26 | /// 请求方法 27 | /// 28 | [Column(StringLength = 20)] 29 | public string Method { get; set; } 30 | 31 | /// 32 | /// 请求路径 33 | /// 34 | [Column(StringLength = 100)] 35 | public string Path { get; set; } 36 | 37 | /// 38 | /// 请求的http返回码 39 | /// 40 | public int? StatusCode { get; set; } 41 | 42 | /// 43 | /// 用户id 44 | /// 45 | public long? UserId { get; set; } 46 | 47 | /// 48 | /// 用户当时的昵称 49 | /// 50 | [Column(StringLength = 24)] 51 | public string Username { get; set; } 52 | 53 | public DateTime CreateTime { get; set; } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/LinPermission.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Entities 6 | { 7 | /// 8 | /// 权限表 9 | /// 10 | [Table(Name = "lin_permission")] 11 | public class LinPermission : FullAuditEntity 12 | { 13 | public LinPermission() 14 | { 15 | } 16 | 17 | public LinPermission(string name, PermissionType permissionType, string router) 18 | { 19 | Name = name; 20 | PermissionType = permissionType; 21 | Router = router; 22 | } 23 | 24 | public PermissionType PermissionType { get; set; } 25 | 26 | /// 27 | /// 父级Id 28 | /// 29 | public long ParentId { get; set; } 30 | 31 | /// 32 | /// 所属权限、权限名称,例如:访问首页 33 | /// 34 | [Column(StringLength = 60)] 35 | public string Name { get; set; } 36 | 37 | /// 38 | /// 后台路由 39 | /// 40 | [Column(StringLength = 200)] 41 | public string Router { get; set; } 42 | 43 | /// 44 | /// 排序 45 | /// 46 | public int SortCode { get; set; } 47 | 48 | } 49 | 50 | public enum PermissionType 51 | { 52 | Folder = 0, 53 | Permission = 1 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/LinUserGroup.cs: -------------------------------------------------------------------------------- 1 | using FreeSql.DataAnnotations; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Entities 5 | { 6 | /// 7 | /// 用户分组中间表 8 | /// 9 | [Table(Name = "lin_user_group")] 10 | public class LinUserGroup : Entity 11 | { 12 | public LinUserGroup() 13 | { 14 | } 15 | public LinUserGroup(long userId, long groupId) 16 | { 17 | UserId = userId; 18 | GroupId = groupId; 19 | } 20 | 21 | public long UserId { get; set; } 22 | 23 | public long GroupId { get; set; } 24 | 25 | [Navigate("UserId")] 26 | public LinUser LinUser { get; set; } 27 | 28 | [Navigate("GroupId")] 29 | public LinGroup LinGroup { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/SerilogDO.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql.DataAnnotations; 3 | 4 | namespace LinCms.Entities 5 | { 6 | /// 7 | /// Serilog数据库存储 8 | /// 9 | [Table(DisableSyncStructure = true, Name = "app_serilog")] 10 | public class SerilogDO 11 | { 12 | public long Id { get; set; } 13 | public string Exception { get; set; } 14 | public int Level { get; set; } 15 | public string Message { get; set; } 16 | public string MessageTemplate { get; set; } 17 | public string Properties { get; set; } 18 | public DateTime Timestamp { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/LinCms.Core/Entities/Settings/LinSetting.cs: -------------------------------------------------------------------------------- 1 | using FreeSql.DataAnnotations; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Entities.Settings 5 | { 6 | /// 7 | /// 配置项 8 | /// 9 | [Table(Name = "lin_settings")] 10 | public class LinSetting : FullAuditEntity 11 | { 12 | /// 13 | /// 键 14 | /// 15 | [Column(StringLength = 128)] 16 | public string Name { get; set; } 17 | 18 | /// 19 | /// 值 20 | /// 21 | [Column(StringLength = 2048)] 22 | public string Value { get; set; } 23 | 24 | /// 25 | /// 提供者 26 | /// 27 | 28 | [Column(StringLength = 64)] 29 | public string ProviderName { get; set; } 30 | 31 | /// 32 | /// 提供者值 33 | /// 34 | [Column(StringLength = 64)] 35 | public string ProviderKey { get; set; } 36 | 37 | public override string ToString() 38 | { 39 | return $"{base.ToString()}, Name = {Name}, Value = {Value}, ProviderName = {ProviderName}, ProviderKey = {ProviderKey}"; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/LinCms.Core/Exceptions/LinCmsException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using LinCms.Data.Enums; 3 | 4 | namespace LinCms.Exceptions 5 | { 6 | [Serializable] 7 | public class LinCmsException(string message = "服务器繁忙,请稍后再试!", ErrorCode errorCode = ErrorCode.Fail, int code = 400) 8 | : ApplicationException(message) 9 | { 10 | /// 11 | /// 状态码 12 | /// 13 | private readonly int _code = code; 14 | /// 15 | /// 错误码,当为0时,代表正常 16 | /// 17 | 18 | private readonly ErrorCode _errorCode = errorCode; 19 | /// 20 | /// 21 | /// 22 | public LinCmsException() : this("服务器繁忙,请稍后再试!", ErrorCode.Fail, 400) 23 | { 24 | } 25 | 26 | /// 27 | /// 28 | /// 29 | /// 30 | public int GetCode() 31 | { 32 | return _code; 33 | } 34 | 35 | public ErrorCode GetErrorCode() 36 | { 37 | return _errorCode; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/LinCms.Core/Extensions/HttpContextExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Authentication; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace LinCms.Extensions 9 | { 10 | public static class HttpContextExtensions 11 | { 12 | public static async Task GetExternalProvidersAsync(this HttpContext context) 13 | { 14 | if (context == null) 15 | { 16 | throw new ArgumentNullException(nameof(context)); 17 | } 18 | 19 | var schemes = context.RequestServices.GetRequiredService(); 20 | 21 | return (from scheme in await schemes.GetAllSchemesAsync() 22 | where !string.IsNullOrEmpty(scheme.DisplayName) 23 | select scheme).ToArray(); 24 | } 25 | 26 | public static async Task IsProviderSupportedAsync(this HttpContext context, string provider) 27 | { 28 | if (context == null) 29 | { 30 | throw new ArgumentNullException(nameof(context)); 31 | } 32 | 33 | return (from scheme in await context.GetExternalProvidersAsync() 34 | where string.Equals(scheme.Name, provider, StringComparison.OrdinalIgnoreCase) 35 | select scheme).Any(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/LinCms.Core/IRepositories/IFileRepository.cs: -------------------------------------------------------------------------------- 1 | using IGeekFan.FreeKit.Extras.FreeSql; 2 | using LinCms.Entities; 3 | 4 | namespace LinCms.IRepositories 5 | { 6 | public interface IFileRepository : IAuditBaseRepository 7 | { 8 | string GetFileUrl(string path); 9 | 10 | } 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/LinCms.Core/IRepositories/ILogRepository.cs: -------------------------------------------------------------------------------- 1 | using IGeekFan.FreeKit.Extras.FreeSql; 2 | using LinCms.Entities; 3 | 4 | namespace LinCms.IRepositories 5 | { 6 | public interface ILogRepository : IAuditBaseRepository 7 | { 8 | void Create(LinLog linlog); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/LinCms.Core/IRepositories/ISettingRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.FreeSql; 4 | using LinCms.Entities.Settings; 5 | 6 | namespace LinCms.IRepositories 7 | { 8 | public interface ISettingRepository : IAuditBaseRepository 9 | { 10 | Task FindAsync(string name, string providerName, string providerKey); 11 | 12 | Task> GetListAsync(string providerName, string providerKey); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/LinCms.Core/IRepositories/IUserRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using System.Threading.Tasks; 4 | using IGeekFan.FreeKit.Extras.FreeSql; 5 | using LinCms.Entities; 6 | 7 | namespace LinCms.IRepositories 8 | { 9 | public interface IUserRepository : IAuditBaseRepository 10 | { 11 | /// 12 | /// 根据条件得到用户信息 13 | /// 14 | /// 15 | /// 16 | Task GetUserAsync(Expression> expression); 17 | 18 | /// 19 | /// 根据用户Id更新用户的最后登录时间 20 | /// 21 | /// 22 | /// 23 | Task UpdateLastLoginTimeAsync(long userId); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/LinCms.Core/LinCms.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | LinCms 6 | True 7 | 8 | 9 | 10 | LinCms.Core.xml 11 | bin\Debug\ 12 | 4 13 | 1701;1702;1705;1591 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/LinCms.Core/Security/LinCmsClaimTypes.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Security 2 | { 3 | public class LinCmsClaimTypes 4 | { 5 | public const string GroupIds = "groupids"; 6 | public const string IsActive = "isactve"; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/LinCms.Infrastructure/FreeSql/IDataSeedContributor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using IGeekFan.FreeKit.Extras.Dependency; 5 | using LinCms.Data; 6 | 7 | namespace LinCms.FreeSql; 8 | 9 | public interface IDataSeedContributor: ISingletonDependency 10 | { 11 | 12 | Task InitAdminPermission(); 13 | 14 | Task SeedPermissionAsync(List linCmsAttributes, CancellationToken cancellationToken); 15 | 16 | } -------------------------------------------------------------------------------- /src/LinCms.Infrastructure/LinCms.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | LinCms 6 | True 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/LinCms.Infrastructure/Repositories/FileRepository.cs: -------------------------------------------------------------------------------- 1 | using FreeSql; 2 | using IGeekFan.FreeKit.Extras.FreeSql; 3 | using IGeekFan.FreeKit.Extras.Security; 4 | using LinCms.Data.Options; 5 | using LinCms.Entities; 6 | using LinCms.IRepositories; 7 | using Microsoft.Extensions.Options; 8 | 9 | namespace LinCms.Repositories; 10 | 11 | public class FileRepository(UnitOfWorkManager unitOfWorkManager, 12 | ICurrentUser currentUser, 13 | IOptionsMonitor fileStorageOption) 14 | : AuditDefaultRepository(unitOfWorkManager, currentUser), IFileRepository 15 | { 16 | private readonly FileStorageOption _fileStorageOption = fileStorageOption.CurrentValue; 17 | 18 | public string GetFileUrl(string path) 19 | { 20 | if (string.IsNullOrEmpty(path)) return ""; 21 | if (path.StartsWith("http") || path.StartsWith("https")) 22 | { 23 | return path; 24 | } 25 | return _fileStorageOption.LocalFile.Host + path; 26 | 27 | //string redisKey = "filerepository:getfileurl:" +path; 28 | 29 | //return RedisHelper.CacheShell( 30 | // redisKey, 5*60, () => 31 | // { 32 | // LinFile linFile = Where(r => r.Path == path).First(); 33 | // if (linFile == null) return path; 34 | // return linFile.Type switch 35 | // { 36 | // 1 => _fileStorageOption.LocalFile.Host + path, 37 | // 2 => _fileStorageOption.Qiniu.Host + path, 38 | // _ => path, 39 | // }; 40 | // } 41 | // ); 42 | } 43 | } -------------------------------------------------------------------------------- /src/LinCms.Infrastructure/Repositories/LogRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql; 3 | using IGeekFan.FreeKit.Extras.FreeSql; 4 | using IGeekFan.FreeKit.Extras.Security; 5 | using LinCms.Entities; 6 | using LinCms.IRepositories; 7 | using LinCms.Security; 8 | 9 | namespace LinCms.Repositories; 10 | 11 | public class LogRepository : AuditDefaultRepository, ILogRepository 12 | { 13 | public LogRepository(UnitOfWorkManager unitOfWorkManager, ICurrentUser currentUser) 14 | : base(unitOfWorkManager, currentUser) 15 | { 16 | 17 | } 18 | 19 | public void Create(LinLog linlog) 20 | { 21 | linlog.CreateTime = DateTime.Now; 22 | linlog.Username = CurrentUser.UserName; 23 | linlog.UserId = CurrentUser.FindUserId(); 24 | 25 | base.Insert(linlog); 26 | } 27 | } -------------------------------------------------------------------------------- /src/LinCms.Infrastructure/Repositories/SettingRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using FreeSql; 5 | using IGeekFan.FreeKit.Extras.FreeSql; 6 | using IGeekFan.FreeKit.Extras.Security; 7 | using LinCms.Entities.Settings; 8 | using LinCms.IRepositories; 9 | 10 | namespace LinCms.Repositories; 11 | 12 | public class SettingRepository : AuditDefaultRepository, ISettingRepository 13 | { 14 | public SettingRepository(UnitOfWorkManager unitOfWorkManager, ICurrentUser currentUser) : base(unitOfWorkManager, 15 | currentUser) 16 | { 17 | } 18 | 19 | public async Task FindAsync(string name, string providerName, string providerKey) 20 | { 21 | return await Select.Where(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey) 22 | .FirstAsync(); 23 | } 24 | 25 | public async Task> GetListAsync(string providerName, string providerKey) 26 | { 27 | return await Select 28 | .Where( 29 | s => s.ProviderName == providerName && s.ProviderKey == providerKey 30 | ) 31 | .OrderByDescending(r => r.CreateTime) 32 | .ToListAsync(); 33 | } 34 | } -------------------------------------------------------------------------------- /src/LinCms.Infrastructure/Repositories/UserRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using System.Threading.Tasks; 4 | 5 | using FreeSql; 6 | using IGeekFan.FreeKit.Extras.FreeSql; 7 | using IGeekFan.FreeKit.Extras.Security; 8 | using LinCms.Entities; 9 | using LinCms.IRepositories; 10 | 11 | namespace LinCms.Repositories; 12 | 13 | public class UserRepository : AuditDefaultRepository, IUserRepository 14 | { 15 | public UserRepository(UnitOfWorkManager unitOfWorkManager, ICurrentUser currentUser) : base(unitOfWorkManager, currentUser) 16 | { 17 | } 18 | 19 | /// 20 | /// 根据条件得到用户信息 21 | /// 22 | /// 23 | /// 24 | public Task GetUserAsync(Expression> expression) 25 | { 26 | return Select.Where(expression).IncludeMany(r => r.LinGroups).ToOneAsync(); 27 | } 28 | 29 | /// 30 | /// 根据用户Id更新用户的最后登录时间 31 | /// 32 | /// 33 | /// 34 | public Task UpdateLastLoginTimeAsync(long userId) 35 | { 36 | return UpdateDiy.Set(r => new LinUser() 37 | { 38 | LastLoginTime = DateTime.Now 39 | }).Where(r => r.Id == userId).ExecuteAffrowsAsync(); 40 | } 41 | } -------------------------------------------------------------------------------- /src/LinCms.Plugins/LinCms.Plugins.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/LinCms.Plugins/Poem/Domain/LinPoem.cs: -------------------------------------------------------------------------------- 1 | using FreeSql.DataAnnotations; 2 | using IGeekFan.FreeKit.Extras.AuditEntity; 3 | 4 | namespace LinCms.Plugins.Poem.Domain; 5 | 6 | [Table(Name = "lin_poem")] 7 | public class LinPoem : FullAuditEntity 8 | { 9 | 10 | /// 11 | /// 作者 12 | /// 13 | [Column(StringLength = 50)] 14 | public string Author { get; set; } = string.Empty; 15 | 16 | /// 17 | /// 内容,以/来分割每一句,以|来分割宋词的上下片 18 | /// 19 | [Column(DbType = "text")] 20 | public string Content { get; set; } = string.Empty; 21 | 22 | /// 23 | /// 朝代 24 | /// 25 | [Column(StringLength = 50)] 26 | public string Dynasty { get; set; } = string.Empty; 27 | 28 | /// 29 | /// 配图 30 | /// 31 | public string Image { get; set; } = string.Empty; 32 | 33 | /// 34 | /// 标题 35 | /// 36 | [Column(StringLength = 50)] 37 | public string Title { get; set; } = string.Empty; 38 | 39 | 40 | } -------------------------------------------------------------------------------- /src/LinCms.Plugins/Poem/Models/CreateUpdatePoemDto.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Plugins.Poem.Models; 2 | 3 | public class CreateUpdatePoemDto 4 | { 5 | public string Author { get; set; } 6 | public string Content { get; set; } 7 | public string Dynasty { get; set; } 8 | public string Image { get; set; } 9 | public string Title { get; set; } 10 | } -------------------------------------------------------------------------------- /src/LinCms.Plugins/Poem/Models/PoemDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IGeekFan.FreeKit.Extras.AuditEntity; 4 | 5 | namespace LinCms.Plugins.Poem.Models; 6 | 7 | public class PoemDto : EntityDto 8 | { 9 | public string Author { get; set; } 10 | public List> Content { get; set; } 11 | public string Dynasty { get; set; } 12 | public string Image { get; set; } 13 | public string Title { get; set; } 14 | public DateTime CreateTime { get; set; } 15 | public DateTime UpdateTime { get; set; } 16 | } -------------------------------------------------------------------------------- /src/LinCms.Plugins/Poem/PoemModule.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Plugins.Poem; 2 | 3 | class PoemModule 4 | { 5 | } -------------------------------------------------------------------------------- /src/LinCms.Plugins/Poem/Services/IPoemService.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Plugins.Poem.Services; 2 | 3 | public interface IPoemService 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /src/LinCms.Plugins/Poem/Services/PoemProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using AutoMapper; 4 | using LinCms.Plugins.Poem.Domain; 5 | using LinCms.Plugins.Poem.Models; 6 | 7 | namespace LinCms.Plugins.Poem.Services; 8 | 9 | public class PoemProfile : Profile 10 | { 11 | public PoemProfile() 12 | { 13 | CreateMap() 14 | .ForMember(r => r.Content, opts => opts.MapFrom(r => r 15 | .Content 16 | .Split('|', StringSplitOptions.None) 17 | .ToList() 18 | .ConvertAll(u => u.Split('/', StringSplitOptions.None).ToList()) 19 | )); 20 | 21 | CreateMap(); 22 | 23 | } 24 | 25 | 26 | } -------------------------------------------------------------------------------- /src/LinCms.Plugins/Poem/Services/PoemService.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Plugins.Poem.Services; 2 | 3 | public class PoemService : IPoemService 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Entities/CommandOption.cs: -------------------------------------------------------------------------------- 1 | namespace LinCms.Scaffolding.Entities 2 | { 3 | public class CommandOption 4 | { 5 | public string Directory { get; set; } = null!; 6 | public string Entity { get; set; } = null!; 7 | /// 8 | /// 是否拆分DTO 9 | /// 10 | public bool SeparateDto { get; set; } 11 | public bool CustomRepository { get; set; } 12 | public bool NoOverwrite { get; set; } 13 | public bool SkipEntityConstructors { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Entities/ProjectInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace LinCms.Scaffolding.Entities 4 | { 5 | public class ProjectInfo 6 | { 7 | public ProjectInfo(string baseDirectory, string fullName) 8 | { 9 | BaseDirectory = baseDirectory; 10 | FullName = fullName; 11 | } 12 | 13 | public string BaseDirectory { get; } 14 | public string FullName { get; } 15 | public string Name => FullName.Split('.').Last(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Entities/PropertyInfo.cs: -------------------------------------------------------------------------------- 1 | using Humanizer; 2 | using System; 3 | 4 | namespace LinCms.Scaffolding.Entities 5 | { 6 | /// 7 | /// 属性 8 | /// 9 | public class PropertyInfo 10 | { 11 | public PropertyInfo(string type, string name) 12 | { 13 | Type = type; 14 | Name = name; 15 | } 16 | 17 | public PropertyInfo(string type, string name, string remarks) : this(type, name) 18 | { 19 | Remarks = remarks ?? throw new ArgumentNullException(nameof(remarks)); 20 | } 21 | 22 | /// 23 | /// 属性类型 24 | /// 25 | public string Type { get; } 26 | 27 | /// 28 | /// 属性名 29 | /// 30 | public string Name { get; } 31 | 32 | /// 33 | /// 备注 34 | /// 35 | public string Remarks { get; set; } 36 | 37 | 38 | /// 39 | /// 属性名转下划线 40 | /// 41 | public string NameUnderscore => Name.Underscore(); 42 | 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Entities/SettingOptions.cs: -------------------------------------------------------------------------------- 1 | using Humanizer; 2 | 3 | namespace LinCms.Scaffolding.Entities 4 | { 5 | public class SettingOptions 6 | { 7 | public static string Name = "SettingOptions"; 8 | public string BaseDirectory { get; set; } 9 | public string ProjectName { get; set; } 10 | public string Areas { get; set; } 11 | public string EntityFilePath { get; set; } 12 | public string TemplatePath { get; set; } 13 | public string OutputDirectory { get; set; } 14 | //区域小写 15 | public string AreasCamelize => Areas.Camelize(); 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/LinCms.Scaffolding.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | 7 | 8 | 9 | 10 | 11 | PreserveNewest 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | PreserveNewest 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Templates/lin-cms-vue/model/{{EntityInfo.NameCamelize}}.js.txt: -------------------------------------------------------------------------------- 1 | import { post, get, put, _delete } from "@/lin/plugin/axios"; 2 | 3 | class {{EntityInfo.Name}} { 4 | 5 | async get{{EntityInfo.NamePluralized}}(params) { 6 | const res = await get("api/{{SettingOptions.AreasCamelize}}/{{EntityInfo.NameCamelizePluralized}}", params); 7 | return res; 8 | } 9 | 10 | async get{{EntityInfo.Name}}(id) { 11 | const res = await get(`api/{{SettingOptions.AreasCamelize}}/{{EntityInfo.NameCamelizePluralized}}/${id}`); 12 | return res; 13 | } 14 | 15 | async add{{EntityInfo.Name}}(params) { 16 | const res = await post("api/{{SettingOptions.AreasCamelize}}/{{EntityInfo.NameCamelizePluralized}}", params); 17 | return res; 18 | } 19 | 20 | async edit{{EntityInfo.Name}}(id, data) { 21 | const res = await put(`api/{{SettingOptions.AreasCamelize}}/{{EntityInfo.NameCamelizePluralized}}/${id}`, data); 22 | return res; 23 | } 24 | 25 | async delete{{EntityInfo.Name}}(id) { 26 | const res = await _delete(`api/{{SettingOptions.AreasCamelize}}/{{EntityInfo.NameCamelizePluralized}}/${id}`); 27 | return res; 28 | } 29 | 30 | } 31 | 32 | export default new {{EntityInfo.Name}}(); 33 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Templates/lin-cms-vue/stage-config.js.txt: -------------------------------------------------------------------------------- 1 | const {{SettingOptions.AreasCamelize}}Router = { 2 | route: null, 3 | name: null, 4 | title: "工作台", 5 | type: "folder", // 类型: folder, tab, view 6 | icon: "iconfont icon-tushuguanli", 7 | filePath: "view/{{SettingOptions.AreasCamelize}}/", 8 | order: null, 9 | inNav: true, 10 | children: [ 11 | { 12 | name: null, 13 | title: "{{EntityInfo.EntityRemark}}管理", 14 | type: "view", 15 | name: "{{EntityInfo.Name}}List", 16 | route: "/{{SettingOptions.AreasCamelize}}/{{EntityInfo.NameCamelize}}/list", 17 | filePath: "plugin/{{SettingOptions.AreasCamelize}}/view/{{EntityInfo.NameCamelize}}/{{EntityInfo.NameCamelize}}-list.vue", 18 | inNav: true, 19 | permission: ["所有{{EntityInfo.EntityRemark}}"] 20 | } 21 | ] 22 | }; 23 | 24 | export default {{SettingOptions.AreasCamelize}}Router; 25 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Templates/{{ProjectInfo.FullName}}.Application.Contracts/{{SettingOptions.Areas}}/{{EntityInfo.NamePluralized}}/CreateUpdate{{EntityInfo.Name}}Dto.cs.txt: -------------------------------------------------------------------------------- 1 |  2 | namespace {{ EntityInfo.Namespace }} 3 | { 4 | public class CreateUpdate{{EntityInfo.Name }}Dto 5 | { 6 | {{~ for prop in EntityInfo.Properties ~}} 7 | public {{ prop.Type}} {{ prop.Name }} { get; set; } 8 | {{~ if !for.last ~}} 9 | 10 | {{~ end ~}} 11 | {{~ end ~}} 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Templates/{{ProjectInfo.FullName}}.Application.Contracts/{{SettingOptions.Areas}}/{{EntityInfo.NamePluralized}}/I{{EntityInfo.Name}}Service.cs.txt: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using LinCms.Data; 3 | 4 | namespace {{ EntityInfo.Namespace }} 5 | { 6 | public interface I{{ EntityInfo.Name }}Service 7 | { 8 | Task DeleteAsync({{EntityInfo.PrimaryKey}} id); 9 | 10 | Task> GetListAsync(PageDto pageDto); 11 | 12 | Task<{{ EntityInfo.Name }}Dto> GetAsync({{EntityInfo.PrimaryKey}} id); 13 | 14 | Task CreateAsync(CreateUpdate{{ EntityInfo.Name }}Dto create{{ EntityInfo.Name }}); 15 | 16 | Task UpdateAsync({{EntityInfo.PrimaryKey}} id, CreateUpdate{{ EntityInfo.Name }}Dto update{{ EntityInfo.Name }}); 17 | } 18 | } -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Templates/{{ProjectInfo.FullName}}.Application.Contracts/{{SettingOptions.Areas}}/{{EntityInfo.NamePluralized}}/{{EntityInfo.Name}}Dto.cs.txt: -------------------------------------------------------------------------------- 1 | using LinCms.Entities; 2 | namespace {{ EntityInfo.Namespace }} 3 | { 4 | public class {{EntityInfo.Name }}Dto:EntityDto<{{ EntityInfo.PrimaryKey }}> 5 | { 6 | {{~ for prop in EntityInfo.Properties ~}} 7 | public {{ prop.Type}} {{ prop.Name }} { get; set; } 8 | {{~ if !for.last ~}} 9 | 10 | {{~ end ~}} 11 | {{~ end ~}} 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Templates/{{ProjectInfo.FullName}}.Application/{{SettingOptions.Areas}}/{{EntityInfo.NamePluralized}}/{{EntityInfo.Name}}Profile.cs.txt: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using {{ProjectInfo.FullName}}.Entities.{{SettingOptions.Areas}}; 3 | 4 | namespace {{ EntityInfo.Namespace }} 5 | { 6 | public class {{ EntityInfo.Name }}Profile : Profile 7 | { 8 | public {{ EntityInfo.Name }}Profile() 9 | { 10 | CreateMap<{{ EntityInfo.Name }}, {{ EntityInfo.Name }}Dto>(); 11 | CreateMap(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Templates/{{ProjectInfo.FullName}}.Core/IRepositories/I{{EntityInfo.Name}}Repository.cs.txt: -------------------------------------------------------------------------------- 1 | using {{ProjectInfo.FullName}}.Entities.{{SettingOptions.Areas}}; 2 | namespace {{ProjectInfo.FullName}}.IRepositories 3 | { 4 | public interface I{{ EntityInfo.Name }}Repository : IAuditBaseRepository<{{ EntityInfo.Name }},{{EntityInfo.PrimaryKey}}> 5 | { 6 | 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/Templates/{{ProjectInfo.FullName}}.Infrastructure/Repositories/{{EntityInfo.Name}}Repository.cs.txt: -------------------------------------------------------------------------------- 1 | using FreeSql; 2 | using {{ProjectInfo.FullName}}.Entities.{{SettingOptions.Areas}}; 3 | using {{ProjectInfo.FullName}}.IRepositories; 4 | using {{ProjectInfo.FullName}}.Security; 5 | namespace {{ProjectInfo.FullName}}.Repositories 6 | { 7 | public class {{ EntityInfo.Name }}Repository : AuditBaseRepository<{{ EntityInfo.Name }},{{EntityInfo.PrimaryKey}}>, I{{ EntityInfo.Name }}Repository 8 | { 9 | private readonly ICurrentUser _currentUser; 10 | public {{ EntityInfo.Name }}Repository(UnitOfWorkManager unitOfWork, ICurrentUser currentUser): base(unitOfWork, currentUser) 11 | { 12 | _currentUser = currentUser; 13 | } 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/LinCms.Scaffolding/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Serilog": { 3 | "Using": [ 4 | "Serilog.Sinks.Console", 5 | "Serilog.Sinks.File" 6 | ], 7 | "MinimalLevel": { 8 | "Default": "Information", 9 | "Override": { 10 | "Microsoft": "Information", 11 | "System": "Information" 12 | } 13 | }, 14 | "WriteTo": [ 15 | { 16 | "Name": "File", 17 | "Args": { 18 | "path": "Logs/log.txt", 19 | "rollingInterval": "Day" 20 | } 21 | }, 22 | { 23 | "Name": "Console", 24 | "Args": { 25 | "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console", 26 | "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {NewLine}{Exception}" 27 | } 28 | } 29 | ] 30 | }, 31 | "SettingOptions": { 32 | "ProjectName": "LinCms", //无用 33 | "BaseDirectory": "../../../../LinCms.Core/", // LinCms.Core所在目录。 34 | "EntityFilePath": "Entities/Book.cs", //实体类所在文件位置 35 | "Areas": "Base", //区域模块名 36 | "TemplatePath": "./Templates", //相对路径,当前项目下的Templates目录 37 | "OutputDirectory": "./code-scaffolding" //可以是相对路径,也可以是绝对路径 38 | } 39 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Controllers/ApiControllerBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace LinCms.Controllers; 5 | 6 | [ApiController] 7 | public abstract class ApiControllerBase : ControllerBase 8 | { 9 | public IServiceProvider? ServiceProvider { get; set; } 10 | 11 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Controllers/Base/BaseItemController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using LinCms.Aop.Filter; 4 | using LinCms.Base.BaseItems; 5 | using LinCms.Data; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace LinCms.Controllers.Base; 9 | 10 | /// 11 | /// 数据字典-详情项 12 | /// 13 | [ApiExplorerSettings(GroupName = "base")] 14 | [Area("base")] 15 | [Route("api/base/item")] 16 | [ApiController] 17 | public class BaseItemController(IBaseItemService baseItemService) : ControllerBase 18 | { 19 | [HttpDelete("{id}")] 20 | [LinCmsAuthorize("删除字典", "字典管理")] 21 | public async Task DeleteAsync(int id) 22 | { 23 | await baseItemService.DeleteAsync(id); 24 | return UnifyResponseDto.Success(); 25 | } 26 | 27 | [HttpGet] 28 | public Task> GetListAsync([FromQuery] string typeCode) 29 | { 30 | return baseItemService.GetListAsync(typeCode); ; 31 | } 32 | 33 | [HttpGet("{id}")] 34 | public Task GetAsync(int id) 35 | { 36 | return baseItemService.GetAsync(id); 37 | } 38 | 39 | [HttpPost] 40 | [LinCmsAuthorize("新增字典", "字典管理")] 41 | public async Task CreateAsync([FromBody] CreateUpdateBaseItemDto createBaseItem) 42 | { 43 | await baseItemService.CreateAsync(createBaseItem); 44 | return UnifyResponseDto.Success("新建字典成功"); 45 | } 46 | 47 | [HttpPut("{id}")] 48 | [LinCmsAuthorize("编辑字典", "字典管理")] 49 | public async Task UpdateAsync(int id, [FromBody] CreateUpdateBaseItemDto updateBaseItem) 50 | { 51 | await baseItemService.UpdateAsync(id, updateBaseItem); 52 | return UnifyResponseDto.Success("更新字典成功"); 53 | } 54 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Controllers/Base/BaseTypeController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using LinCms.Aop.Filter; 4 | using LinCms.Base.BaseTypes; 5 | using LinCms.Data; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace LinCms.Controllers.Base; 9 | 10 | /// 11 | /// 数据字典-分类 12 | /// 13 | [ApiExplorerSettings(GroupName = "base")] 14 | [Area("base")] 15 | [Route("api/base/type")] 16 | [ApiController] 17 | public class BaseTypeController(IBaseTypeService baseTypeService) : ControllerBase 18 | { 19 | [HttpDelete("{id}")] 20 | [LinCmsAuthorize("删除字典类别", "字典类别")] 21 | public async Task DeleteAsync(int id) 22 | { 23 | await baseTypeService.DeleteAsync(id); 24 | return UnifyResponseDto.Success(); 25 | } 26 | 27 | [HttpGet] 28 | public Task> GetListAsync() 29 | { 30 | return baseTypeService.GetListAsync(); 31 | } 32 | 33 | [HttpGet("{id}")] 34 | public Task GetAsync(int id) 35 | { 36 | return baseTypeService.GetAsync(id); 37 | } 38 | 39 | [HttpPost] 40 | [LinCmsAuthorize("新增字典类别", "字典类别")] 41 | public async Task CreateAsync([FromBody] CreateUpdateBaseTypeDto createBaseType) 42 | { 43 | await baseTypeService.CreateAsync(createBaseType); 44 | return UnifyResponseDto.Success("新建类别成功"); 45 | } 46 | 47 | [HttpPut("{id}")] 48 | [LinCmsAuthorize("编辑字典类别", "字典类别")] 49 | public async Task UpdateAsync(int id, [FromBody] CreateUpdateBaseTypeDto updateBaseType) 50 | { 51 | await baseTypeService.UpdateAsync(id, updateBaseType); 52 | return UnifyResponseDto.Success("更新类别成功"); 53 | } 54 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Controllers/Blog/ArticleDraftController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | using LinCms.Blog.ArticleDrafts; 5 | 6 | using Microsoft.AspNetCore.Authorization; 7 | using Microsoft.AspNetCore.Mvc; 8 | 9 | namespace LinCms.Controllers.Blog; 10 | 11 | /// 12 | /// 随笔草稿箱,自动保存随笔 13 | /// 14 | [Area("blog")] 15 | [ApiExplorerSettings(GroupName = "blog")] 16 | [Route("api/blog/articles/draft")] 17 | [ApiController] 18 | [Authorize] 19 | public class ArticleDraftController(IArticleDraftService articleDraftService) : ControllerBase 20 | { 21 | [HttpPut("{id}")] 22 | public Task UpdateAsync(Guid id, [FromBody] UpdateArticleDraftDto updateArticleDto) 23 | { 24 | return articleDraftService.UpdateAsync(id, updateArticleDto); 25 | } 26 | 27 | /// 28 | /// 用户的随笔草稿详情 29 | /// 30 | /// 31 | /// 32 | [HttpGet("{id}")] 33 | public Task GetAsync(Guid id) 34 | { 35 | return articleDraftService.GetAsync(id); 36 | } 37 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Controllers/Blog/AuthorCenterController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using LinCms.Blog.AuthorCenter; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Microsoft.AspNetCore.Mvc; 5 | 6 | namespace LinCms.Controllers.Blog; 7 | 8 | /// 9 | /// 随笔草稿箱,自动保存随笔 10 | /// 11 | [Area("blog")] 12 | [ApiExplorerSettings(GroupName = "blog")] 13 | [Route("api/blog/author_center")] 14 | [ApiController] 15 | [Authorize] 16 | public class AuthorCenterController(IAuthorCenterService authorCenterService) : ControllerBase 17 | { 18 | [HttpGet("card")] 19 | public async Task GetArtcileCardAsync() 20 | { 21 | return await authorCenterService.GetArtcileCardAsync(); 22 | } 23 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Controllers/Blog/ClassifyController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using IGeekFan.FreeKit.Extras.Dto; 5 | using LinCms.Aop.Filter; 6 | using LinCms.Blog.Classifys; 7 | using LinCms.Data; 8 | 9 | using Microsoft.AspNetCore.Mvc; 10 | 11 | namespace LinCms.Controllers.Blog; 12 | 13 | /// 14 | /// 分类专栏 15 | /// 16 | [ApiExplorerSettings(GroupName = "blog")] 17 | [Area("blog")] 18 | [Route("api/blog/classifies")] 19 | [ApiController] 20 | public class ClassifyController(IClassifyService classifyService) : ControllerBase 21 | { 22 | 23 | [HttpGet] 24 | public Task> GetListAsync([FromQuery] ClassifySearchDto pageDto) 25 | { 26 | return classifyService.GetListAsync(pageDto); 27 | } 28 | 29 | [HttpGet("{id}")] 30 | public Task GetAsync(Guid id) 31 | { 32 | return classifyService.GetAsync(id); 33 | } 34 | 35 | [HttpPost] 36 | public async Task CreateAsync([FromBody] CreateUpdateClassifyDto createClassify) 37 | { 38 | await classifyService.CreateAsync(createClassify); 39 | return UnifyResponseDto.Success("新建分类专栏成功"); 40 | } 41 | 42 | [HttpPut("{id}")] 43 | public async Task UpdateAsync(Guid id, [FromBody] CreateUpdateClassifyDto updateClassify) 44 | { 45 | await classifyService.UpdateAsync(id, updateClassify); 46 | return UnifyResponseDto.Success("更新分类专栏成功"); 47 | } 48 | 49 | [HttpDelete("{id}")] 50 | public async Task Delete(Guid id) 51 | { 52 | await classifyService.DeleteAsync(id); 53 | return UnifyResponseDto.Success(); 54 | } 55 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Controllers/Blog/NotificationController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using DotNetCore.CAP; 4 | using IGeekFan.FreeKit.Extras.Dto; 5 | using LinCms.Blog.Notifications; 6 | using LinCms.Data; 7 | using Microsoft.AspNetCore.Mvc; 8 | 9 | namespace LinCms.Controllers.Blog; 10 | 11 | /// 12 | /// 消息通知 13 | /// 14 | [ApiExplorerSettings(GroupName = "blog")] 15 | [Area("blog")] 16 | [Route("api/blog/notifications")] 17 | [ApiController] 18 | public class NotificationController(INotificationService notificationService) : ControllerBase 19 | { 20 | [HttpGet] 21 | public async Task> GetListAsync([FromQuery] NotificationSearchDto pageDto) 22 | { 23 | return await notificationService.GetListAsync(pageDto); 24 | } 25 | 26 | [NonAction] 27 | [CapSubscribe(CreateNotificationDto.CreateOrCancelAsync)] 28 | public async Task CreateOrCancelAsync([FromBody] CreateNotificationDto createNotification) 29 | { 30 | await notificationService.CreateOrCancelAsync(createNotification); 31 | return UnifyResponseDto.Success("新建消息成功"); 32 | } 33 | 34 | [HttpPut("{id}")] 35 | public async Task SetNotificationReadAsync(Guid id) 36 | { 37 | await notificationService.SetNotificationReadAsync(id); 38 | } 39 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Controllers/Blog/UserTagController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using IGeekFan.FreeKit.Extras.Dto; 4 | using LinCms.Blog.Tags; 5 | using LinCms.Blog.UserSubscribes; 6 | using LinCms.Data; 7 | using Microsoft.AspNetCore.Authorization; 8 | using Microsoft.AspNetCore.Mvc; 9 | 10 | namespace LinCms.Controllers.Blog; 11 | 12 | /// 13 | /// 用户关注标签 14 | /// 15 | [ApiExplorerSettings(GroupName = "blog")] 16 | [Area("blog")] 17 | [Route("api/blog/user-tag")] 18 | [ApiController] 19 | [Authorize] 20 | public class UserTagController(ITagService tagService, IUserTagService userTagService) : ControllerBase 21 | { 22 | /// 23 | /// 用户关注标签 24 | /// 25 | /// 26 | [HttpPost("{tagId}")] 27 | public async Task CreateUserTagAsync(Guid tagId) 28 | { 29 | await userTagService.CreateUserTagAsync(tagId); 30 | return UnifyResponseDto.Success("关注成功"); 31 | } 32 | 33 | /// 34 | /// 取消关注标签 35 | /// 36 | /// 37 | [HttpDelete("{tagId}")] 38 | public async Task DeleteUserTagAsync(Guid tagId) 39 | { 40 | await userTagService.DeleteUserTagAsync(tagId); 41 | return UnifyResponseDto.Success("取消关注成功"); 42 | } 43 | 44 | /// 45 | /// 用户关注的标签的分页数据 46 | /// 47 | /// 48 | [HttpGet] 49 | [AllowAnonymous] 50 | public PagedResultDto GetUserTagList([FromQuery] UserSubscribeSearchDto userSubscribeDto) 51 | { 52 | return tagService.GetSubscribeTags(userSubscribeDto); 53 | } 54 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Data/Authorization/PermissionAuthorizationHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using LinCms.Cms.Permissions; 3 | using LinCms.Data.Enums; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.Filters; 8 | 9 | namespace LinCms.Data.Authorization; 10 | 11 | public class PermissionAuthorizationHandler(IPermissionService permissionService) : AuthorizationHandler 12 | { 13 | protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ModuleAuthorizationRequirement requirement) 14 | { 15 | AuthorizationFilterContext filterContext = context.Resource as AuthorizationFilterContext; 16 | 17 | if (context.User.Identity == null || !context.User.Identity.IsAuthenticated) 18 | { 19 | HandlerAuthenticationFailed(filterContext, "认证失败,请检查请求头或者重新登陆", ErrorCode.AuthenticationFailed); 20 | context.Fail(); 21 | return; 22 | } 23 | 24 | if (await permissionService.CheckPermissionAsync(requirement.Name)) 25 | { 26 | context.Succeed(requirement); 27 | return; 28 | } 29 | HandlerAuthenticationFailed(filterContext, $"您没有权限:{requirement.Module}-{requirement.Name}", ErrorCode.NoPermission); 30 | } 31 | 32 | public void HandlerAuthenticationFailed(AuthorizationFilterContext context, string errorMsg, ErrorCode errorCode) 33 | { 34 | context.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; 35 | context.Result = new JsonResult(new UnifyResponseDto(errorCode, errorMsg, context.HttpContext)); 36 | } 37 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Data/MigrationStartupTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using LinCms.FreeSql; 5 | using LinCms.Utils; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace LinCms.Data; 10 | 11 | public class MigrationStartupTask 12 | { 13 | private readonly IServiceProvider _serviceProvider; 14 | private readonly ILogger _logger; 15 | public MigrationStartupTask(IServiceProvider serviceProvider, ILogger logger) 16 | { 17 | _serviceProvider = serviceProvider; 18 | _logger = logger; 19 | } 20 | 21 | public async Task StartAsync(CancellationToken cancellationToken = default) 22 | { 23 | try 24 | { 25 | using var scope = _serviceProvider.CreateScope(); 26 | IDataSeedContributor dataSeedContributor = scope.ServiceProvider.GetRequiredService(); 27 | 28 | var permissions = ReflexHelper.GetAssemblyLinCmsAttributes(); 29 | await dataSeedContributor.SeedPermissionAsync(permissions, cancellationToken); 30 | await dataSeedContributor.InitAdminPermission(); 31 | } 32 | catch (Exception ex) 33 | { 34 | _logger.LogError($"初始化数据失败!!!{ex.Message}{ex.StackTrace}{ex.InnerException}"); 35 | }; 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 2 | USER root 3 | WORKDIR /app 4 | EXPOSE 8080 5 | EXPOSE 8081 6 | 7 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 8 | ARG BUILD_CONFIGURATION=Release 9 | WORKDIR /src 10 | COPY ["src/LinCms.Web/LinCms.Web.csproj", "src/LinCms.Web/"] 11 | COPY ["src/LinCms.Application.Contracts/LinCms.Application.Contracts.csproj", "src/LinCms.Application.Contracts/"] 12 | COPY ["src/LinCms.Core/LinCms.Core.csproj", "src/LinCms.Core/"] 13 | COPY ["src/LinCms.Application/LinCms.Application.csproj", "src/LinCms.Application/"] 14 | COPY ["src/LinCms.Infrastructure/LinCms.Infrastructure.csproj", "src/LinCms.Infrastructure/"] 15 | COPY ["src/LinCms.Plugins/LinCms.Plugins.csproj", "src/LinCms.Plugins/"] 16 | RUN dotnet restore "./src/LinCms.Web/LinCms.Web.csproj" 17 | COPY . . 18 | WORKDIR "/src/src/LinCms.Web" 19 | RUN dotnet build "./LinCms.Web.csproj" -c $BUILD_CONFIGURATION -o /app/build 20 | 21 | FROM build AS publish 22 | ARG BUILD_CONFIGURATION=Release 23 | RUN dotnet publish "./LinCms.Web.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false 24 | 25 | FROM base AS final 26 | WORKDIR /app 27 | COPY --from=publish /app/publish . 28 | ENTRYPOINT ["dotnet", "LinCms.Web.dll"] -------------------------------------------------------------------------------- /src/LinCms.Web/Fonts/JetBrainsMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoyunchong/lin-cms-dotnetcore/e00f7c6e7a0a6c187a10d5ecda90ed9c911a55ff/src/LinCms.Web/Fonts/JetBrainsMono-Bold.ttf -------------------------------------------------------------------------------- /src/LinCms.Web/Middleware/AopCacheIntercept.cs: -------------------------------------------------------------------------------- 1 | using Castle.DynamicProxy; 2 | 3 | namespace LinCms.Middleware; 4 | 5 | public class AopCacheIntercept(AopCacheAsyncIntercept interceptor) : IInterceptor 6 | { 7 | public void Intercept(IInvocation invocation) 8 | { 9 | interceptor.ToInterceptor().Intercept(invocation); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/LinCms.Web/Middleware/CacheableMethodInfoExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using LinCms.Aop.Attributes; 4 | 5 | namespace LinCms.Middleware; 6 | 7 | public static class CacheableMethodInfoExtensions 8 | { 9 | /// 10 | /// 判断方法上或类上是否有CacheableAttribute特性标签 11 | /// 12 | /// 13 | /// 14 | public static CacheableAttribute? GetCacheableAttributeOrNull(this MethodInfo methodInfo) 15 | { 16 | var attrs = methodInfo.GetCustomAttributes(true).OfType().ToArray(); 17 | if (attrs.Length > 0) 18 | { 19 | return attrs[0]; 20 | } 21 | 22 | if (methodInfo.DeclaringType == null) return null; 23 | attrs = methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true).OfType().ToArray(); 24 | if (attrs.Length > 0) 25 | { 26 | return attrs[0]; 27 | } 28 | 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/LinCms.Web/Middleware/IpLimitMiddleware.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using AspNetCoreRateLimit; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.Extensions.Logging; 5 | using Microsoft.Extensions.Options; 6 | 7 | namespace LinCms.Middleware; 8 | 9 | public class IpLimitMiddleware(RequestDelegate next, IProcessingStrategy processingStrategy, 10 | IOptions options, IIpPolicyStore policyStore, IRateLimitConfiguration config, 11 | ILogger logger) 12 | : IpRateLimitMiddleware(next, processingStrategy, options, policyStore, config, logger) 13 | { 14 | public override Task ReturnQuotaExceededResponse(HttpContext httpContext, RateLimitRule rule, string retryAfter) 15 | { 16 | httpContext.Response.Headers.Append("Access-Control-Allow-Origin", "*"); 17 | return base.ReturnQuotaExceededResponse(httpContext, rule, retryAfter); 18 | } 19 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Models/Options/GooglereCAPTCHAOptions.cs: -------------------------------------------------------------------------------- 1 | using Owl.reCAPTCHA; 2 | 3 | namespace LinCms.Models.Options; 4 | 5 | public class GooglereCAPTCHAOptions : reCAPTCHAOptions 6 | { 7 | public static string RecaptchaSettings = "RecaptchaSettings"; 8 | public string HeaderKey { get; set; } = "Google-RecaptchaToken"; 9 | public bool Enabled { get; set; } = false; 10 | public string Version { get; set; } = reCAPTCHAConsts.V3; 11 | public float MinimumScore { get; set; } = 0.9F; 12 | } -------------------------------------------------------------------------------- /src/LinCms.Web/RateLimitConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "IpRateLimiting": { 3 | //false则全局将应用限制,并且仅应用具有作为端点的规则* 。 true则限制将应用于每个端点,如{HTTP_Verb}{PATH} 4 | "EnableEndpointRateLimiting": true, 5 | //false则拒绝的API调用不会添加到调用次数计数器上 6 | "StackBlockedRequests": false, 7 | "RealIpHeader": "X-Real-IP", 8 | "ClientIdHeader": "X-ClientId", 9 | "HttpStatusCode": 200, 10 | "QuotaExceededResponse": { 11 | "Content": "{{\"code\":10140,\"message\":\"访问过于频繁,请稍后重试\",\"data\":null}}", 12 | "ContentType": "application/json", 13 | "StatusCode": 429 14 | }, 15 | "IpWhitelist": [], 16 | "EndpointWhitelist": [], 17 | "ClientWhitelist": [], 18 | "GeneralRules": [ 19 | { 20 | "Endpoint": "*", 21 | // "Endpoint": "*:/cms/test", 22 | "Period": "1s", 23 | "Limit": 10 24 | } 25 | ] 26 | }, 27 | "IpRateLimitPolicies": { 28 | "IpRules": [ 29 | { 30 | "Ip": "192.168.2.136", 31 | "Rules": [ 32 | { 33 | "Endpoint": "*", 34 | "Period": "1s", 35 | "Limit": 10 36 | } 37 | ] 38 | } 39 | ] 40 | } 41 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Startup/Configuration/AutofacModule.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using LinCms.Data; 3 | using LinCms.Data.Authorization; 4 | using Microsoft.AspNetCore.Authorization; 5 | 6 | namespace LinCms.Startup.Configuration; 7 | 8 | public class AutofacModule : Module 9 | { 10 | protected override void Load(ContainerBuilder builder) 11 | { 12 | builder.RegisterType().As().InstancePerLifetimeScope(); 13 | builder.RegisterType().As().InstancePerLifetimeScope(); 14 | 15 | //初始化种子数据 16 | builder.RegisterType().SingleInstance(); 17 | builder.RegisterBuildCallback(async (c) => await c.Resolve().StartAsync()); 18 | } 19 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Startup/Configuration/RepositoryModule.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Autofac; 3 | 4 | namespace LinCms.Startup.Configuration; 5 | 6 | /// 7 | /// 注入仓储接口 8 | /// 9 | public class RepositoryModule : Autofac.Module 10 | { 11 | protected override void Load(ContainerBuilder builder) 12 | { 13 | Assembly assemblysRepository = Assembly.Load("LinCms.Infrastructure"); 14 | builder.RegisterAssemblyTypes(assemblysRepository) 15 | .Where(a => a.Name.EndsWith("Repository")) 16 | .AsImplementedInterfaces() 17 | .InstancePerLifetimeScope(); 18 | } 19 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Startup/Configuration/ServiceModule.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using LinCms.Cms.Account; 3 | using LinCms.Cms.Files; 4 | using LinCms.Cms.Users; 5 | using LinCms.Entities; 6 | using LinCms.Middleware; 7 | 8 | namespace LinCms.Startup.Configuration; 9 | 10 | /// 11 | /// 注入Application层中的Service 12 | /// 13 | public class ServiceModule : Autofac.Module 14 | { 15 | protected override void Load(ContainerBuilder builder) 16 | { 17 | builder.RegisterType(); 18 | builder.RegisterType(); 19 | 20 | //一个接口多个实现,使用Named,区分 21 | builder.RegisterType().Named(LinFile.LocalFileService).InstancePerLifetimeScope(); 22 | builder.RegisterType().Named(LinFile.QiniuService).InstancePerLifetimeScope(); 23 | 24 | builder.RegisterType().Named(LinUserIdentity.GitHub).InstancePerLifetimeScope(); 25 | builder.RegisterType().Named(LinUserIdentity.Gitee).InstancePerLifetimeScope(); 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Utils/LogHelper.cs: -------------------------------------------------------------------------------- 1 | using IGeekFan.FreeKit.Extras.Security; 2 | using LinCms.Security; 3 | using Microsoft.AspNetCore.Http; 4 | using Serilog; 5 | 6 | namespace LinCms.Utils; 7 | 8 | public class LogHelper 9 | { 10 | public static void EnrichFromRequest(IDiagnosticContext diagnosticContext, HttpContext httpContext) 11 | { 12 | var request = httpContext.Request; 13 | if (httpContext.RequestServices.GetService(typeof(ICurrentUser)) is ICurrentUser currentUser) 14 | { 15 | diagnosticContext.Set("UserName", currentUser.UserName); 16 | diagnosticContext.Set("UserId", currentUser.FindUserId()); 17 | } 18 | // et all the common properties available for every request 19 | diagnosticContext.Set("Host", request.Host); 20 | diagnosticContext.Set("Protocol", request.Protocol); 21 | diagnosticContext.Set("Scheme", request.Scheme); 22 | 23 | // Only set it if available. You're not sending sensitive data in a querystring right?! 24 | if (request.QueryString.HasValue) 25 | { 26 | diagnosticContext.Set("QueryString", request.QueryString.Value); 27 | } 28 | 29 | // Set the content-type of the Response at this point 30 | diagnosticContext.Set("ContentType", httpContext.Response.ContentType); 31 | 32 | // Retrieve the IEndpointFeature selected for the request 33 | var endpoint = httpContext.GetEndpoint(); 34 | if (endpoint != null) 35 | { 36 | diagnosticContext.Set("EndpointName", endpoint.DisplayName); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/LinCms.Web/Utils/MultipartRequestHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LinCms.Utils; 4 | 5 | public class MultipartRequestHelper 6 | { 7 | public static bool IsMultipartContentType(string? contentType) 8 | { 9 | return !string.IsNullOrEmpty(contentType) 10 | && contentType.IndexOf("multipart/", StringComparison.OrdinalIgnoreCase) >= 0; 11 | } 12 | } -------------------------------------------------------------------------------- /src/LinCms.Web/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/LinCms.Web/wwwroot/_Illegal.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoyunchong/lin-cms-dotnetcore/e00f7c6e7a0a6c187a10d5ecda90ed9c911a55ff/src/LinCms.Web/wwwroot/_Illegal.zip -------------------------------------------------------------------------------- /test/LinCms.Test/Core/EmailSenderTest.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using IGeekFan.FreeKit.Email; 3 | using MimeKit; 4 | using Xunit; 5 | using Xunit.Abstractions; 6 | 7 | 8 | namespace LinCms.Test.Core 9 | { 10 | public class EmailSenderTest 11 | { 12 | private readonly ITestOutputHelper _testOutputHelper; 13 | private readonly IEmailSender _emailSender; 14 | public EmailSenderTest(ITestOutputHelper testOut, IEmailSender emailSender) 15 | { 16 | _testOutputHelper = testOut; 17 | _emailSender = emailSender; 18 | } 19 | 20 | [Fact] 21 | public async Task OutputTest() 22 | { 23 | var message = new MimeMessage(); 24 | message.From.Add(new MailboxAddress("igeekfan", "igeekfan@163.com")); 25 | message.To.Add(new MailboxAddress("Mrs. luoyunchong", "luoyunchong@foxmail.com")); 26 | message.Subject = "How you doin'?"; 27 | 28 | message.Body = new TextPart("plain") 29 | { 30 | Text = @"Hey Chandler, 31 | 32 | I just wanted to let you know that Monica and I were going to go play some paintball, you in? 33 | 34 | -- Joey" 35 | 36 | }; 37 | await _emailSender.SendAsync(message); 38 | 39 | await Task.CompletedTask; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test/LinCms.Test/EnumTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using LinCms.Data.Enums; 5 | using Xunit; 6 | 7 | namespace LinCms.Test 8 | { 9 | public class EnumTest 10 | { 11 | [Fact] 12 | public void ErrorCodeTest() 13 | { 14 | Dictionary errCodes = Enum.GetValues(typeof(ErrorCode)) 15 | .Cast() 16 | .ToDictionary(t => (int)t, t => t.ToString()); 17 | 18 | } 19 | 20 | [Fact] 21 | public void Test() 22 | { 23 | string path = "https://lc-gold-cdn.xitu.io/bac28828a49181c34110.png"; 24 | 25 | string name = path.Substring(path.LastIndexOf("/") + 1, path.Length - path.LastIndexOf("/") - 1); 26 | 27 | Assert.Equal("bac28828a49181c34110.png", name); 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/LinCms.Test/ExpandObjTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Dynamic; 3 | using Xunit; 4 | 5 | namespace LinCms.Test 6 | { 7 | public class ExpandObjTest 8 | { 9 | [Fact] 10 | public void ExpandObjToDictionary() 11 | { 12 | IDictionary perExpandObject = new ExpandoObject(); 13 | 14 | perExpandObject.TryAdd("Name", "1"); 15 | } 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/LinCms.Test/Md5CommonTest.cs: -------------------------------------------------------------------------------- 1 | using LinCms.Common; 2 | using Xunit; 3 | using Xunit.Abstractions; 4 | 5 | namespace LinCms.Test 6 | { 7 | public class Md5CommonTest 8 | { 9 | private readonly ITestOutputHelper _testOutputHelper; 10 | 11 | public Md5CommonTest(ITestOutputHelper testOutputHelper) 12 | { 13 | _testOutputHelper = testOutputHelper; 14 | } 15 | 16 | [Fact] 17 | public void Get32Md5One() 18 | { 19 | string result = EncryptUtil.Encrypt("123qwe"); 20 | _testOutputHelper.WriteLine(result); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/LinCms.Test/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "LinCms.Test": { 4 | "commandName": "Project", 5 | "environmentVariables": { 6 | "ASPNETCORE_ENVIRONMENT": "Development" 7 | } 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /test/LinCms.Test/Repositories/Blog/TagRepositoryTest.cs: -------------------------------------------------------------------------------- 1 | using IGeekFan.FreeKit.Extras.FreeSql; 2 | using LinCms.Blog.Tags; 3 | using LinCms.Entities.Blog; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Xunit; 6 | 7 | namespace LinCms.Test.Repositories.Blog 8 | { 9 | public class TagRepositoryTest 10 | { 11 | 12 | private readonly IAuditBaseRepository _tagRepository; 13 | private readonly IAuditBaseRepository _tagArticleRepository; 14 | 15 | public TagRepositoryTest(IAuditBaseRepository tagRepository, IAuditBaseRepository tagArticleRepository) 16 | { 17 | _tagRepository = tagRepository; 18 | _tagArticleRepository = tagArticleRepository; 19 | } 20 | 21 | [Fact] 22 | public void Get() 23 | { 24 | //LinUser关联无数据 25 | var d0 = _tagRepository.Select.Include(r => r.LinUser).ToList(); 26 | 27 | //LinUser关联有数据 28 | var d1 = _tagRepository.Select.Include(r => r.LinUser).ToList(); 29 | 30 | //其他字段都有值,LinUser关联没有数据。 31 | var d2 = _tagRepository.Select.ToList(r => new TagListDto()); 32 | var d22 = _tagRepository.Select.ToList(); ; 33 | 34 | 35 | //其他字段不取 36 | var d4 = _tagRepository.Select.ToList(r => new TagListDto() { TagName = r.TagName }); 37 | 38 | 39 | var d3 = _tagRepository.Select.ToList(r => new 40 | { 41 | OpenUserDto = new 42 | { 43 | r.LinUser.Id, 44 | r.LinUser.Username, 45 | r.LinUser.Nickname 46 | } 47 | }); 48 | 49 | 50 | } 51 | 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/LinCms.Test/Service/Blog/ArticleServiceTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using FreeSql; 4 | using LinCms.Blog.Articles; 5 | using LinCms.Data; 6 | using Xunit; 7 | 8 | namespace LinCms.Test.Service.Blog 9 | { 10 | public class ArticleServiceTest 11 | { 12 | private readonly IArticleService _articleService; 13 | private readonly UnitOfWorkManager _unitOfWorkManager; 14 | 15 | public ArticleServiceTest(IArticleService articleService, UnitOfWorkManager unitOfWorkManager) : base() 16 | { 17 | _articleService = articleService; 18 | _unitOfWorkManager = unitOfWorkManager; 19 | } 20 | 21 | [Fact] 22 | public async Task DeleteAsync() 23 | { 24 | await _articleService.DeleteAsync(new Guid("5dc93286-5e44-c190-008e-3fc74d4fcee0")); 25 | } 26 | 27 | [Fact] 28 | public async Task GetAsync() 29 | { 30 | await _articleService.GetAsync(new Guid("5deea988-b280-dff8-003c-85247943caf7")); 31 | 32 | } 33 | 34 | [Fact] 35 | public async Task GetSubscribeArticleAsyncTest() 36 | { 37 | await _articleService.GetSubscribeArticleAsync(new PageDto()); 38 | } 39 | 40 | [Fact] 41 | public async Task GetArticleAsync() 42 | { 43 | await _articleService.GetArticleAsync(new ArticleSearchDto() { TagId = Guid.NewGuid() }); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /test/LinCms.Test/Service/Cms/LogServiceTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using LinCms.Cms.Logs; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Xunit; 5 | namespace LinCms.Test.Service.Cms 6 | { 7 | 8 | public class LogServiceTest 9 | { 10 | private readonly ILogService _logService; 11 | 12 | public LogServiceTest(ILogService logService) : base() 13 | { 14 | _logService = logService; 15 | } 16 | 17 | [Fact] 18 | public void GetLoggedUsersTest() 19 | { 20 | List users = _logService.GetLoggedUsers(null); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/LinCms.Test/Utils/ToolWordTest.cs: -------------------------------------------------------------------------------- 1 | using ToolGood.Words; 2 | using Xunit; 3 | 4 | namespace LinCms.Test.Utils 5 | { 6 | public class ToolWordTest 7 | { 8 | [Fact] 9 | [System.Obsolete] 10 | public void IssuesTest_17() 11 | { 12 | var illegalWordsSearch = new IllegalWordsSearch(); 13 | string s = "中国|zg人"; 14 | illegalWordsSearch.SetKeywords(s.Split('|')); 15 | var str = illegalWordsSearch.Replace("我是中美国人厉害中国完美zg人好的", '*'); 16 | 17 | Assert.Equal("我是中美国人厉害**完美***好的", str); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/LinCms.Test/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | --------------------------------------------------------------------------------