From be8137e0aba96567d42195cd976692e9cc81c03c Mon Sep 17 00:00:00 2001 From: Peter Donker Date: Fri, 31 Jan 2025 12:27:31 +0100 Subject: [PATCH 1/5] First raw conversion --- .yo-rc.json | 26 + ...ke.Modules.Blog.sln => DotNetNuke.Blog.sln | 69 +- License.md | 10 + .../BlogML/BlogMLBlogExtendedProperties.cs | 9 + Server/Core/BlogML/BlogMLResource.cs | 112 ++ Server/Core/BlogML/BlogMLWriterBase.cs | 484 +++++++ .../Core/BlogML/Enumerators/BlogPostTypes.cs | 11 + .../Enumerators/CommentModerationTypes.cs | 10 + .../Core/BlogML/Enumerators/ContentTypes.cs | 16 + .../BlogML/Enumerators/SendTrackbackTypes.cs | 9 + Server/Core/BlogML/Pair.cs | 19 + Server/Core/BlogML/Xml/BlogMLAttachment.cs | 26 + Server/Core/BlogML/Xml/BlogMLAuthor.cs | 14 + .../Core/BlogML/Xml/BlogMLAuthorReference.cs | 14 + Server/Core/BlogML/Xml/BlogMLBlog.cs | 60 + Server/Core/BlogML/Xml/BlogMLCategory.cs | 17 + .../BlogML/Xml/BlogMLCategoryReference.cs | 14 + Server/Core/BlogML/Xml/BlogMLComment.cs | 27 + Server/Core/BlogML/Xml/BlogMLContent.cs | 93 ++ Server/Core/BlogML/Xml/BlogMLMeta.cs | 18 + Server/Core/BlogML/Xml/BlogMLNode.cs | 26 + Server/Core/BlogML/Xml/BlogMLPost.cs | 168 +++ Server/Core/BlogML/Xml/BlogMLSerializer.cs | 67 + Server/Core/BlogML/Xml/BlogMLTrackback.cs | 14 + Server/Core/Common/BlogContextInfo.cs | 394 ++++++ Server/Core/Common/BlogModuleBase.cs | 207 +++ Server/Core/Common/DynatreeItem.cs | 34 + Server/Core/Common/Extensions.cs | 790 +++++++++++ Server/Core/Common/Globals.cs | 377 ++++++ Server/Core/Common/Image.cs | 221 ++++ Server/Core/Common/LocalizedText.cs | 269 ++++ Server/Core/Common/ModuleSettings.cs | 415 ++++++ Server/Core/Common/ModuleUrls.cs | 266 ++++ Server/Core/Common/PostBodyAndSummary.cs | 221 ++++ Server/Core/Common/ViewSettings.cs | 374 ++++++ Server/Core/Common/WebPage.cs | 119 ++ Server/Core/Data/DataProvider.cs | 30 + Server/Core/Data/DataProvider_CMD.cs | 68 + Server/Core/Data/DataProvider_CRUD.cs | 91 ++ Server/Core/Data/DataProvider_FK.cs | 46 + Server/Core/Data/SqlDataProvider.cs | 31 + Server/Core/Data/SqlDataProvider_CMD.cs | 210 +++ Server/Core/Data/SqlDataProvider_CRUD.cs | 221 ++++ Server/Core/Data/SqlDataProvider_FK.cs | 59 + .../Core/DotNetNuke.Modules.Blog.Core.csproj | 30 + .../Core/Entities/Blogs/BlogCalendarInfo.cs | 219 ++++ Server/Core/Entities/Blogs/BlogInfo.cs | 91 ++ .../Entities/Blogs/BlogInfo_Interfaces.cs | 583 +++++++++ .../Entities/Blogs/BlogInfo_Properties.cs | 203 +++ Server/Core/Entities/Blogs/BlogsController.cs | 94 ++ .../Entities/Blogs/BlogsController_CRUD.cs | 64 + .../Core/Entities/Blogs/BlogsController_FK.cs | 33 + .../Entities/Blogs/BlogsController_Service.cs | 221 ++++ Server/Core/Entities/Comments/CommentInfo.cs | 30 + .../Comments/CommentInfo_Interfaces.cs | 457 +++++++ .../Comments/CommentInfo_Properties.cs | 82 ++ .../Entities/Comments/CommentsController.cs | 142 ++ .../Comments/CommentsController_CRUD.cs | 55 + .../Comments/CommentsController_FK.cs | 40 + .../Comments/CommentsController_Service.cs | 505 ++++++++ .../LegacyUrls/LegacyUrlInfo_Interfaces.cs | 74 ++ .../LegacyUrls/LegacyUrlInfo_Properties.cs | 55 + .../LegacyUrls/LegacyUrlsController_CRUD.cs | 39 + Server/Core/Entities/Posts/PostAuthor.cs | 182 +++ Server/Core/Entities/Posts/PostInfo.cs | 131 ++ .../Entities/Posts/PostInfo_Interfaces.cs | 496 +++++++ .../Entities/Posts/PostInfo_Properties.cs | 200 +++ Server/Core/Entities/Posts/PostsController.cs | 275 ++++ .../Entities/Posts/PostsController_CRUD.cs | 71 + .../Entities/Posts/PostsController_Service.cs | 101 ++ Server/Core/Entities/Terms/TermInfo.cs | 367 ++++++ Server/Core/Entities/Terms/TermsController.cs | 219 ++++ .../Entities/Terms/TermsController_Service.cs | 70 + .../BlogModuleController_Portable.cs | 242 ++++ .../BlogModuleController_Searchable.cs | 104 ++ .../BlogModuleController_Upgradeable.cs | 48 + Server/Core/Integration/FileController.cs | 90 ++ Server/Core/Integration/Integration.cs | 62 + Server/Core/Integration/JournalController.cs | 208 +++ .../Integration/NotificationController.cs | 344 +++++ Server/Core/Integration/NotificationKey.cs | 60 + .../Services/NotificationServiceController.cs | 146 +++ Server/Core/Integration/SiteMapProvider.cs | 73 ++ Server/Core/Rss/BlogRssFeed.cs | 455 +++++++ Server/Core/Rss/StringWriterWithEncoding.cs | 52 + Server/Core/Security/BlogUser.cs | 171 +++ Server/Core/Security/ContextSecurity.cs | 356 +++++ .../Security/Controls/BlogPermissionsGrid.cs | 690 ++++++++++ .../Core/Security/Controls/PermissionsGrid.cs | 1150 +++++++++++++++++ .../Permissions/BlogPermissionCollection.cs | 271 ++++ .../Permissions/BlogPermissionInfo.cs | 147 +++ .../BlogPermissionInfo_Interfaces.cs | 328 +++++ .../BlogPermissionInfo_Properties.cs | 54 + .../Permissions/BlogPermissionsController.cs | 271 ++++ .../BlogPermissionsController_CRUD.cs | 40 + .../Permissions/PermissionCollection.cs | 216 ++++ .../Permissions/PermissionInfo_Properties.cs | 53 + .../Permissions/PermissionsController.cs | 47 + Server/Core/Security/Security.cs | 42 + .../Core/Services/BlogAuthorizeAttribute.cs | 165 +++ Server/Core/Services/BlogRouteMapper.cs | 80 ++ Server/Core/Services/ModulesController.cs | 174 +++ Server/Core/Services/RSSController.cs | 58 + .../Services/TrackAndPingBackController.cs | 270 ++++ Server/Core/Services/WLW/BlogPostException.cs | 46 + Server/Core/Services/WLW/Blogger/IBlogger.cs | 51 + .../Services/WLW/MetaWeblog/IMetaWeblog.cs | 288 +++++ .../WLW/MoveableType/IMoveableType.cs | 61 + .../Core/Services/WLW/WordPress/IWordPress.cs | 59 + .../Core/Templating/BaseCustomTokenReplace.cs | 216 ++++ Server/Core/Templating/BaseTokenReplace.cs | 186 +++ Server/Core/Templating/BlogTokenReplace.cs | 301 +++++ Server/Core/Templating/CustomParameters.cs | 88 ++ Server/Core/Templating/GenericTokenReplace.cs | 76 ++ Server/Core/Templating/LazyLoadingUser.cs | 152 +++ Server/Core/Templating/Resources.cs | 91 ++ Server/Core/Templating/Template.cs | 334 +++++ Server/Core/Templating/TemplateController.cs | 107 ++ Server/Core/Templating/TemplateManager.cs | 105 ++ .../Core/Templating/TemplateRepeaterItem.cs | 101 ++ Server/Core/Templating/TemplateSetting.cs | 47 + .../Core/Templating/TemplateSettingValue.cs | 36 + Server/Core/Templating/TemplateSettings.cs | 56 + Server/Core/Templating/TokenReplace.cs | 434 +++++++ Server/Core/Templating/ViewTemplate.cs | 178 +++ nuget.config | 7 + tslint.json | 7 + 127 files changed, 20370 insertions(+), 29 deletions(-) create mode 100644 .yo-rc.json rename DotNetNuke.Modules.Blog.sln => DotNetNuke.Blog.sln (65%) create mode 100644 License.md create mode 100644 Server/Core/BlogML/BlogMLBlogExtendedProperties.cs create mode 100644 Server/Core/BlogML/BlogMLResource.cs create mode 100644 Server/Core/BlogML/BlogMLWriterBase.cs create mode 100644 Server/Core/BlogML/Enumerators/BlogPostTypes.cs create mode 100644 Server/Core/BlogML/Enumerators/CommentModerationTypes.cs create mode 100644 Server/Core/BlogML/Enumerators/ContentTypes.cs create mode 100644 Server/Core/BlogML/Enumerators/SendTrackbackTypes.cs create mode 100644 Server/Core/BlogML/Pair.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLAttachment.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLAuthor.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLAuthorReference.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLBlog.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLCategory.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLCategoryReference.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLComment.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLContent.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLMeta.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLNode.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLPost.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLSerializer.cs create mode 100644 Server/Core/BlogML/Xml/BlogMLTrackback.cs create mode 100644 Server/Core/Common/BlogContextInfo.cs create mode 100644 Server/Core/Common/BlogModuleBase.cs create mode 100644 Server/Core/Common/DynatreeItem.cs create mode 100644 Server/Core/Common/Extensions.cs create mode 100644 Server/Core/Common/Globals.cs create mode 100644 Server/Core/Common/Image.cs create mode 100644 Server/Core/Common/LocalizedText.cs create mode 100644 Server/Core/Common/ModuleSettings.cs create mode 100644 Server/Core/Common/ModuleUrls.cs create mode 100644 Server/Core/Common/PostBodyAndSummary.cs create mode 100644 Server/Core/Common/ViewSettings.cs create mode 100644 Server/Core/Common/WebPage.cs create mode 100644 Server/Core/Data/DataProvider.cs create mode 100644 Server/Core/Data/DataProvider_CMD.cs create mode 100644 Server/Core/Data/DataProvider_CRUD.cs create mode 100644 Server/Core/Data/DataProvider_FK.cs create mode 100644 Server/Core/Data/SqlDataProvider.cs create mode 100644 Server/Core/Data/SqlDataProvider_CMD.cs create mode 100644 Server/Core/Data/SqlDataProvider_CRUD.cs create mode 100644 Server/Core/Data/SqlDataProvider_FK.cs create mode 100644 Server/Core/DotNetNuke.Modules.Blog.Core.csproj create mode 100644 Server/Core/Entities/Blogs/BlogCalendarInfo.cs create mode 100644 Server/Core/Entities/Blogs/BlogInfo.cs create mode 100644 Server/Core/Entities/Blogs/BlogInfo_Interfaces.cs create mode 100644 Server/Core/Entities/Blogs/BlogInfo_Properties.cs create mode 100644 Server/Core/Entities/Blogs/BlogsController.cs create mode 100644 Server/Core/Entities/Blogs/BlogsController_CRUD.cs create mode 100644 Server/Core/Entities/Blogs/BlogsController_FK.cs create mode 100644 Server/Core/Entities/Blogs/BlogsController_Service.cs create mode 100644 Server/Core/Entities/Comments/CommentInfo.cs create mode 100644 Server/Core/Entities/Comments/CommentInfo_Interfaces.cs create mode 100644 Server/Core/Entities/Comments/CommentInfo_Properties.cs create mode 100644 Server/Core/Entities/Comments/CommentsController.cs create mode 100644 Server/Core/Entities/Comments/CommentsController_CRUD.cs create mode 100644 Server/Core/Entities/Comments/CommentsController_FK.cs create mode 100644 Server/Core/Entities/Comments/CommentsController_Service.cs create mode 100644 Server/Core/Entities/LegacyUrls/LegacyUrlInfo_Interfaces.cs create mode 100644 Server/Core/Entities/LegacyUrls/LegacyUrlInfo_Properties.cs create mode 100644 Server/Core/Entities/LegacyUrls/LegacyUrlsController_CRUD.cs create mode 100644 Server/Core/Entities/Posts/PostAuthor.cs create mode 100644 Server/Core/Entities/Posts/PostInfo.cs create mode 100644 Server/Core/Entities/Posts/PostInfo_Interfaces.cs create mode 100644 Server/Core/Entities/Posts/PostInfo_Properties.cs create mode 100644 Server/Core/Entities/Posts/PostsController.cs create mode 100644 Server/Core/Entities/Posts/PostsController_CRUD.cs create mode 100644 Server/Core/Entities/Posts/PostsController_Service.cs create mode 100644 Server/Core/Entities/Terms/TermInfo.cs create mode 100644 Server/Core/Entities/Terms/TermsController.cs create mode 100644 Server/Core/Entities/Terms/TermsController_Service.cs create mode 100644 Server/Core/Integration/BlogModuleController_Portable.cs create mode 100644 Server/Core/Integration/BlogModuleController_Searchable.cs create mode 100644 Server/Core/Integration/BlogModuleController_Upgradeable.cs create mode 100644 Server/Core/Integration/FileController.cs create mode 100644 Server/Core/Integration/Integration.cs create mode 100644 Server/Core/Integration/JournalController.cs create mode 100644 Server/Core/Integration/NotificationController.cs create mode 100644 Server/Core/Integration/NotificationKey.cs create mode 100644 Server/Core/Integration/Services/NotificationServiceController.cs create mode 100644 Server/Core/Integration/SiteMapProvider.cs create mode 100644 Server/Core/Rss/BlogRssFeed.cs create mode 100644 Server/Core/Rss/StringWriterWithEncoding.cs create mode 100644 Server/Core/Security/BlogUser.cs create mode 100644 Server/Core/Security/ContextSecurity.cs create mode 100644 Server/Core/Security/Controls/BlogPermissionsGrid.cs create mode 100644 Server/Core/Security/Controls/PermissionsGrid.cs create mode 100644 Server/Core/Security/Permissions/BlogPermissionCollection.cs create mode 100644 Server/Core/Security/Permissions/BlogPermissionInfo.cs create mode 100644 Server/Core/Security/Permissions/BlogPermissionInfo_Interfaces.cs create mode 100644 Server/Core/Security/Permissions/BlogPermissionInfo_Properties.cs create mode 100644 Server/Core/Security/Permissions/BlogPermissionsController.cs create mode 100644 Server/Core/Security/Permissions/BlogPermissionsController_CRUD.cs create mode 100644 Server/Core/Security/Permissions/PermissionCollection.cs create mode 100644 Server/Core/Security/Permissions/PermissionInfo_Properties.cs create mode 100644 Server/Core/Security/Permissions/PermissionsController.cs create mode 100644 Server/Core/Security/Security.cs create mode 100644 Server/Core/Services/BlogAuthorizeAttribute.cs create mode 100644 Server/Core/Services/BlogRouteMapper.cs create mode 100644 Server/Core/Services/ModulesController.cs create mode 100644 Server/Core/Services/RSSController.cs create mode 100644 Server/Core/Services/TrackAndPingBackController.cs create mode 100644 Server/Core/Services/WLW/BlogPostException.cs create mode 100644 Server/Core/Services/WLW/Blogger/IBlogger.cs create mode 100644 Server/Core/Services/WLW/MetaWeblog/IMetaWeblog.cs create mode 100644 Server/Core/Services/WLW/MoveableType/IMoveableType.cs create mode 100644 Server/Core/Services/WLW/WordPress/IWordPress.cs create mode 100644 Server/Core/Templating/BaseCustomTokenReplace.cs create mode 100644 Server/Core/Templating/BaseTokenReplace.cs create mode 100644 Server/Core/Templating/BlogTokenReplace.cs create mode 100644 Server/Core/Templating/CustomParameters.cs create mode 100644 Server/Core/Templating/GenericTokenReplace.cs create mode 100644 Server/Core/Templating/LazyLoadingUser.cs create mode 100644 Server/Core/Templating/Resources.cs create mode 100644 Server/Core/Templating/Template.cs create mode 100644 Server/Core/Templating/TemplateController.cs create mode 100644 Server/Core/Templating/TemplateManager.cs create mode 100644 Server/Core/Templating/TemplateRepeaterItem.cs create mode 100644 Server/Core/Templating/TemplateSetting.cs create mode 100644 Server/Core/Templating/TemplateSettingValue.cs create mode 100644 Server/Core/Templating/TemplateSettings.cs create mode 100644 Server/Core/Templating/TokenReplace.cs create mode 100644 Server/Core/Templating/ViewTemplate.cs create mode 100644 nuget.config create mode 100644 tslint.json diff --git a/.yo-rc.json b/.yo-rc.json new file mode 100644 index 00000000..f7a4977a --- /dev/null +++ b/.yo-rc.json @@ -0,0 +1,26 @@ +{ + "generator-dotnetnuke": { + "promptValues": { + "projType": "library", + "dnnVersion": "9.13.0", + "npm": true, + "projectname": "Blog", + "projectdescription": "The DotNetNuke Blog module is an easy to use content publishing module that is tightly integrated with the core DotNetNuke framework. It can be used in single or multi-author environments and also permits content authoring using off-site tools such as Windows Live Writer.", + "yourname": "Peter Donker", + "email": "peter@bring2mind.net", + "companyfull": "DotNetNuke Community", + "companyshort": "DotNetNuke", + "companyUrl": "www.dnncommunity.org", + "dnnHost": "http://dnndev.me", + "dnnRoot": "DL/", + "namespace": "DotNetNuke.Modules.Blog", + "Name": "Core", + "Namespace": "DotNetNuke.Blog.Core", + "Separate": false + }, + "Company": "DotNetNuke", + "Project": "Blog", + "Namespace": "DotNetNuke.Blog", + "Solution": "DotNetNuke.Blog" + } +} diff --git a/DotNetNuke.Modules.Blog.sln b/DotNetNuke.Blog.sln similarity index 65% rename from DotNetNuke.Modules.Blog.sln rename to DotNetNuke.Blog.sln index 412f6f3e..f698b688 100644 --- a/DotNetNuke.Modules.Blog.sln +++ b/DotNetNuke.Blog.sln @@ -1,29 +1,40 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.1.32328.378 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "DotNetNuke.Modules.Blog", "Server\Blog\DotNetNuke.Modules.Blog.vbproj", "{4E2BCA3B-927C-4AF2-9999-B1C074FD0539}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Build", "build\Build.csproj", "{22A9DE4E-9CFD-4ABA-8C82-87D1C22F2FD9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4E2BCA3B-927C-4AF2-9999-B1C074FD0539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4E2BCA3B-927C-4AF2-9999-B1C074FD0539}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4E2BCA3B-927C-4AF2-9999-B1C074FD0539}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4E2BCA3B-927C-4AF2-9999-B1C074FD0539}.Release|Any CPU.Build.0 = Release|Any CPU - {22A9DE4E-9CFD-4ABA-8C82-87D1C22F2FD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {22A9DE4E-9CFD-4ABA-8C82-87D1C22F2FD9}.Release|Any CPU.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A4DC134D-8514-4096-8B8B-8AB593421020} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32328.378 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "DotNetNuke.Modules.Blog", "Server\Blog\DotNetNuke.Modules.Blog.vbproj", "{4E2BCA3B-927C-4AF2-9999-B1C074FD0539}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Build", "build\Build.csproj", "{22A9DE4E-9CFD-4ABA-8C82-87D1C22F2FD9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{2D9F0B28-4FD1-466D-9547-DE5524D61990}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetNuke.Blog.Core", "Server\Core\DotNetNuke.Blog.Core.csproj", "{18CBD81C-C31C-465D-8865-70957DF4711C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4E2BCA3B-927C-4AF2-9999-B1C074FD0539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E2BCA3B-927C-4AF2-9999-B1C074FD0539}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E2BCA3B-927C-4AF2-9999-B1C074FD0539}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E2BCA3B-927C-4AF2-9999-B1C074FD0539}.Release|Any CPU.Build.0 = Release|Any CPU + {22A9DE4E-9CFD-4ABA-8C82-87D1C22F2FD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22A9DE4E-9CFD-4ABA-8C82-87D1C22F2FD9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18CBD81C-C31C-465D-8865-70957DF4711C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18CBD81C-C31C-465D-8865-70957DF4711C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18CBD81C-C31C-465D-8865-70957DF4711C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18CBD81C-C31C-465D-8865-70957DF4711C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A4DC134D-8514-4096-8B8B-8AB593421020} + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {18CBD81C-C31C-465D-8865-70957DF4711C} = {2D9F0B28-4FD1-466D-9547-DE5524D61990} + EndGlobalSection +EndGlobal diff --git a/License.md b/License.md new file mode 100644 index 00000000..5c100fc3 --- /dev/null +++ b/License.md @@ -0,0 +1,10 @@ +Copyright (c) 2025 DotNetNuke, All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/Server/Core/BlogML/BlogMLBlogExtendedProperties.cs b/Server/Core/BlogML/BlogMLBlogExtendedProperties.cs new file mode 100644 index 00000000..b10ca729 --- /dev/null +++ b/Server/Core/BlogML/BlogMLBlogExtendedProperties.cs @@ -0,0 +1,9 @@ + +namespace DotNetNuke.Modules.Blog.BlogML +{ + public class BlogMLBlogExtendedProperties + { + public static readonly string CommentModeration = "CommentModeration"; + public static readonly string EnableSendingTrackbacks = "SendTrackback"; + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/BlogMLResource.cs b/Server/Core/BlogML/BlogMLResource.cs new file mode 100644 index 00000000..90d4c18e --- /dev/null +++ b/Server/Core/BlogML/BlogMLResource.cs @@ -0,0 +1,112 @@ +using System; +using System.IO; +using System.Xml; +using System.Xml.Schema; + +namespace DotNetNuke.Modules.Blog.BlogML +{ + + public class BlogMLResource + { + // TODO: Update to .NET 2.0 + public static Stream GetSchemaStream() + { + var stream = typeof(BlogMLResource).Assembly.GetManifestResourceStream("BlogML.BlogML.xsd"); + if (stream is null) + { + throw new InvalidOperationException("Schema not found"); + } + return stream; + } + + public static XmlSchema GetSchema() + { + + var schema = XmlSchema.Read(GetSchemaStream(), new ValidationEventHandler(ValidationEvent)); + return schema; + + } + + private static void ValidationEvent(object sender, ValidationEventArgs e) + { + string message = string.Format("Validation {0}: {1}", e.Severity, e.Message); + throw new InvalidOperationException(message); + } + + + public static void Validate(string inputUri) + { + Validate(inputUri, null); + } + + + public static void Validate(string inputUri, ValidationEventHandler validationHandler) + { + XmlTextReader reader = null; + try + { + reader = new XmlTextReader(inputUri); + Validate(reader, validationHandler); + } + finally + { + if (reader is not null) + { + reader.Close(); + + } + } + } + + public static void Validate(XmlTextReader reader) + { + Validate(reader, null); + } + + + public static void Validate(XmlTextReader treader, ValidationEventHandler validationHandler) + { + XmlReaderSettings validator = null; + try + { + validator = new XmlReaderSettings(); + var schema = GetSchema(); + validator.Schemas.Add(schema); + validator.ValidationType = ValidationType.Schema; + + + if (validationHandler is not null) + { + validator.ValidationEventHandler += validationHandler; + } + else + { + validator.ValidationEventHandler += new ValidationEventHandler(ValidationEvent); + } + + var objXmlReader = XmlReader.Create(treader, validator); + + + while (objXmlReader.Read()) + { + } + } + catch (Exception ex) + { + // Console.WriteLine(ex.ToString()) + throw; + } + finally + { + if (validationHandler is not null) + { + validator.ValidationEventHandler -= validationHandler; + } + else + { + validator.ValidationEventHandler -= new ValidationEventHandler(ValidationEvent); + } + } + } + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/BlogMLWriterBase.cs b/Server/Core/BlogML/BlogMLWriterBase.cs new file mode 100644 index 00000000..adfd8d5d --- /dev/null +++ b/Server/Core/BlogML/BlogMLWriterBase.cs @@ -0,0 +1,484 @@ +using System; +using System.IO; +using System.Text.RegularExpressions; +using System.Xml; +using DotNetNuke.Modules.Blog.BlogML.Xml; + +namespace DotNetNuke.Modules.Blog.BlogML +{ + + public abstract class BlogMLWriterBase + { + private const string BlogMLNamespace = "http://www.blogml.com/2006/09/BlogML"; + + protected XmlWriter Writer + { + get + { + return m_Writer; + } + private set + { + m_Writer = value; + } + } + private XmlWriter m_Writer; + + public void Write(XmlWriter writer__1) + { + Writer = writer__1; + + // Write the XML delcaration. + writer__1.WriteStartDocument(); + + try + { + InternalWriteBlog(); + } + finally + { + Writer = null; + } + } + + protected abstract void InternalWriteBlog(); + + #region WriteStartBlog + + + protected void WriteStartBlog(string title, string subTitle, string rootUrl) + { + WriteStartBlog(title, ContentTypes.Text, subTitle, ContentTypes.Text, rootUrl, DateTime.Now); + } + + protected void WriteStartBlog(string title, string subTitle, string rootUrl, DateTime dateCreated) + { + WriteStartBlog(title, ContentTypes.Text, subTitle, ContentTypes.Text, rootUrl, dateCreated); + } + + protected void WriteStartBlog(string title, ContentTypes titleContentType, string subTitle, ContentTypes subTitleContentType, string rootUrl, DateTime dateCreated) + { + // WriteStartElement("blog"); + Writer.WriteStartElement("blog", BlogMLNamespace); + // fixes bug in Work Item 2004 + WriteAttributeStringRequired("root-url", rootUrl); + WriteAttributeString("date-created", FormatDateTime(dateCreated)); + + // Write the default namespace, identified as xmlns with no prefix + Writer.WriteAttributeString("xmlns", null, null, "http://www.blogml.com/2006/09/BlogML"); + Writer.WriteAttributeString("xmlns", "xs", null, "http://www.w3.org/2001/XMLSchema"); + + WriteContent("title", BlogMLContent.Create(title, titleContentType)); + WriteContent("sub-title", BlogMLContent.Create(subTitle, subTitleContentType)); + } + + #endregion + + protected void WriteStartElement(string tag) + { + Writer.WriteStartElement(tag); + } + + + protected void WriteEndElement() + { + Writer.WriteEndElement(); + } + + + #region Extended Properties + + protected void WriteStartExtendedProperties() + { + WriteStartElement("extended-properties"); + } + + protected void WriteExtendedProperty(string name, string value) + { + WriteStartElement("property"); + WriteAttributeString("name", name); + WriteAttributeString("value", value); + WriteEndElement(); + } + + #endregion + + + protected void WriteAuthor(string id, string name, string email, DateTime dateCreated, DateTime dateModified, bool approved) + { + WriteStartElement("author"); + WriteNodeAttributes(id, dateCreated, dateModified, approved); + WriteAttributeString("email", email); + WriteContent("title", BlogMLContent.Create(name, ContentTypes.Text)); + WriteEndElement(); + } + + + protected void WriteCategory(string id, string title, DateTime dateCreated, DateTime dateModified, bool approved, string description, string parentRef) + { + WriteCategory(id, title, ContentTypes.Text, dateCreated, dateModified, approved, description, parentRef); + } + + + protected void WriteCategory(string id, string title, ContentTypes titleContentType, DateTime dateCreated, DateTime dateModified, bool approved, string description, string parentRef) + { + WriteStartElement("category"); + WriteNodeAttributes(id, dateCreated, dateModified, approved); + WriteAttributeString("description", description); + WriteAttributeString("parentref", parentRef); + WriteContent("title", BlogMLContent.Create(title, titleContentType)); + WriteEndElement(); + } + + protected void WriteAuthorReference(string refId) + { + WriteStartElement("author"); + WriteAttributeStringRequired("ref", refId); + WriteEndElement(); + } + + protected void WriteCategoryReference(string refId) + { + WriteStartElement("category"); + WriteAttributeStringRequired("ref", refId); + WriteEndElement(); + } + + protected void WriteStartAuthors() + { + WriteStartElement("authors"); + } + + protected void WriteStartCategories() + { + WriteStartElement("categories"); + } + + + protected void WriteStartPosts() + { + WriteStartElement("posts"); + } + + + protected void WriteStartTrackbacks() + { + WriteStartElement("trackbacks"); + } + + + protected void WriteStartAttachments() + { + WriteStartElement("attachments"); + } + + + protected void WriteNodeAttributes(string id, DateTime dateCreated, DateTime dateModified, bool approved) + { + WriteAttributeString("id", id); + WriteAttributeString("date-created", FormatDateTime(dateCreated)); + WriteAttributeString("date-modified", FormatDateTime(dateModified)); + WriteAttributeString("approved", approved ? "true" : "false"); + } + + + protected string FormatDateTime(DateTime date) + { + return date.ToUniversalTime().ToString("s"); + } + + protected void WriteStartPost(string id, string title, DateTime dateCreated, DateTime dateModified, bool approved, string content, string postUrl) + { + WriteStartPost(id, title, ContentTypes.Text, dateCreated, dateModified, approved, content, ContentTypes.Text, postUrl, 0U, false, null, ContentTypes.Text, BlogPostTypes.Normal, string.Empty); + + } + + protected void WriteStartPost(string id, string title, DateTime dateCreated, DateTime dateModified, bool approved, string content, string postUrl, uint views, BlogPostTypes blogpostType, string postName) + { + WriteStartPost(id, title, ContentTypes.Text, dateCreated, dateModified, approved, content, ContentTypes.Text, postUrl, views, false, null, ContentTypes.Text, blogpostType, postName); + + } + + protected void WriteStartPost(string id, string title, DateTime dateCreated, DateTime dateModified, bool approved, string content, string postUrl, uint views, string excerpt, BlogPostTypes blogpostType, string postName) + { + WriteStartPost(id, title, ContentTypes.Text, dateCreated, dateModified, approved, content, ContentTypes.Text, postUrl, views, true, excerpt, ContentTypes.Text, blogpostType, postName); + + } + + protected void WriteStartPost(string id, BlogMLContent title, DateTime dateCreated, DateTime dateModified, bool approved, BlogMLContent content, string postUrl, uint views, bool hasexcerpt, BlogMLContent excerpt, BlogPostTypes blogpostType, string postName) + { + WriteStartElement("post"); + WriteNodeAttributes(id, dateCreated, dateModified, approved); + WriteAttributeString("post-url", postUrl); + WriteAttributeStringRequired("type", blogpostType.ToString().ToLower()); + WriteAttributeStringRequired("hasexcerpt", hasexcerpt.ToString().ToLower()); + WriteAttributeStringRequired("views", views.ToString()); + WriteContent("title", title); + WriteContent("content", content); + if (postName is not null) + { + WriteContent("post-name", BlogMLContent.Create(postName, ContentTypes.Text)); + } + if (hasexcerpt) + { + WriteContent("excerpt", excerpt); + } + } + + protected void WriteStartPost(string id, string title, ContentTypes titleContentType, DateTime dateCreated, DateTime dateModified, bool approved, string content, ContentTypes postContentType, string postUrl, uint views, bool hasexcerpt, string excerpt, ContentTypes excerptContentType, BlogPostTypes blogpostType, string postName) + + { + WriteStartElement("post"); + WriteNodeAttributes(id, dateCreated, dateModified, approved); + WriteAttributeString("post-url", postUrl); + WriteAttributeStringRequired("type", blogpostType.ToString().ToLower()); + WriteAttributeStringRequired("hasexcerpt", hasexcerpt.ToString().ToLower()); + WriteAttributeStringRequired("views", views.ToString()); + WriteContent("title", BlogMLContent.Create(title, titleContentType)); + WriteContent("content", BlogMLContent.Create(content, postContentType)); + if (postName is not null) + { + WriteContent("post-name", BlogMLContent.Create(postName, ContentTypes.Text)); + } + if (hasexcerpt) + { + WriteContent("excerpt", BlogMLContent.Create(excerpt, excerptContentType)); + } + } + + protected void WriteStartComments() + { + WriteStartElement("comments"); + } + + + protected void WriteComment(string id, string title, DateTime dateCreated, DateTime dateModified, bool approved, string userName, string userEmail, string userUrl, string content) + { + WriteComment(id, title, ContentTypes.Text, dateCreated, dateModified, approved, userName, userEmail, userUrl, content, ContentTypes.Text); + } + + protected void WriteComment(string id, BlogMLContent title, DateTime dateCreated, DateTime dateModified, bool approved, string userName, string userEmail, string userUrl, BlogMLContent content) + { + WriteStartElement("comment"); + WriteNodeAttributes(id, dateCreated, dateModified, approved); + WriteAttributeStringRequired("user-name", userName ?? ""); + WriteAttributeString("user-url", userUrl ?? ""); + WriteAttributeString("user-email", userEmail ?? ""); + WriteContent("title", title); + WriteContent("content", content); + WriteEndElement(); + } + + + protected void WriteComment(string id, string title, ContentTypes titleContentType, DateTime dateCreated, DateTime dateModified, bool approved, string userName, string userEmail, string userUrl, string content, ContentTypes commentContentType) + { + WriteStartElement("comment"); + WriteNodeAttributes(id, dateCreated, dateModified, approved); + WriteAttributeStringRequired("user-name", userName ?? ""); + WriteAttributeString("user-url", userUrl ?? ""); + WriteAttributeString("user-email", userEmail ?? ""); + WriteContent("title", BlogMLContent.Create(title, titleContentType)); + WriteContent("content", BlogMLContent.Create(content, commentContentType)); + WriteEndElement(); + } + + + protected void WriteTrackback(string id, string title, DateTime dateCreated, DateTime dateModified, bool approved, string url) + { + WriteTrackback(id, title, ContentTypes.Text, dateCreated, dateModified, approved, url); + } + + + protected void WriteTrackback(string id, string title, ContentTypes titleContentType, DateTime dateCreated, DateTime dateModified, bool approved, string url) + { + WriteStartElement("trackback"); + WriteNodeAttributes(id, dateCreated, dateModified, approved); + WriteAttributeStringRequired("url", url); + WriteContent("title", BlogMLContent.Create(title, titleContentType)); + WriteEndElement(); + } + + + protected void WriteAttributeStringRequired(string name, string value) + { + if (string.IsNullOrEmpty(value)) + { + throw new ArgumentNullException("value", name); + } + Writer.WriteAttributeString(name, value); + } + + + protected void WriteAttributeString(string name, string value) + { + if (!string.IsNullOrEmpty(value)) + { + Writer.WriteAttributeString(name, value); + } + } + + protected void WriteContent(string elementName, BlogMLContent content) + { + WriteStartElement(elementName); + string contentType = (Enum.GetName(typeof(ContentTypes), content.ContentType) ?? "text").ToLowerInvariant(); + WriteAttributeString("type", contentType); + Writer.WriteCData(content.Text ?? string.Empty); + WriteEndElement(); + } + + protected void WriteAttachment(string externalUri, string mimeType, string fullUrl) + { + WriteAttachment(fullUrl, 0d, mimeType, externalUri, false, null); + } + + protected void WriteAttachment(string embeddedUrl, string mimeType, Stream inputStream) + { + using (var reader = new BinaryReader(inputStream)) + { + reader.BaseStream.Position = 0L; + byte[] data = reader.ReadBytes((int)inputStream.Length); + WriteAttachment(embeddedUrl, data.Length, mimeType, null, true, data); + } + } + + protected void WriteAttachment(string embeddedUrl, double size, string mimeType, string externalUri, bool embedded, byte[] data) + { + WriteStartElement("attachment"); + + try + { + + WriteAttributeStringRequired("url", embeddedUrl); + + if (size > 0d) + { + WriteAttributeStringRequired("size", size.ToString()); + } + + if (mimeType is not null) + { + WriteAttributeStringRequired("mime-type", mimeType); + } + + if (!string.IsNullOrEmpty(externalUri)) + { + WriteAttributeStringRequired("external-uri", externalUri); + } + + WriteAttributeString("embedded", embedded ? "true" : "false"); + + if (embedded) + { + Writer.WriteBase64(data, 0, data.Length); + } + } + finally + { + WriteEndElement(); + } + + } + + + internal void CopyStream(Stream src, Stream dst) + { + var buf = new byte[4096]; + while (true) + { + int bytesRead = src.Read(buf, 0, buf.Length); + + // Read returns 0 when reached end of stream. + if (bytesRead == 0) + { + break; + } + + dst.Write(buf, 0, bytesRead); + } + } + + + public sealed class SgmlUtil + { + public static bool IsRootUrlOf(string rootUrl, string url) + { + + if (rootUrl is null) + { + throw new ArgumentNullException("rootUrl"); + } + + if (url is null) + { + throw new ArgumentNullException("url"); + } + + rootUrl = rootUrl.Trim().ToLower(); + url = url.Trim().ToLower(); + // is it a full path + if (url.StartsWith("http://")) + { + return url.StartsWith(rootUrl); + } + + // it's local + return true; + } + + public static string StripRootUrlPath(string rootUrl, string url) + { + if (url.StartsWith(rootUrl)) + { + url = url.Remove(0, rootUrl.Length); + } + + if (url.StartsWith("/")) + { + url.TrimStart('/'); + } + + return url; + } + + public static string CleanAttachmentUrls(string content, string oldPath, string newPath) + { + oldPath = Regex.Escape(oldPath); + + content = Regex.Replace(content, oldPath, newPath, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture); + return content; + } + + public static string[] GetAttributeValues(string content, string tag, string attribute) + { + var srcrx = CreateAttributeRegex(attribute); + var matches = CreateTagRegex(tag).Matches(content); + var sources = new string[matches.Count]; + for (int i = 0, loopTo = sources.Length - 1; i <= loopTo; i++) + { + var m = srcrx.Match(matches[i].Value); + sources[i] = m.Groups["Value"].Value; + } + return sources; + } + + public static Regex CreateTagRegex(string name) + { + + string pattern = @"<\s*{0}[^>]+>"; + + pattern = string.Format(pattern, name); + return new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture); + } + + public static Regex CreateAttributeRegex(string name) + { + string pattern = @"{0}\s*=\s*['""]?\s*(?[^'"" ]+)"; + pattern = string.Format(pattern, name); + return new Regex(pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture); + } + + } + + } + +} \ No newline at end of file diff --git a/Server/Core/BlogML/Enumerators/BlogPostTypes.cs b/Server/Core/BlogML/Enumerators/BlogPostTypes.cs new file mode 100644 index 00000000..597f7b60 --- /dev/null +++ b/Server/Core/BlogML/Enumerators/BlogPostTypes.cs @@ -0,0 +1,11 @@ + +namespace DotNetNuke.Modules.Blog.BlogML +{ + public enum BlogPostTypes : short + { + [System.Xml.Serialization.XmlEnum("normal")] + Normal = 1, + [System.Xml.Serialization.XmlEnum("article")] + Article = 2 + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Enumerators/CommentModerationTypes.cs b/Server/Core/BlogML/Enumerators/CommentModerationTypes.cs new file mode 100644 index 00000000..40fd61e0 --- /dev/null +++ b/Server/Core/BlogML/Enumerators/CommentModerationTypes.cs @@ -0,0 +1,10 @@ + +namespace DotNetNuke.Modules.Blog.BlogML +{ + public enum CommentModerationTypes : short + { + Anonymous = 1, + Enabled = 2, + Disabled = 3 + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Enumerators/ContentTypes.cs b/Server/Core/BlogML/Enumerators/ContentTypes.cs new file mode 100644 index 00000000..f3bb582a --- /dev/null +++ b/Server/Core/BlogML/Enumerators/ContentTypes.cs @@ -0,0 +1,16 @@ +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML +{ + public enum ContentTypes : short + { + [XmlEnum("html")] + Html = 1, + [XmlEnum("xhtml")] + Xhtml = 2, + [XmlEnum("text")] + Text = 3, + [XmlEnum("base64")] + Base64 = 4 + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Enumerators/SendTrackbackTypes.cs b/Server/Core/BlogML/Enumerators/SendTrackbackTypes.cs new file mode 100644 index 00000000..b379d3c5 --- /dev/null +++ b/Server/Core/BlogML/Enumerators/SendTrackbackTypes.cs @@ -0,0 +1,9 @@ + +namespace DotNetNuke.Modules.Blog.BlogML +{ + public enum SendTrackbackTypes : short + { + Yes = 1, + No = 2 + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Pair.cs b/Server/Core/BlogML/Pair.cs new file mode 100644 index 00000000..9ea93e14 --- /dev/null +++ b/Server/Core/BlogML/Pair.cs @@ -0,0 +1,19 @@ + +namespace DotNetNuke.Modules.Blog.BlogML +{ + + /// + /// A serializable keyvalue pair class + /// + public struct Pair + { + public K Key; + public V Value; + public Pair(K key, V value) + { + Key = key; + Value = value; + } + } + +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLAttachment.cs b/Server/Core/BlogML/Xml/BlogMLAttachment.cs new file mode 100644 index 00000000..bc8d2385 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLAttachment.cs @@ -0,0 +1,26 @@ +using System; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public sealed class BlogMLAttachment + { + + [XmlAttribute("embedded")] + public bool Embedded { get; set; } = false; + + [XmlAttribute("url")] + public string Url { get; set; } + + [XmlAttribute("path")] + public string Path { get; set; } + + [XmlAttribute("mime-type")] + public string MimeType { get; set; } + + [XmlText] + public byte[] Data { get; set; } + + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLAuthor.cs b/Server/Core/BlogML/Xml/BlogMLAuthor.cs new file mode 100644 index 00000000..eef981a8 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLAuthor.cs @@ -0,0 +1,14 @@ +using System; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public sealed class BlogMLAuthor : BlogMLNode + { + + [XmlAttribute("email")] + public string Email { get; set; } + + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLAuthorReference.cs b/Server/Core/BlogML/Xml/BlogMLAuthorReference.cs new file mode 100644 index 00000000..476bdf57 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLAuthorReference.cs @@ -0,0 +1,14 @@ +using System; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public sealed class BlogMLAuthorReference + { + + [XmlAttribute("ref")] + public string Ref { get; set; } + + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLBlog.cs b/Server/Core/BlogML/Xml/BlogMLBlog.cs new file mode 100644 index 00000000..643ea5cc --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLBlog.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + [XmlRoot(ElementName = "blog", Namespace = "http://www.blogml.com/2006/09/BlogML")] + public sealed class BlogMLBlog + { + + [XmlAttribute("root-url")] + public string RootUrl { get; set; } + + [XmlElement("title")] + public string Title { get; set; } + + [XmlElement("sub-title")] + public string SubTitle { get; set; } + + [XmlAttribute("date-created", DataType = "dateTime")] + public DateTime DateCreated { get; set; } = DateTime.Now; + + [XmlArray("extended-properties")] + [XmlArrayItem("property", typeof(Pair))] + public ExtendedPropertiesCollection ExtendedProperties { get; set; } = new ExtendedPropertiesCollection(); + + [XmlArray("authors")] + [XmlArrayItem("author", typeof(BlogMLAuthor))] + public AuthorCollection Authors { get; set; } = new AuthorCollection(); + + [XmlArray("posts")] + [XmlArrayItem("post", typeof(BlogMLPost))] + public PostCollection Posts { get; set; } = new PostCollection(); + + [XmlArray("categories")] + [XmlArrayItem("category", typeof(BlogMLCategory))] + public CategoryCollection Categories { get; set; } = new CategoryCollection(); + + [Serializable] + public sealed class AuthorCollection : List + { + } + + [Serializable] + public sealed class PostCollection : List + { + } + + [Serializable] + public sealed class CategoryCollection : List + { + } + + [Serializable] + public sealed class ExtendedPropertiesCollection : List> + { + } + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLCategory.cs b/Server/Core/BlogML/Xml/BlogMLCategory.cs new file mode 100644 index 00000000..aedd2aba --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLCategory.cs @@ -0,0 +1,17 @@ +using System; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public sealed class BlogMLCategory : BlogMLNode + { + + [XmlAttribute("description")] + public string Description { get; set; } + + [XmlAttribute("parentref")] + public string ParentRef { get; set; } + + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLCategoryReference.cs b/Server/Core/BlogML/Xml/BlogMLCategoryReference.cs new file mode 100644 index 00000000..44f3b7a7 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLCategoryReference.cs @@ -0,0 +1,14 @@ +using System; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public sealed class BlogMLCategoryReference + { + + [XmlAttribute("ref")] + public string Ref { get; set; } + + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLComment.cs b/Server/Core/BlogML/Xml/BlogMLComment.cs new file mode 100644 index 00000000..8350f23a --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLComment.cs @@ -0,0 +1,27 @@ +using System; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public sealed class BlogMLComment : BlogMLNode + { + private string m_userName; + private string m_userEmail; + private string m_userUrl; + private BlogMLContent m_content = new BlogMLContent(); + + [XmlAttribute("user-name")] + public string UserName { get; set; } + + [XmlAttribute("user-url")] + public string UserUrl { get; set; } + + [XmlAttribute("user-email")] + public string UserEMail { get; set; } + + [XmlElement("content")] + public BlogMLContent Content { get; set; } + + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLContent.cs b/Server/Core/BlogML/Xml/BlogMLContent.cs new file mode 100644 index 00000000..f37e62a1 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLContent.cs @@ -0,0 +1,93 @@ +using System; +using System.Text; +using System.Web; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public sealed class BlogMLContent + { + private bool Base64Encoded + { + get + { + return ContentType == ContentTypes.Base64; + } + } + + private bool HtmlEncoded + { + get + { + return ContentType == ContentTypes.Html || ContentType == ContentTypes.Xhtml; + } + } + + [XmlAttribute("type")] + public ContentTypes ContentType + { + get + { + return m_ContentType; + } + set + { + m_ContentType = value; + } + } + private ContentTypes m_ContentType = ContentTypes.Text; + + // Encoded Text + [XmlText] + public string Text + { + get + { + return m_Text; + } + set + { + m_Text = value; + } + } + private string m_Text; + + [XmlIgnore] + public string UncodedText + { + get + { + if (Base64Encoded) + { + byte[] byteArray = Convert.FromBase64String(Text); + return Encoding.UTF8.GetString(byteArray); + } + if (HtmlEncoded) + { + return HttpUtility.HtmlDecode(Text); + } + return Text; + } + } + + public static BlogMLContent Create(string unencodedText, ContentTypes contentType) + { + var content = new BlogMLContent() { ContentType = contentType }; + if (content.Base64Encoded) + { + byte[] byteArray = Encoding.UTF8.GetBytes(unencodedText); + content.Text = Convert.ToBase64String(byteArray); + } + else if (content.HtmlEncoded) + { + content.Text = HttpUtility.HtmlEncode(unencodedText); + } + else + { + content.Text = unencodedText; + } + return content; + } + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLMeta.cs b/Server/Core/BlogML/Xml/BlogMLMeta.cs new file mode 100644 index 00000000..fcabe732 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLMeta.cs @@ -0,0 +1,18 @@ +using System; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + [Obsolete("I don't think that we use this now that we are using Dictionary")] + public sealed class Meta + { + + [XmlAttribute("type")] + public string Type { get; set; } + + [XmlAttribute("value")] + public string Value { get; set; } + + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLNode.cs b/Server/Core/BlogML/Xml/BlogMLNode.cs new file mode 100644 index 00000000..7a59b1e4 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLNode.cs @@ -0,0 +1,26 @@ +using System; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public abstract class BlogMLNode + { + + [XmlAttribute("id")] + public string ID { get; set; } + + [XmlElement("title")] + public string Title { get; set; } + + [XmlAttribute("date-created", DataType = "dateTime")] + public DateTime DateCreated { get; set; } = DateTime.Now; + + [XmlAttribute("date-modified", DataType = "dateTime")] + public DateTime DateModified { get; set; } = DateTime.Now; + + [XmlAttribute("approved")] + public bool Approved { get; set; } = true; + + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLPost.cs b/Server/Core/BlogML/Xml/BlogMLPost.cs new file mode 100644 index 00000000..ebfcc180 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLPost.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public sealed class BlogMLPost : BlogMLNode + { + + [XmlAttribute("post-url")] + public string PostUrl { get; set; } + + [XmlAttribute("hasexcerpt")] + public bool HasExcerpt { get; set; } = false; + + [XmlAttribute("type")] + public BlogPostTypes PostType { get; set; } = new BlogPostTypes(); + + [XmlAttribute("views")] + public uint Views { get; set; } = 0U; + + [XmlAttribute("image", Namespace = "http://dnn-connect.org/blog/")] + public string Image { get; set; } + + [XmlAttribute("allow-comments", Namespace = "http://dnn-connect.org/blog/")] + public bool AllowComments { get; set; } = true; + + [XmlAttribute("display-copyright", Namespace = "http://dnn-connect.org/blog/")] + public bool DisplayCopyright { get; set; } = false; + + [XmlAttribute("copyright", Namespace = "http://dnn-connect.org/blog/")] + public string Copyright { get; set; } + + [XmlAttribute("locale", Namespace = "http://dnn-connect.org/blog/")] + public string Locale { get; set; } + + [XmlElement("post-name")] + public string PostName { get; set; } + + [XmlElement("content")] + public BlogMLContent Content { get; set; } = new BlogMLContent(); + + [XmlElement("excerpt")] + public BlogMLContent Excerpt { get; set; } = new BlogMLContent(); + + [XmlArray("authors")] + [XmlArrayItem("author", typeof(BlogMLAuthorReference))] + public AuthorReferenceCollection Authors { get; set; } = new AuthorReferenceCollection(); + + [XmlArray("categories")] + [XmlArrayItem("category", typeof(BlogMLCategoryReference))] + public CategoryReferenceCollection Categories { get; set; } = new CategoryReferenceCollection(); + + [XmlArray("comments")] + [XmlArrayItem("comment", typeof(BlogMLComment))] + public CommentCollection Comments { get; set; } = new CommentCollection(); + + [XmlArray("trackbacks")] + [XmlArrayItem("trackback", typeof(BlogMLTrackback))] + public TrackbackCollection Trackbacks { get; set; } = new TrackbackCollection(); + + [XmlArray("attachments")] + [XmlArrayItem("attachment", typeof(BlogMLAttachment))] + public AttachmentCollection Attachments { get; set; } = new AttachmentCollection(); + + [Serializable] + public sealed class AuthorReferenceCollection : ArrayList + { + public new BlogMLAuthorReference this[int index] + { + get + { + return base[index] as BlogMLAuthorReference; + } + } + + public void Add(BlogMLAuthorReference value) + { + base.Add(value); + } + + public BlogMLAuthorReference Add(string authorID) + { + var item = new BlogMLAuthorReference(); + item.Ref = authorID; + base.Add(item); + return item; + } + } + + [Serializable] + public sealed class CommentCollection : ArrayList + { + public new BlogMLComment this[int index] + { + get + { + return base[index] as BlogMLComment; + } + } + + public void Add(BlogMLComment value) + { + base.Add(value); + } + } + + [Serializable] + public sealed class TrackbackCollection : ArrayList + { + public new BlogMLTrackback this[int index] + { + get + { + return base[index] as BlogMLTrackback; + } + } + + public void Add(BlogMLTrackback value) + { + base.Add(value); + } + } + + [Serializable] + public sealed class CategoryReferenceCollection : ArrayList + { + public new BlogMLCategoryReference this[int index] + { + get + { + return base[index] as BlogMLCategoryReference; + } + } + + public void Add(BlogMLCategoryReference value) + { + base.Add(value); + } + + public BlogMLCategoryReference Add(string categoryID) + { + var item = new BlogMLCategoryReference(); + item.Ref = categoryID; + base.Add(item); + return item; + } + } + + [Serializable] + public sealed class AttachmentCollection : ArrayList + { + public new BlogMLAttachment this[int index] + { + get + { + return base[index] as BlogMLAttachment; + } + } + + public void Add(BlogMLAttachment value) + { + base.Add(value); + } + } + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLSerializer.cs b/Server/Core/BlogML/Xml/BlogMLSerializer.cs new file mode 100644 index 00000000..a8cbd286 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLSerializer.cs @@ -0,0 +1,67 @@ +using System.IO; +using System.Xml; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + public class BlogMLSerializer + { + private static readonly object syncRoot = new object(); + private static XmlSerializer m_serializer; + + public static XmlSerializer Serializer + { + get + { + lock (syncRoot) + { + if (m_serializer is null) + { + m_serializer = new XmlSerializer(typeof(BlogMLBlog)); + } + return m_serializer; + } + } + } + + public static XmlSerializerNamespaces Namespaces + { + get + { + var ns = new XmlSerializerNamespaces(); + ns.Add("dnn", "http://dnn-connect.org/blog/"); + return ns; + } + } + + public static BlogMLBlog Deserialize(Stream stream) + { + return Serializer.Deserialize(stream) as BlogMLBlog; + } + + public static BlogMLBlog Deserialize(TextReader reader) + { + return Serializer.Deserialize(reader) as BlogMLBlog; + } + + public static BlogMLBlog Deserialize(XmlReader reader) + { + return Serializer.Deserialize(reader) as BlogMLBlog; + } + + public static void Serialize(Stream stream, BlogMLBlog blog) + { + Serializer.Serialize(stream, blog, Namespaces); + } + + public static void Serialize(TextWriter writer, BlogMLBlog blog) + { + Serializer.Serialize(writer, blog, Namespaces); + } + + public static void Serialize(XmlWriter writer, BlogMLBlog blog) + { + Serializer.Serialize(writer, blog, Namespaces); + } + } +} \ No newline at end of file diff --git a/Server/Core/BlogML/Xml/BlogMLTrackback.cs b/Server/Core/BlogML/Xml/BlogMLTrackback.cs new file mode 100644 index 00000000..74598a23 --- /dev/null +++ b/Server/Core/BlogML/Xml/BlogMLTrackback.cs @@ -0,0 +1,14 @@ +using System; +using System.Xml.Serialization; + +namespace DotNetNuke.Modules.Blog.BlogML.Xml +{ + [Serializable] + public sealed class BlogMLTrackback : BlogMLNode + { + + [XmlAttribute("url")] + public string Url { get; set; } + + } +} \ No newline at end of file diff --git a/Server/Core/Common/BlogContextInfo.cs b/Server/Core/Common/BlogContextInfo.cs new file mode 100644 index 00000000..7f3ce84e --- /dev/null +++ b/Server/Core/Common/BlogContextInfo.cs @@ -0,0 +1,394 @@ +using System; +using System.Collections.Specialized; +using System.Web; +using static DotNetNuke.Modules.Blog.Common.Globals; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Modules.Blog.Security; +using DotNetNuke.Services.Tokens; + +namespace DotNetNuke.Modules.Blog.Common +{ + + public class BlogContextInfo : IPropertyAccess + { + + #region Private Members + private NameValueCollection RequestParams { get; set; } + #endregion + + #region Public Methods + public BlogContextInfo(HttpContext context, BlogModuleBase blogModule) + { + + BlogModuleId = blogModule.ModuleId; + + // Initialize values from View Settings + if (blogModule.ViewSettings.BlogModuleId != -1) + { + BlogModuleId = blogModule.ViewSettings.BlogModuleId; + ParentModule = new DotNetNuke.Entities.Modules.ModuleController().GetModule(BlogModuleId); + } + BlogId = blogModule.ViewSettings.BlogId; + Categories = blogModule.ViewSettings.Categories; + AuthorId = blogModule.ViewSettings.AuthorId; + + Locale = System.Threading.Thread.CurrentThread.CurrentCulture.Name; + if (context.Request.UrlReferrer is not null) + Referrer = context.Request.UrlReferrer.PathAndQuery; + RequestParams = context.Request.Params; + + int argVariable = BlogId; + Extensions.ReadValue(ref context.Request.Params, "Blog", ref argVariable); + BlogId = argVariable; + int argVariable1 = ContentItemId; + Extensions.ReadValue(ref context.Request.Params, "Post", ref argVariable1); + ContentItemId = argVariable1; + int argVariable2 = TermId; + Extensions.ReadValue(ref context.Request.Params, "Term", ref argVariable2); + TermId = argVariable2; + string argVariable3 = Categories; + Extensions.ReadValue(ref context.Request.Params, "Categories", ref argVariable3); + Categories = argVariable3; + int argVariable4 = AuthorId; + Extensions.ReadValue(ref context.Request.Params, "User", ref argVariable4); + AuthorId = argVariable4; + int argVariable5 = AuthorId; + Extensions.ReadValue(ref context.Request.Params, "uid", ref argVariable5); + AuthorId = argVariable5; + int argVariable6 = AuthorId; + Extensions.ReadValue(ref context.Request.Params, "UserId", ref argVariable6); + AuthorId = argVariable6; + int argVariable7 = AuthorId; + Extensions.ReadValue(ref context.Request.Params, "Author", ref argVariable7); + AuthorId = argVariable7; + var argVariable8 = EndDate; + Extensions.ReadValue(ref context.Request.Params, "end", ref argVariable8); + EndDate = argVariable8; + string argVariable9 = SearchString; + Extensions.ReadValue(ref context.Request.Params, "search", ref argVariable9); + SearchString = argVariable9; + bool argVariable10 = SearchTitle; + Extensions.ReadValue(ref context.Request.Params, "t", ref argVariable10); + SearchTitle = argVariable10; + bool argVariable11 = SearchContents; + Extensions.ReadValue(ref context.Request.Params, "c", ref argVariable11); + SearchContents = argVariable11; + bool argVariable12 = SearchUnpublished; + Extensions.ReadValue(ref context.Request.Params, "u", ref argVariable12); + SearchUnpublished = argVariable12; + int argVariable13 = LegacyEntryId; + Extensions.ReadValue(ref context.Request.Params, "EntryId", ref argVariable13); + LegacyEntryId = argVariable13; + if (ContentItemId > -1) + Post = Entities.Posts.PostsController.GetPost(ContentItemId, BlogModuleId, Locale); + if (BlogId > -1 & Post is not null && Post.BlogID != BlogId) + Post = null; // double check in case someone is hacking to retrieve an Post from another blog + if (BlogId == -1 & Post is not null) + BlogId = Post.BlogID; + if (BlogId > -1) + Blog = Entities.Blogs.BlogsController.GetBlog(BlogId, blogModule.UserInfo.UserID, Locale); + if (BlogId > -1) + BlogMapPath = GetBlogDirectoryMapPath(BlogId); + if (!string.IsNullOrEmpty(BlogMapPath) && !System.IO.Directory.Exists(BlogMapPath)) + System.IO.Directory.CreateDirectory(BlogMapPath); + if (ContentItemId > -1) + PostMapPath = GetPostDirectoryMapPath(BlogId, ContentItemId); + if (!string.IsNullOrEmpty(PostMapPath) && !System.IO.Directory.Exists(PostMapPath)) + System.IO.Directory.CreateDirectory(PostMapPath); + if (TermId > -1) + Term = Entities.Terms.TermsController.GetTerm(TermId, BlogModuleId, Locale); + if (AuthorId > -1) + Author = DotNetNuke.Entities.Users.UserController.GetUserById(blogModule.PortalId, AuthorId); + if (context.Request.UserAgent is not null) + { + WLWRequest = context.Request.UserAgent.IndexOf("Windows Live Writer") > -1; + } + Security = new ContextSecurity(BlogModuleId, blogModule.TabId, Blog, blogModule.UserInfo); + if (EndDate < DateTime.Now.AddDays(-1)) + { + EndDate = EndDate.Date.AddDays(1d).AddMinutes(-1); + EndDateOrNow = EndDate; + } + else if (Security.CanAddPost) + { + EndDate = default; + } + else + { + EndDate = DateTime.Now.ToUniversalTime(); // security measure to stop people prying into future posts + EndDateOrNow = EndDate; + } + + // security + bool isStylePostRequest = false; + if (Post is not null && !(Post.Published | Security.CanEditThisPost(Post)) && !Security.IsEditor) + { + if (Post.Title.Contains("3bfe001a-32de-4114-a6b4-4005b770f6d7") & WLWRequest) + { + isStylePostRequest = true; + } + else + { + Post = null; + ContentItemId = -1; + } + } + if (Blog is not null && !Blog.Published && !Security.IsOwner && !Security.UserIsAdmin && !isStylePostRequest) + { + Blog = null; + BlogId = -1; + } + + // set urls for use in module + if (ParentModule is null) + { + ModuleUrls = new ModuleUrls(blogModule.TabId, BlogId, ContentItemId, TermId, AuthorId); + } + else + { + ModuleUrls = new ModuleUrls(blogModule.TabId, ParentModule.TabID, BlogId, ContentItemId, TermId, AuthorId); + } + IsMultiLingualSite = ComponentModel.ComponentBase.Instance.GetLocales(blogModule.PortalId).Count > 1; + if (!blogModule.ViewSettings.ShowAllLocales) + { + ShowLocale = Locale; + } + if (Referrer.Contains("/ctl/") | Referrer.Contains("&ctl=")) + { + Referrer = DotNetNuke.Common.Globals.NavigateURL(blogModule.TabId); // just catch 99% of bad referrals to edit pages + } + + UiTimeZone = blogModule.ModuleContext.PortalSettings.TimeZone; + if (blogModule.UserInfo.Profile.PreferredTimeZone is not null) + { + UiTimeZone = blogModule.UserInfo.Profile.PreferredTimeZone; + } + + } + + public static BlogContextInfo GetBlogContext(ref HttpContext context, BlogModuleBase blogModule) + { + BlogContextInfo res; + if (context.Items["BlogContext" + blogModule.TabModuleId.ToString()] is null) + { + res = new BlogContextInfo(context, blogModule); + context.Items["BlogContext" + blogModule.TabModuleId.ToString()] = res; + } + else + { + res = (BlogContextInfo)context.Items["BlogContext" + blogModule.TabModuleId.ToString()]; + } + return res; + } + #endregion + + #region Public Properties + public int BlogModuleId { get; set; } = -1; + public DotNetNuke.Entities.Modules.ModuleInfo ParentModule { get; set; } = null; + public int BlogId { get; set; } = -1; + public int ContentItemId { get; set; } = -1; + public int TermId { get; set; } = -1; + public string Categories { get; set; } = ""; + public int AuthorId { get; set; } = -1; + public DateTime EndDate { get; set; } = DateTime.Now.ToUniversalTime(); + public DateTime EndDateOrNow { get; set; } = DateTime.Now; + public Entities.Blogs.BlogInfo Blog { get; set; } = null; + public Entities.Posts.PostInfo Post { get; set; } = null; + public Entities.Terms.TermInfo Term { get; set; } = null; + public DotNetNuke.Entities.Users.UserInfo Author { get; set; } = null; + public string BlogMapPath { get; set; } = ""; + public string PostMapPath { get; set; } = ""; + public bool OutputAdditionalFiles { get; set; } + public ModuleUrls ModuleUrls { get; set; } = null; + public string SearchString { get; set; } = ""; + public bool SearchTitle { get; set; } = true; + public bool SearchContents { get; set; } = false; + public bool SearchUnpublished { get; set; } = false; + public bool IsMultiLingualSite { get; set; } = false; + public string ShowLocale { get; set; } = null; + public string Locale { get; set; } = ""; + public string Referrer { get; set; } = ""; + public bool WLWRequest { get; set; } = false; + public TimeZoneInfo UiTimeZone { get; set; } + public ContextSecurity Security { get; set; } + public int LegacyEntryId { get; set; } = -1; + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "blogmoduleid": + { + return BlogModuleId.ToString(OutputFormat, formatProvider); + } + case "blogid": + { + return BlogId.ToString(OutputFormat, formatProvider); + } + case "Postid": + case "contentitemid": + case "postid": + case "post": + { + return ContentItemId.ToString(OutputFormat, formatProvider); + } + case "termid": + case "term": + { + return TermId.ToString(OutputFormat, formatProvider); + } + case "categories": + { + return Categories; + } + case "authorid": + case "author": + { + return AuthorId.ToString(OutputFormat, formatProvider); + } + case "enddate": + { + return EndDate.ToString(OutputFormat, formatProvider); + } + case "enddateornow": + { + return EndDateOrNow.ToString(OutputFormat, formatProvider); + } + case "blogselected": + { + return (BlogId > -1).ToString(); + } + case "postselected": + { + return (ContentItemId > -1).ToString(); + } + case "termselected": + { + return (TermId > -1).ToString(); + } + case "authorselected": + { + return (AuthorId > -1).ToString(); + } + case "ismultilingualsite": + { + return IsMultiLingualSite.ToString(); + } + case "showlocale": + { + return ShowLocale; + } + case "locale": + { + switch (strFormat.ToLower() ?? "") + { + case "3": + { + return System.Threading.Thread.CurrentThread.CurrentCulture.ThreeLetterISOLanguageName; + } + case "ietf": + { + return System.Threading.Thread.CurrentThread.CurrentCulture.IetfLanguageTag; + } + case "displayname": + case "display": + { + return System.Threading.Thread.CurrentThread.CurrentCulture.DisplayName; + } + case "englishname": + case "english": + { + return System.Threading.Thread.CurrentThread.CurrentCulture.EnglishName; + } + case "nativename": + case "native": + { + return System.Threading.Thread.CurrentThread.CurrentCulture.NativeName; + } + case "generic": + case "2": + { + return System.Threading.Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName; + } + + default: + { + return Locale; + } + } + + break; + } + case "searchstring": + { + return SearchString; + } + case "issearch": + { + return (!string.IsNullOrEmpty(SearchString)).ToString(); + } + case "referrer": + { + return Referrer; + } + + default: + { + if (RequestParams[strPropertyName] is not null) + { + return RequestParams[strPropertyName]; + } + else + { + PropertyNotFound = true; + } + + break; + } + } + return DotNetNuke.Common.Utilities.Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Common/BlogModuleBase.cs b/Server/Core/Common/BlogModuleBase.cs new file mode 100644 index 00000000..9fc1c63c --- /dev/null +++ b/Server/Core/Common/BlogModuleBase.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Text; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Framework; +using DotNetNuke.Framework.JavaScriptLibraries; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Entities.Terms; +using DotNetNuke.Modules.Blog.Templating; +using DotNetNuke.Services.Localization; +using DotNetNuke.UI.Utilities; +using Microsoft.VisualBasic; + +namespace DotNetNuke.Modules.Blog.Common +{ + + public class BlogModuleBase : PortalModuleBase + { + + #region Private Members + #endregion + + #region Properties + private BlogContextInfo _blogContext; + public BlogContextInfo BlogContext + { + get + { + if (_blogContext is null) + { + var argcontext = Context; + _blogContext = BlogContextInfo.GetBlogContext(ref argcontext, this); + } + return _blogContext; + } + set + { + _blogContext = value; + } + } + + private ModuleSettings _settings; + public new ModuleSettings Settings + { + get + { + if (_settings is null) + { + if (ViewSettings.BlogModuleId == -1) + { + _settings = ModuleSettings.GetModuleSettings(ModuleConfiguration.ModuleID); + } + else + { + _settings = ModuleSettings.GetModuleSettings(ViewSettings.BlogModuleId); + } + } + return _settings; + } + set + { + _settings = value; + } + } + + private Dictionary _categories; + public Dictionary Categories + { + get + { + if (_categories is null) + { + _categories = TermsController.GetTermsByVocabulary(ModuleId, Settings.VocabularyId, BlogContext.Locale); + } + return _categories; + } + set + { + _categories = value; + } + } + + private ViewSettings _viewSettings; + public ViewSettings ViewSettings + { + get + { + if (_viewSettings is null) + _viewSettings = ViewSettings.GetViewSettings(TabModuleId); + return _viewSettings; + } + set + { + _viewSettings = value; + } + } + + public new CDefault Page + { + get + { + return (CDefault)base.Page; + } + } + + private string _BlogModuleMapPath = ""; + public string BlogModuleMapPath + { + get + { + if (string.IsNullOrEmpty(_BlogModuleMapPath)) + { + _BlogModuleMapPath = Server.MapPath("~/DesktopModules/Blog") + @"\"; + } + return _BlogModuleMapPath; + } + } + + public BlogModuleBase() + { + Load += Page_Load; + } + #endregion + + #region Event Handlers + private void Page_Load(object sender, EventArgs e) + { + + if (Context.Items["BlogModuleBaseInitialized"] is null) + { + + JavaScript.RequestRegistration(CommonJs.jQuery); + JavaScript.RequestRegistration(CommonJs.jQueryUI); + var script = new StringBuilder(); + script.AppendLine(""); + ClientAPI.RegisterClientScriptBlock(Page, "blogAppPath", script.ToString()); + AddBlogService(); + + Context.Items["BlogModuleBaseInitialized"] = true; + } + + } + #endregion + + #region Public Methods + public void AddBlogService() + { + + if (Context.Items["BlogServiceAdded"] is null) + { + + JavaScript.RequestRegistration(CommonJs.DnnPlugins); + ServiceLocator.Instance.RequestAjaxScriptSupport(); + ServiceLocator.Instance.RequestAjaxAntiForgerySupport(); + AddJavascriptFile("dotnetnuke.blog.js", 70); + + // Load initialization snippet + string scriptBlock = ReadFile(DotNetNuke.Common.Globals.ApplicationMapPath + @"\DesktopModules\Blog\js\dotnetnuke.blog.pagescript.js"); + var tr = new BlogTokenReplace(BlogContext.BlogModuleId); + tr.AddResources("~/DesktopModules/Blog/App_LocalResources/SharedResources.resx"); + scriptBlock = tr.ReplaceTokens(scriptBlock); + scriptBlock = ""; + Page.ClientScript.RegisterClientScriptBlock(GetType(), "BlogServiceScript", scriptBlock); + + Context.Items["BlogServiceAdded"] = true; + } + + } + + public void AddJavascriptFile(string jsFilename, int priority) + { + Page.AddJavascriptFile(Settings.Version, jsFilename, priority); + } + + public void AddJavascriptFile(string jsFilename, string name, string version, int priority) + { + Page.AddJavascriptFile(Settings.Version, jsFilename, name, version, priority); + } + + public void AddCssFile(string cssFilename) + { + Page.AddCssFile(Settings.Version, cssFilename); + } + + public void AddCssFile(string cssFilename, string name, string version) + { + Page.AddCssFile(Settings.Version, cssFilename, name, version); + } + + public string LocalizeJSString(string resourceKey) + { + return ClientAPI.GetSafeJSString(LocalizeString(resourceKey)); + } + + public string LocalizeJSString(string resourceKey, string resourceFile) + { + return ClientAPI.GetSafeJSString(Localization.GetString(resourceKey, resourceFile)); + } + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Common/DynatreeItem.cs b/Server/Core/Common/DynatreeItem.cs new file mode 100644 index 00000000..935823ff --- /dev/null +++ b/Server/Core/Common/DynatreeItem.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +namespace DotNetNuke.Modules.Blog.Common +{ + public class DynatreeItem + { + public string title { get; set; } = ""; + public string key { get; set; } = ""; + public bool icon { get; set; } = false; + public bool expand { get; set; } = true; + public bool isFolder { get; set; } = true; + public bool @select { get; set; } = false; + public List children { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/Server/Core/Common/Extensions.cs b/Server/Core/Common/Extensions.cs new file mode 100644 index 00000000..8dcef959 --- /dev/null +++ b/Server/Core/Common/Extensions.cs @@ -0,0 +1,790 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Data; +using System.Globalization; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Linq; +using System.Text; +using System.Web; +using System.Web.UI; +using System.Xml; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Entities.Terms; +using DotNetNuke.Web.Client; +using DotNetNuke.Web.Client.ClientResourceManagement; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Common +{ + static class Extensions + { + + #region Collection Read Extensions + public static void ReadValue(ref Hashtable ValueTable, string ValueName, ref int Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToInteger(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref Hashtable ValueTable, string ValueName, ref long Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToLong(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref Hashtable ValueTable, string ValueName, ref string Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToString(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref Hashtable ValueTable, string ValueName, ref bool Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToBoolean(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref Hashtable ValueTable, string ValueName, ref DateTime Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToDate(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref Hashtable ValueTable, string ValueName, ref SummaryType Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = (SummaryType)Conversions.ToInteger(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref Hashtable ValueTable, string ValueName, ref LocalizationType Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = (LocalizationType)Conversions.ToInteger(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref Hashtable ValueTable, string ValueName, ref TimeSpan Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = TimeSpan.Parse(Conversions.ToString(ValueTable[ValueName])); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref NameValueCollection ValueTable, string ValueName, ref int Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToInteger(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref NameValueCollection ValueTable, string ValueName, ref long Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToLong(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref NameValueCollection ValueTable, string ValueName, ref string Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = ValueTable[ValueName]; + Variable = new DotNetNuke.Security.PortalSecurity().InputFilter(Variable, DotNetNuke.Security.PortalSecurity.FilterFlag.NoMarkup | DotNetNuke.Security.PortalSecurity.FilterFlag.NoScripting); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref NameValueCollection ValueTable, string ValueName, ref bool Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToBoolean(ValueTable[ValueName]); + } + catch (Exception ex) + { + switch (ValueTable[ValueName].ToLower() ?? "") + { + case "on": + case "yes": + { + Variable = true; + break; + } + + default: + { + Variable = false; + break; + } + } + } + } + } + + public static void ReadValue(ref NameValueCollection ValueTable, string ValueName, ref DateTime Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToDate(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref NameValueCollection ValueTable, string ValueName, ref TimeSpan Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = TimeSpan.Parse(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(this Dictionary ValueTable, string ValueName, ref int Variable) + { + if (ValueTable.ContainsKey(ValueName)) + { + try + { + Variable = Conversions.ToInteger(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(this Dictionary ValueTable, string ValueName, ref string Variable) + { + if (ValueTable.ContainsKey(ValueName)) + { + try + { + Variable = ValueTable[ValueName]; + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(this Dictionary ValueTable, string ValueName, ref bool Variable) + { + if (ValueTable.ContainsKey(ValueName)) + { + try + { + Variable = Conversions.ToBoolean(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(this Dictionary ValueTable, string ValueName, ref DateTime Variable) + { + if (ValueTable.ContainsKey(ValueName)) + { + try + { + Variable = Conversions.ToDate(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(this Dictionary ValueTable, string ValueName, ref TimeSpan Variable) + { + if (ValueTable.ContainsKey(ValueName)) + { + try + { + Variable = TimeSpan.Parse(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref StateBag ValueTable, string ValueName, ref int Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToInteger(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref StateBag ValueTable, string ValueName, ref long Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToLong(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref StateBag ValueTable, string ValueName, ref string Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToString(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref StateBag ValueTable, string ValueName, ref bool Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToBoolean(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref StateBag ValueTable, string ValueName, ref DateTime Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = Conversions.ToDate(ValueTable[ValueName]); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref StateBag ValueTable, string ValueName, ref TimeSpan Variable) + { + if (ValueTable[ValueName] is not null) + { + try + { + Variable = TimeSpan.Parse(Conversions.ToString(ValueTable[ValueName])); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref XmlNode ValueTable, string ValueName, ref int Variable) + { + if (ValueTable.SelectSingleNode(ValueName) is not null) + { + try + { + Variable = Conversions.ToInteger(ValueTable.SelectSingleNode(ValueName).InnerText); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref XmlNode ValueTable, string ValueName, ref long Variable) + { + if (ValueTable.SelectSingleNode(ValueName) is not null) + { + try + { + Variable = Conversions.ToLong(ValueTable.SelectSingleNode(ValueName).InnerText); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref XmlNode ValueTable, string ValueName, ref string Variable) + { + if (ValueTable.SelectSingleNode(ValueName) is not null) + { + try + { + Variable = ValueTable.SelectSingleNode(ValueName).InnerText; + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref XmlNode ValueTable, string ValueName, ref bool Variable) + { + if (ValueTable.SelectSingleNode(ValueName) is not null) + { + try + { + Variable = Conversions.ToBoolean(ValueTable.SelectSingleNode(ValueName).InnerText); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref XmlNode ValueTable, string ValueName, ref DateTime Variable) + { + if (ValueTable.SelectSingleNode(ValueName) is not null) + { + try + { + Variable = Conversions.ToDate(ValueTable.SelectSingleNode(ValueName).InnerText); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref XmlNode ValueTable, string ValueName, ref SummaryType Variable) + { + if (ValueTable.SelectSingleNode(ValueName) is not null) + { + try + { + Variable = (SummaryType)Conversions.ToInteger(ValueTable.SelectSingleNode(ValueName).InnerText); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref XmlNode ValueTable, string ValueName, ref LocalizationType Variable) + { + if (ValueTable.SelectSingleNode(ValueName) is not null) + { + try + { + Variable = (LocalizationType)Conversions.ToInteger(ValueTable.SelectSingleNode(ValueName).InnerText); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref XmlNode ValueTable, string ValueName, ref TimeSpan Variable) + { + if (ValueTable.SelectSingleNode(ValueName) is not null) + { + try + { + Variable = TimeSpan.Parse(ValueTable.SelectSingleNode(ValueName).InnerText); + } + catch (Exception ex) + { + } + } + } + + public static void ReadValue(ref XmlNode ValueTable, string ValueName, ref LocalizedText Variable) + { + if (ValueTable.SelectSingleNode(ValueName) is not null) + { + if (ValueTable.SelectSingleNode(ValueName).SelectSingleNode("MLText") is not null) + { + if (Variable is null) + Variable = new LocalizedText(); + foreach (XmlNode t in ValueTable.SelectSingleNode(ValueName).SelectSingleNode("MLText").SelectNodes("Text")) + Variable.Add(t.Attributes["Locale"].InnerText, t.InnerText); + } + } + } + #endregion + + #region Conversion Extensions + public static int ToInt(this bool @var) + { + if (@var) + { + return 1; + } + else + { + return 0; + } + } + + public static string ToYesNo(this bool @var) + { + if (@var) + { + return "Yes"; + } + else + { + return "No"; + } + } + + public static int ToInt(this string @var) + { + if (Information.IsNumeric(@var)) + { + return int.Parse(@var); + } + else + { + return -1; + } + } + + public static bool ToBool(this int @var) + { + return @var > 0; + } + + public static string[] ToStringArray(this List terms) + { + return terms.Select(x => x.Name).ToArray(); + } + + public static string ToTermIDString(this List terms) + { + return terms.ToTermIDString(";"); + } + + public static string ToTermIDString(this List terms, string separator) + { + var res = new List(); + foreach (TermInfo t in terms) + res.Add(t.TermId.ToString()); + return string.Join(separator, res.ToArray()); + } + + public static string ToStringOrZero(this int? value) + { + if (value is null) + { + return "0"; + } + else + { + return value.ToString(); + } + } + #endregion + + #region Other + public static Control FindControlByID(this Control Control, string id) + { + Control found = null; + if (Control is not null) + { + if ((Control.ID ?? "") == (id ?? "")) + { + found = Control; + } + else + { + found = Control.Controls.FindControlByID(id); + } + } + return found; + } + + public static Control FindControlByID(this ControlCollection Controls, string id) + { + Control found = null; + if (Controls is not null && Controls.Count > 0) + { + for (int i = 0, loopTo = Controls.Count - 1; i <= loopTo; i++) + { + if ((Controls[i].ID ?? "") == (id ?? "")) + { + found = Controls[i]; + } + else + { + found = Controls[i].Controls.FindControlByID(id); + } + if (found is not null) + break; + } + } + return found; + } + + public static string OutputHtml(this string encodedHtml, string strFormat) + { + switch (strFormat.ToLower() ?? "") + { + case var @case when @case == "": + { + return HttpUtility.HtmlDecode(encodedHtml); + } + case "js": + { + return HttpUtility.HtmlDecode(encodedHtml).Replace("\"", @"\""").Replace("'", @"\'").Replace(Constants.vbCrLf, @"\r\n"); + } + + default: + { + if (Information.IsNumeric(strFormat)) + { + return RemoveHtmlTags(HttpUtility.HtmlDecode(encodedHtml)).SubstringWithoutException(0, int.Parse(strFormat)); + } + else + { + return HttpUtility.HtmlDecode(encodedHtml); + } + } + } + } + + public static string SubstringWithoutException(this string input, int startIndex, int length) + { + if (string.IsNullOrEmpty(input)) + return ""; + if (startIndex > 0) + { + if (startIndex >= input.Length) + { + return ""; + } + if (startIndex + length > input.Length) + { + return input.Substring(startIndex, input.Length - startIndex); + } + else + { + return input.Substring(startIndex, length); + } + } + else if (length > input.Length) + { + return input.Substring(0, input.Length - startIndex); + } + else + { + return input.Substring(0, length); + } + } + + public static void WriteAttachmentToXml(this BlogML.Xml.BlogMLAttachment attachment, XmlWriter writer) + { + writer.WriteStartElement("File"); + writer.WriteElementString("Path", attachment.Path); + writer.WriteStartElement("Data"); + writer.WriteBase64(attachment.Data, 0, attachment.Data.Length - 1); + writer.WriteEndElement(); // Data + writer.WriteEndElement(); // File + } + + public static void AddJavascriptFile(this Page page, string moduleVersion, string jsFilename, int priority) + { + if (DotNetNuke.Entities.Host.Host.CrmEnableCompositeFiles) + { + ClientResourceManager.RegisterScript(page, DotNetNuke.Common.Globals.ResolveUrl("~/DesktopModules/Blog/js/" + jsFilename), priority); + } + else + { + ClientResourceManager.RegisterScript(page, DotNetNuke.Common.Globals.ResolveUrl("~/DesktopModules/Blog/js/" + jsFilename) + "?_=" + moduleVersion, priority); + } + } + + public static void AddJavascriptFile(this Page page, string moduleVersion, string jsFilename, string name, string version, int priority) + { + if (DotNetNuke.Entities.Host.Host.CrmEnableCompositeFiles) + { + ClientResourceManager.RegisterScript(page, DotNetNuke.Common.Globals.ResolveUrl("~/DesktopModules/Blog/js/" + jsFilename), priority, "DnnBodyProvider", name, version); + } + else + { + ClientResourceManager.RegisterScript(page, DotNetNuke.Common.Globals.ResolveUrl("~/DesktopModules/Blog/js/" + jsFilename) + "?_=" + moduleVersion, priority, "DnnBodyProvider", name, version); + } + } + + public static void AddCssFile(this Page page, string moduleVersion, string cssFilename) + { + if (DotNetNuke.Entities.Host.Host.CrmEnableCompositeFiles) + { + ClientResourceManager.RegisterStyleSheet(page, DotNetNuke.Common.Globals.ResolveUrl("~/DesktopModules/Blog/css/" + cssFilename), FileOrder.Css.ModuleCss); + } + else + { + ClientResourceManager.RegisterStyleSheet(page, DotNetNuke.Common.Globals.ResolveUrl("~/DesktopModules/Blog/css/" + cssFilename) + "?_=" + moduleVersion, FileOrder.Css.ModuleCss); + } + } + + public static void AddCssFile(this Page page, string moduleVersion, string cssFilename, string name, string version) + { + if (DotNetNuke.Entities.Host.Host.CrmEnableCompositeFiles) + { + ClientResourceManager.RegisterStyleSheet(page, DotNetNuke.Common.Globals.ResolveUrl("~/DesktopModules/Blog/css/" + cssFilename), (int)FileOrder.Css.ModuleCss, "DnnPageHeaderProvider", name, version); + } + else + { + ClientResourceManager.RegisterStyleSheet(page, DotNetNuke.Common.Globals.ResolveUrl("~/DesktopModules/Blog/css/" + cssFilename) + "?_=" + moduleVersion, (int)FileOrder.Css.ModuleCss, "DnnPageHeaderProvider", name, version); + } + } + + public static string RemoveDiacritics(this string text) + { + if (string.IsNullOrEmpty(text)) + { + return text; + } + + string normalizedString = text.Normalize(NormalizationForm.FormD); + var stringBuilder = new StringBuilder(); + + foreach (char c in normalizedString) + { + var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); + + if (unicodeCategory != UnicodeCategory.NonSpacingMark) + { + stringBuilder.Append(c); + } + } + + return stringBuilder.ToString().Normalize(NormalizationForm.FormC); + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Common/Globals.cs b/Server/Core/Common/Globals.cs new file mode 100644 index 00000000..c4d41239 --- /dev/null +++ b/Server/Core/Common/Globals.cs @@ -0,0 +1,377 @@ +using System; +using System.Collections.Generic; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Linq; +using System.Text.RegularExpressions; +using System.Web; +using System.Web.UI.WebControls; +using DotNetNuke.Entities.Content.Taxonomy; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Common +{ + + public class Globals + { + + #region Constants + public const string SharedResourceFileName = "~/DesktopModules/Blog/App_LocalResources/SharedResources.resx"; + public const string glbAppName = "Blog"; + public const string glbImageHandlerPath = "~/DesktopModules/Blog/BlogImage.ashx"; + public const string glbPermittedFileExtensions = ".jpg,.png,.gif,.bmp,"; + public const string glbTemplatesPath = "~/DesktopModules/Blog/Templates/"; + public const string glbServicesPath = "~/DesktopModules/Blog/API/"; + public const string BloggerPermission = "BLOGGER"; + + public enum SummaryType + { + PlainTextIndependent = 0, + HtmlIndependent = 1, + HtmlPrecedesPost = 2 + } + + public enum LocalizationType + { + None = 0, + Loose = 1, + Strict = 2 + } + #endregion + + #region Dates + public static DateTime UtcToLocalTime(DateTime utcTime, TimeZoneInfo TimeZone) + { + return TimeZoneInfo.ConvertTimeFromUtc(utcTime, TimeZone); + } + + public static DateTime ParseDate(string DateString, string Culture) + { + var dtf = new System.Globalization.CultureInfo(Culture, false).DateTimeFormat; + try + { + return DateTime.Parse(DateString, dtf); + } + catch (Exception ex) + { + return default; + } + } + + public static bool IsValidDate(string DateString, string Culture) + { + var dtf = new System.Globalization.CultureInfo(Culture, false).DateTimeFormat; + try + { + var oDate = DateTime.Parse(DateString, dtf); + return true; + } + catch (Exception ex) + { + return false; + } + } + + public static DateTime GetLocalAddedTime(DateTime AddedDate, int PortalId, DotNetNuke.Entities.Users.UserInfo user) + { + return TimeZoneInfo.ConvertTimeToUtc(AddedDate, user.Profile.PreferredTimeZone); + } + #endregion + + #region Other + public static string GetBlogDirectoryMapPath(int blogId) + { + return string.Format(@"{0}Blog\Files\{1}\", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectoryMapPath, blogId); + } + public static string GetBlogDirectoryPath(int blogId) + { + return string.Format("{0}Blog/Files/{1}/", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectory, blogId); + } + public static string GetPostDirectoryMapPath(int blogId, int postId) + { + return string.Format(@"{0}Blog\Files\{1}\{2}\", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectoryMapPath, blogId, postId); + } + public static string GetPostDirectoryPath(int blogId, int postId) + { + return string.Format("{0}Blog/Files/{1}/{2}/", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectory, blogId, postId); + } + public static string GetPostDirectoryMapPath(Entities.Posts.PostInfo post) + { + return GetPostDirectoryMapPath(post.BlogID, post.ContentItemId); + } + public static string GetPostDirectoryPath(Entities.Posts.PostInfo post) + { + return GetPostDirectoryPath(post.BlogID, post.ContentItemId); + } + public static string GetTempPostDirectoryMapPath(int blogId) + { + return string.Format(@"{0}Blog\Files\{1}\_temp_images\", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectoryMapPath, blogId); + } + public static string GetTempPostDirectoryPath(int blogId) + { + return string.Format("{0}Blog/Files/{1}/_temp_images/", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectory, blogId); + } + + public static string ManifestFilePath(int tabId, int moduleId) + { + return string.Format("~/DesktopModules/Blog/API/Modules/Manifest?TabId={0}&ModuleId={1}", tabId, moduleId); + } + + public static string GetAString(object Value) + { + if (Value is null) + { + return ""; + } + else if (ReferenceEquals(Value, DBNull.Value)) + { + return ""; + } + else + { + return Conversions.ToString(Value); + } + } + + public static string ReadFile(string fileName) + { + if (!System.IO.File.Exists(fileName)) + return ""; + using (var sr = new System.IO.StreamReader(fileName)) + { + return sr.ReadToEnd(); + } + } + + public static void WriteToFile(string filePath, string text) + { + WriteToFile(filePath, text, false); + } + public static void WriteToFile(string filePath, string text, bool append) + { + using (var sw = new System.IO.StreamWriter(filePath, append)) + { + sw.Write(text); + sw.Flush(); + } + } + + public static string GetResource(string resourceName) + { + string res = ""; + using (var stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) + { + using (var rdr = new System.IO.StreamReader(stream)) + { + res = rdr.ReadToEnd(); + } + } + return res; + } + + public static string FormatBoolean(bool value, string format) + { + if (string.IsNullOrEmpty(format)) + { + return value.ToString(); + } + if (format.Contains(";")) + { + if (value) + { + return Strings.Left(format, format.IndexOf(";")); + } + else + { + return Strings.Mid(format, format.IndexOf(";") + 2); + } + } + return value.ToString(); + } + + public static string GetSummary(string body, int autoGenerateLength, SummaryType summaryModel, bool encoded) + { + if (string.IsNullOrEmpty(body)) + return ""; + string res = body; + if (encoded) + { + res = HttpUtility.HtmlDecode(res); + } + res = TryToGetFirstParagraph(res); + res = RemoveHtmlTags(res).SubstringWithoutException(0, autoGenerateLength); + if (res.Length >= autoGenerateLength) + res += " ..."; + if (!(summaryModel == SummaryType.PlainTextIndependent)) + { + res = string.Format("

{0}

", res); + } + if (encoded) + { + return HttpUtility.HtmlEncode(res); + } + else + { + return res; + } + } + + public static string TryToGetFirstParagraph(string inputString) + { + var m = Regex.Match(inputString, "(?s)(?i)]*>((?:(?!

).)*)(?-i)(?-s)"); + if (m.Success) + { + return m.Groups[1].Value; + } + return inputString; + } + + public static string RemoveHtmlTags(string inputString) + { + inputString = Regex.Replace(inputString, "<[^>]+>", ""); + return new DotNetNuke.Security.PortalSecurity().InputFilter(inputString, DotNetNuke.Security.PortalSecurity.FilterFlag.NoScripting | DotNetNuke.Security.PortalSecurity.FilterFlag.NoMarkup); + } + + internal static List GetPortalVocabularies(int portalId) + { + var cntVocab = DotNetNuke.Entities.Content.Common.Util.GetVocabularyController(); + var colVocabularies = cntVocab.GetVocabularies(); + var portalVocabularies = from v in colVocabularies + where v.ScopeTypeId == 2 & v.ScopeId == portalId + select v; + return portalVocabularies.ToList(); + } + + public static string GetSafePageName(string pageName) + { + return Regex.Replace(Regex.Replace(pageName, @"[^\w^\d]", "-").Trim('-'), "-+", "-").RemoveDiacritics(); + } + + public static void RemoveOldTimeStampedFiles(System.IO.DirectoryInfo dir) + { + string today = DateTime.Now.ToString("yyyy-MM-dd"); + var deleteList = new List(); + foreach (System.IO.FileInfo f in dir.GetFiles()) + { + var m = Regex.Match(f.Name, @"^(\d\d\d\d-\d\d-\d\d)-"); + if (m.Success) + { + if (Operators.CompareString(m.Groups[1].Value, today, false) < 0) + { + deleteList.Add(f.FullName); + } + } + } + foreach (string f in deleteList) + { + try + { + System.IO.File.Delete(f); + } + catch (Exception ex) + { + } + } + } + + public static List GetRolesByGroup(int portalId, int roleGroupId) + { + return DotNetNuke.Security.Roles.RoleProvider.Instance().GetRoles(portalId).Cast().Where(r => r.RoleGroupID == roleGroupId).ToList(); + } + + public static List GetRolesByPortal(int portalId) + { + return DotNetNuke.Security.Roles.RoleProvider.Instance().GetRoles(portalId).Cast().ToList(); + } + + public static string SafeString(string input, DotNetNuke.Security.PortalSecurity.FilterFlag filter) + { + var ps = new DotNetNuke.Security.PortalSecurity(); + return ps.InputFilter(input, filter); + } + + public static string SafeString(string input) + { + return SafeString(input, DotNetNuke.Security.PortalSecurity.FilterFlag.NoMarkup & DotNetNuke.Security.PortalSecurity.FilterFlag.NoProfanity & DotNetNuke.Security.PortalSecurity.FilterFlag.NoScripting & DotNetNuke.Security.PortalSecurity.FilterFlag.NoSQL); + } + + public static string SafeHtml(string input) + { + return SafeString(input, DotNetNuke.Security.PortalSecurity.FilterFlag.NoProfanity & DotNetNuke.Security.PortalSecurity.FilterFlag.NoScripting & DotNetNuke.Security.PortalSecurity.FilterFlag.NoSQL); + } + + public static string SafeStringSimpleHtml(string input) + { + input = SafeString(input); + input = Regex.Replace(input, @"(?#Protocol)(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?#Username:Password)(?:\w+:\w+@)?(?#Subdomains)(?:(?:[-\w]+\.)+(?#TopLevel Domains)(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum|travel|[a-z]{2}))(?#Port)(?::[\d]{1,5})?(?#Directories)(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?#Query)(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?#Anchor)(?:#(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)?", ReplaceLink); + input = input.Replace(Constants.vbCrLf, "
"); + return input; + } + + public static string CleanStringForXmlAttribute(string input) + { + return input.Replace("&", "and").Replace("\"", """); + } + + public static string ReplaceLink(Match m) + { + string link = m.Value; + return string.Format("{0}", link); + } + + public static string readElement(System.Xml.XmlReader reader, string ElementName) + { + if (!(reader.NodeType == System.Xml.XmlNodeType.Element) || (reader.Name ?? "") != (ElementName ?? "")) + { + reader.ReadToFollowing(ElementName); + } + if (reader.NodeType == System.Xml.XmlNodeType.Element) + { + return reader.ReadElementContentAsString(); + } + else + { + return ""; + } + } + + public static string readAttribute(System.Xml.XmlReader reader, string attributeName) + { + if (!(reader.NodeType == System.Xml.XmlNodeType.Attribute) || (reader.Name ?? "") != (attributeName ?? "")) + { + reader.ReadToFollowing(attributeName); + } + if (reader.NodeType == System.Xml.XmlNodeType.Attribute) + { + return reader.ReadContentAsString(); + } + else + { + return ""; + } + } + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Common/Image.cs b/Server/Core/Common/Image.cs new file mode 100644 index 00000000..d69a84ab --- /dev/null +++ b/Server/Core/Common/Image.cs @@ -0,0 +1,221 @@ +using System; +using System.Drawing; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Drawing.Imaging; + +namespace DotNetNuke.Modules.Blog.Common +{ + public class Image + { + + public const string glbJpegFileType = ".jpg"; + public const string glbPngFileType = ".png"; + public const string glbGifFileType = ".gif"; + + private Bitmap _thisImage; + private ImageFormat _imgFormat; + private float _imgRatio; + private string _extension = ""; + private string _newExtension = ""; + private string _originalFile = ""; + + public bool IsValidExtension { get; set; } = true; + public string MimeType { get; set; } = "image/jpeg"; + public int OriginalWidth { get; set; } + public int OriginalHeight { get; set; } + public double Scale { get; set; } + public int NewHeight { get; set; } + public int NewWidth { get; set; } + + public Image(string originalFilePath) + { + _originalFile = originalFilePath; + _extension = System.IO.Path.GetExtension(originalFilePath).ToLower(); + if ((_extension ?? "") == glbGifFileType | (_extension ?? "") == glbJpegFileType | (_extension ?? "") == glbPngFileType) + { + _thisImage = new Bitmap(originalFilePath); + _imgFormat = _thisImage.RawFormat; + OriginalWidth = _thisImage.Width; + OriginalHeight = _thisImage.Height; + _imgRatio = Convert.ToSingle(OriginalHeight / (double)OriginalWidth); + switch (_extension ?? "") + { + case glbGifFileType: + { + MimeType = "image/gif"; + break; + } + case glbPngFileType: + { + MimeType = "image/png"; + break; + } + } + } + else + { + IsValidExtension = false; + } + } + + public string ResizeImage(int maxWidth, int maxHeight, bool crop) + { + + switch (_extension ?? "") + { + case var @case when @case == (glbGifFileType.ToLower() ?? ""): + { + _newExtension = glbGifFileType; + return ResizeImage(maxWidth, maxHeight, crop, ImageFormat.Gif); + } + case var case1 when case1 == (glbPngFileType.ToLower() ?? ""): + { + _newExtension = glbPngFileType; + return ResizeImage(maxWidth, maxHeight, crop, ImageFormat.Png); // jpg + } + + default: + { + _newExtension = glbJpegFileType; + return ResizeImage(maxWidth, maxHeight, crop, ImageFormat.Jpeg); + } + } + + } + + public string ResizeImage(int maxWidth, int maxHeight, bool crop, ImageFormat format) + { + + try + { + + Bitmap backBuffer = null; + Graphics backBufferGraphics = null; + + if (maxHeight == -1) + { + + NewHeight = (int)Math.Round(Math.Floor((double)(_imgRatio * maxWidth))); + Scale = maxWidth / (double)OriginalWidth; + backBuffer = new Bitmap(maxWidth, NewHeight, PixelFormat.Format32bppRgb); + backBufferGraphics = Graphics.FromImage(backBuffer); + backBufferGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + backBufferGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + backBufferGraphics.DrawImage(_thisImage, 0, 0, maxWidth, NewHeight); + } + + else if (maxWidth == -1) + { + + NewWidth = (int)Math.Round(Math.Floor((double)(maxHeight / _imgRatio))); + Scale = maxHeight / (double)OriginalHeight; + backBuffer = new Bitmap(NewWidth, maxHeight, PixelFormat.Format32bppRgb); + backBufferGraphics = Graphics.FromImage(backBuffer); + backBufferGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + backBufferGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + backBufferGraphics.DrawImage(_thisImage, 0, 0, NewWidth, maxHeight); + } + + else if (crop) + { + + bool WidthOverflow = false; + Scale = maxWidth / (double)OriginalWidth; + if (maxHeight / (double)OriginalHeight > Scale) + { + Scale = maxHeight / (double)OriginalHeight; + WidthOverflow = true; + } + NewHeight = maxHeight; + NewWidth = maxWidth; + backBuffer = new Bitmap(NewWidth, NewHeight, PixelFormat.Format32bppRgb); + backBufferGraphics = Graphics.FromImage(backBuffer); + backBufferGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + backBufferGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + if (WidthOverflow) + { + int Overflow = Convert.ToInt32((Scale * OriginalWidth - maxWidth) / 2d); + backBufferGraphics.DrawImage(_thisImage, -1 * Overflow, 0, Convert.ToInt32(OriginalWidth * Scale), NewHeight); + } + else + { + int Overflow = Convert.ToInt32((Scale * OriginalHeight - maxHeight) / 2d); + backBufferGraphics.DrawImage(_thisImage, 0, -1 * Overflow, NewWidth, Convert.ToInt32(OriginalHeight * Scale)); + } + } + + else + { + + Scale = maxWidth / (double)OriginalWidth; + if (maxHeight / (double)OriginalHeight < Scale) + { + Scale = maxHeight / (double)OriginalHeight; + } + if (Scale > 1d) + { + Scale = 1d; + NewHeight = OriginalHeight; + NewWidth = OriginalWidth; + } + else + { + NewHeight = Convert.ToInt32(OriginalHeight * Scale); + NewWidth = Convert.ToInt32(OriginalWidth * Scale); + } + backBuffer = new Bitmap(NewWidth, NewHeight, PixelFormat.Format32bppRgb); + backBufferGraphics = Graphics.FromImage(backBuffer); + backBufferGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + backBufferGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; + backBufferGraphics.DrawImage(_thisImage, 0, 0, NewWidth, NewHeight); + + } + + string newFilePath = _originalFile.Substring(0, _originalFile.LastIndexOf(".")) + string.Format("-{0}-{1}-{2}", maxWidth, maxHeight, crop) + _newExtension; + backBuffer.Save(newFilePath, _imgFormat); + return newFilePath; + } + + catch (Exception ex) + { + + throw new Exception(ex.Message); + + } + + } + + public void Dispose() + { + try + { + _thisImage.Dispose(); + _thisImage = null; + } + catch + { + } + } + + + } +} \ No newline at end of file diff --git a/Server/Core/Common/LocalizedText.cs b/Server/Core/Common/LocalizedText.cs new file mode 100644 index 00000000..b378f6a0 --- /dev/null +++ b/Server/Core/Common/LocalizedText.cs @@ -0,0 +1,269 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Text; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Common +{ + [Serializable()] + public class LocalizedText : IXmlSerializable + { + + #region Properties + private Dictionary _texts = new Dictionary(); + public List Locales + { + get + { + var res = new List(); + foreach (string k in _texts.Keys) + res.Add(k); + return res; + } + } + public string this[string key] + { + get + { + if (ContainsKey(key)) + { + return _texts[key]; + } + else + { + return ""; + } + } + set + { + _texts[key] = value; + } + } + #endregion + + #region Public Methods + public Dictionary GetDictionary() + { + return _texts; + } + public bool ContainsKey(string key) + { + return _texts.ContainsKey(key); + } + public void Add(string key, string value) + { + _texts.Add(key, value); + } + public bool Remove(string key) + { + return _texts.Remove(key); + } + #endregion + + #region Constructors + public LocalizedText() : base() + { + } + + public LocalizedText(IDataReader ir, string FieldName) : base() + { + while (ir.Read()) + { + if (!ReferenceEquals(ir[FieldName], DBNull.Value)) + { + _texts.Add(Conversions.ToString(ir["Locale"]), Conversions.ToString(ir[FieldName])); + } + } + ir.Close(); + ir.Dispose(); + } + #endregion + + #region (De)Serialization + public string ToJSONArray(string DefaultLocale, string DefaultText) + { + string res = ""; + foreach (string localeCode in _texts.Keys) + { + res += ", \"" + localeCode.Replace("-", "_") + "\": \""; + res += _texts[localeCode]; + res += "\""; + } + res += ", \"" + DefaultLocale.Replace("-", "_") + "\": \""; + res += DefaultText; + res += "\""; + return res; + } + + public override string ToString() + { + var res = new StringBuilder(); + var xw = XmlWriter.Create(res); + xw.WriteStartElement("MLText"); + foreach (string l in _texts.Keys) + { + xw.WriteStartElement("Text"); + xw.WriteAttributeString("Locale", l); + xw.WriteString(_texts[l]); + xw.WriteEndElement(); + } + xw.WriteEndElement(); + xw.Flush(); + return res.ToString(); + } + + public void Deserialize(string xml) + { + var str = new System.IO.StringReader(xml); + var xr = XmlReader.Create(str); + xr.MoveToContent(); + while (xr.ReadToFollowing("Text")) + { + if (xr.MoveToAttribute("Locale")) + { + string l = xr.ReadContentAsString(); + xr.MoveToContent(); + string s = xr.ReadElementContentAsString(); + _texts.Add(l, s); + } + } + } + + public void FromXml(XmlNode xml) + { + if (xml is null) + return; + + } + + public string ToConcatenatedString() + { + var res = new StringBuilder(); + foreach (string l in _texts.Keys) + { + res.Append(_texts[l]); + res.Append(" "); + } + return res.ToString(); + } + #endregion + + #region IXmlSerializable Implementation + public XmlSchema GetSchema() + { + return null; + } + + private string readElement(XmlReader reader, string ElementName) + { + if (!(reader.NodeType == XmlNodeType.Element) || (reader.Name ?? "") != (ElementName ?? "")) + { + reader.ReadToFollowing(ElementName); + } + if (reader.NodeType == XmlNodeType.Element) + { + return reader.ReadElementContentAsString(); + } + else + { + return ""; + } + } + + private string readAttribute(XmlReader reader, string AttributeName) + { + if (reader.HasAttributes) + { + reader.MoveToAttribute(AttributeName); + return reader.Value; + } + else + { + return ""; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// ReadXml fills the object (de-serializes it) from the XmlReader passed + /// + /// + /// The XmlReader that contains the xml for the object + /// + /// [pdonker] 05/21/2008 Created + /// + /// ----------------------------------------------------------------------------- + public void ReadXml(XmlReader reader) + { + while (reader.Name == "Text") + { + reader.ReadStartElement("Text"); + string loc = readAttribute(reader, "Locale"); + if (!string.IsNullOrEmpty(loc)) + { + string txt = reader.ReadElementContentAsString(); + Add(loc, txt); + } + reader.ReadEndElement(); // Text + } + } + + public void ReadXml(XmlNode xMLText) + { + if (xMLText is null) + return; + foreach (XmlNode xText in xMLText.ChildNodes) + { + string locale = xText.Attributes["Locale"].InnerText; + _texts.Add(locale, xText.InnerText); + } + } + + /// ----------------------------------------------------------------------------- + /// + /// WriteXml converts the object to Xml (serializes it) and writes it using the XmlWriter passed + /// + /// + /// The XmlWriter that contains the xml for the object + /// + /// [pdonker] 05/21/2008 Created + /// + /// ----------------------------------------------------------------------------- + public void WriteXml(XmlWriter writer) + { + foreach (string locale in _texts.Keys) + { + writer.WriteStartElement("Text"); + writer.WriteAttributeString("Locale", locale); + writer.WriteCData(_texts[locale]); + writer.WriteEndElement(); + } + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Common/ModuleSettings.cs b/Server/Core/Common/ModuleSettings.cs new file mode 100644 index 00000000..cb5ec4cb --- /dev/null +++ b/Server/Core/Common/ModuleSettings.cs @@ -0,0 +1,415 @@ +using System; +using System.Collections; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Xml; +using DotNetNuke.Common.Utilities; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Services.Tokens; + +namespace DotNetNuke.Modules.Blog.Common +{ + [Serializable()] + public class ModuleSettings : IPropertyAccess + { + + #region Private Members + private Hashtable _allSettings = null; + private int _moduleId = -1; + private int _importedModuleId = -1; + #endregion + + #region Properties + public string Version { get; set; } = "0.0.0"; + public bool AllowWLW { get; set; } = false; + public bool AllowMultipleCategories { get; set; } = true; + public int VocabularyId { get; set; } = -1; + public bool AllowAttachments { get; set; } = true; + public SummaryType SummaryModel { get; set; } = SummaryType.HtmlIndependent; + public string StyleDetectionUrl { get; set; } = ""; + public int WLWRecentPostsMax { get; set; } = 10; + public bool AutoGenerateMissingSummary { get; set; } = true; + public int AutoGeneratedSummaryLength { get; set; } = 1000; + public string FacebookAppId { get; set; } = ""; + public int FacebookProfileIdProperty { get; set; } = -1; + + public bool ModifyPageDetails { get; set; } = false; + + public string RssEmail { get; set; } = ""; + public int RssDefaultNrItems { get; set; } = 20; + public int RssMaxNrItems { get; set; } = 50; + public int RssTtl { get; set; } = 30; + public int RssImageWidth { get; set; } = 144; + public int RssImageHeight { get; set; } = 96; + public bool RssImageSizeAllowOverride { get; set; } = true; + public bool RssAllowContentInFeed { get; set; } = true; + public string RssDefaultCopyright { get; set; } = ""; + + public string PortalTemplatesPath { get; set; } = ""; + public int IncrementViewCount { get; set; } = 60; // seconds + private string PortalModulePath { get; set; } = ""; + private string PortalModuleMapPath { get; set; } = ""; + private string _portalTemplatesMapPath = ""; + public bool UseFriendlyURLs { get; set; } = true; + + public string PortalTemplatesMapPath + { + get + { + return _portalTemplatesMapPath; + } + } + public int ModuleId + { + get + { + return _moduleId; + } + } + #endregion + + #region Constructors + public ModuleSettings(int moduleId) + { + + _moduleId = moduleId; + Version = GetType().Assembly.GetName().Version.ToString(); + _allSettings = new DotNetNuke.Entities.Modules.ModuleController().GetModule(moduleId).ModuleSettings; + bool argVariable = AllowWLW; + Extensions.ReadValue(ref _allSettings, "AllowWLW", ref argVariable); + AllowWLW = argVariable; + bool argVariable1 = AllowMultipleCategories; + Extensions.ReadValue(ref _allSettings, "AllowMultipleCategories", ref argVariable1); + AllowMultipleCategories = argVariable1; + int argVariable2 = VocabularyId; + Extensions.ReadValue(ref _allSettings, "VocabularyId", ref argVariable2); + VocabularyId = argVariable2; + bool argVariable3 = AllowAttachments; + Extensions.ReadValue(ref _allSettings, "AllowAttachments", ref argVariable3); + AllowAttachments = argVariable3; + var argVariable4 = SummaryModel; + Extensions.ReadValue(ref _allSettings, "SummaryModel", ref argVariable4); + SummaryModel = argVariable4; + string argVariable5 = StyleDetectionUrl; + Extensions.ReadValue(ref _allSettings, "StyleDetectionUrl", ref argVariable5); + StyleDetectionUrl = argVariable5; + int argVariable6 = WLWRecentPostsMax; + Extensions.ReadValue(ref _allSettings, "WLWRecentPostsMax", ref argVariable6); + WLWRecentPostsMax = argVariable6; + bool argVariable7 = ModifyPageDetails; + Extensions.ReadValue(ref _allSettings, "ModifyPageDetails", ref argVariable7); + ModifyPageDetails = argVariable7; + bool argVariable8 = AutoGenerateMissingSummary; + Extensions.ReadValue(ref _allSettings, "AutoGenerateMissingSummary", ref argVariable8); + AutoGenerateMissingSummary = argVariable8; + int argVariable9 = AutoGeneratedSummaryLength; + Extensions.ReadValue(ref _allSettings, "AutoGeneratedSummaryLength", ref argVariable9); + AutoGeneratedSummaryLength = argVariable9; + string argVariable10 = FacebookAppId; + Extensions.ReadValue(ref _allSettings, "FacebookAppId", ref argVariable10); + FacebookAppId = argVariable10; + int argVariable11 = FacebookProfileIdProperty; + Extensions.ReadValue(ref _allSettings, "FacebookProfileIdProperty", ref argVariable11); + FacebookProfileIdProperty = argVariable11; + + string argVariable12 = RssEmail; + Extensions.ReadValue(ref _allSettings, "RssEmail", ref argVariable12); + RssEmail = argVariable12; + int argVariable13 = RssDefaultNrItems; + Extensions.ReadValue(ref _allSettings, "RssDefaultNrItems", ref argVariable13); + RssDefaultNrItems = argVariable13; + int argVariable14 = RssMaxNrItems; + Extensions.ReadValue(ref _allSettings, "RssMaxNrItems", ref argVariable14); + RssMaxNrItems = argVariable14; + int argVariable15 = RssTtl; + Extensions.ReadValue(ref _allSettings, "RssTtl", ref argVariable15); + RssTtl = argVariable15; + int argVariable16 = RssImageWidth; + Extensions.ReadValue(ref _allSettings, "RssImageWidth", ref argVariable16); + RssImageWidth = argVariable16; + int argVariable17 = RssImageHeight; + Extensions.ReadValue(ref _allSettings, "RssImageHeight", ref argVariable17); + RssImageHeight = argVariable17; + bool argVariable18 = RssImageSizeAllowOverride; + Extensions.ReadValue(ref _allSettings, "RssImageSizeAllowOverride", ref argVariable18); + RssImageSizeAllowOverride = argVariable18; + bool argVariable19 = RssAllowContentInFeed; + Extensions.ReadValue(ref _allSettings, "RssAllowContentInFeed", ref argVariable19); + RssAllowContentInFeed = argVariable19; + string argVariable20 = RssDefaultCopyright; + Extensions.ReadValue(ref _allSettings, "RssDefaultCopyright", ref argVariable20); + RssDefaultCopyright = argVariable20; + int argVariable21 = IncrementViewCount; + Extensions.ReadValue(ref _allSettings, "IncrementViewCount", ref argVariable21); + IncrementViewCount = argVariable21; + + PortalModulePath = DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectory; + if (!PortalModulePath.EndsWith("/")) + { + PortalModulePath += "/"; + } + PortalModulePath += string.Format("Blog/", moduleId); + + PortalModuleMapPath = DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectoryMapPath; + if (!PortalModuleMapPath.EndsWith(@"\")) + { + PortalModuleMapPath += @"\"; + } + PortalModuleMapPath += string.Format(@"Blog\", moduleId); + + _portalTemplatesMapPath = string.Format(@"{0}Templates\", PortalModuleMapPath); + if (!System.IO.Directory.Exists(_portalTemplatesMapPath)) + { + System.IO.Directory.CreateDirectory(_portalTemplatesMapPath); + } + PortalTemplatesPath = string.Format("{0}Templates/", PortalModulePath); + + } + + public static ModuleSettings GetModuleSettings(int moduleId) + { + string CacheKey = "Blog_ModuleSettings" + moduleId.ToString(); + ModuleSettings settings = (ModuleSettings)DataCache.GetCache(CacheKey); + if (settings is null) + { + settings = new ModuleSettings(moduleId); + DataCache.SetCache(CacheKey, settings); + } + return settings; + } + #endregion + + #region Public Members + public virtual void UpdateSettings() + { + + var objModules = new DotNetNuke.Entities.Modules.ModuleController(); + objModules.UpdateModuleSetting(_moduleId, "AllowWLW", AllowWLW.ToString()); + objModules.UpdateModuleSetting(_moduleId, "AllowMultipleCategories", AllowMultipleCategories.ToString()); + objModules.UpdateModuleSetting(_moduleId, "VocabularyId", VocabularyId.ToString()); + objModules.UpdateModuleSetting(_moduleId, "AllowAttachments", AllowAttachments.ToString()); + objModules.UpdateModuleSetting(_moduleId, "SummaryModel", ((int)SummaryModel).ToString()); + objModules.UpdateModuleSetting(_moduleId, "StyleDetectionUrl", StyleDetectionUrl); + objModules.UpdateModuleSetting(_moduleId, "WLWRecentPostsMax", WLWRecentPostsMax.ToString()); + objModules.UpdateModuleSetting(_moduleId, "ModifyPageDetails", ModifyPageDetails.ToString()); + objModules.UpdateModuleSetting(_moduleId, "AutoGenerateMissingSummary", AutoGenerateMissingSummary.ToString()); + objModules.UpdateModuleSetting(_moduleId, "AutoGeneratedSummaryLength", AutoGeneratedSummaryLength.ToString()); + objModules.UpdateModuleSetting(_moduleId, "FacebookAppId", FacebookAppId); + objModules.UpdateModuleSetting(_moduleId, "FacebookProfileIdProperty", FacebookProfileIdProperty.ToString()); + + objModules.UpdateModuleSetting(_moduleId, "RssEmail", RssEmail); + objModules.UpdateModuleSetting(_moduleId, "RssDefaultNrItems", RssDefaultNrItems.ToString()); + objModules.UpdateModuleSetting(_moduleId, "RssMaxNrItems", RssMaxNrItems.ToString()); + objModules.UpdateModuleSetting(_moduleId, "RssTtl", RssTtl.ToString()); + objModules.UpdateModuleSetting(_moduleId, "RssImageWidth", RssImageWidth.ToString()); + objModules.UpdateModuleSetting(_moduleId, "RssImageHeight", RssImageHeight.ToString()); + objModules.UpdateModuleSetting(_moduleId, "RssImageSizeAllowOverride", RssImageSizeAllowOverride.ToString()); + objModules.UpdateModuleSetting(_moduleId, "RssAllowContentInFeed", RssAllowContentInFeed.ToString()); + objModules.UpdateModuleSetting(_moduleId, "RssDefaultCopyright", RssDefaultCopyright); + objModules.UpdateModuleSetting(_moduleId, "IncrementViewCount", IncrementViewCount.ToString()); + if (_importedModuleId > -1) + objModules.UpdateModuleSetting(_moduleId, "ImportedModuleID", _importedModuleId.ToString()); + + string CacheKey = "Blog_ModuleSettings" + _moduleId.ToString(); + DataCache.SetCache(CacheKey, this); + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "email": + { + return PropertyAccess.FormatString(RssEmail, strFormat); + } + case "allowmultiplecategories": + { + return AllowMultipleCategories.ToString(formatProvider); + } + case "allowattachments": + { + return AllowAttachments.ToString(formatProvider); + } + case "summarymodel": + { + return ((int)SummaryModel).ToString(); + } + + case "portaltemplatespath": + { + return PropertyAccess.FormatString(PortalTemplatesPath, strFormat); + } + case "portalmodulepath": + { + return PropertyAccess.FormatString(PortalModulePath, strFormat); + } + case "apppath": + { + return DotNetNuke.Common.Globals.ApplicationPath; + } + case "imagehandlerpath": + { + return DotNetNuke.Common.Globals.ResolveUrl(glbImageHandlerPath); + } + case "facebookappid": + { + return FacebookAppId; + } + + default: + { + PropertyNotFound = true; + break; + } + } + + return Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + #region Serialization + public void Serialize(XmlWriter writer) + { + writer.WriteStartElement("Settings"); + writer.WriteElementString("ModuleID", ModuleId.ToString()); + writer.WriteElementString("AllowWLW", AllowWLW.ToString()); + writer.WriteElementString("AllowMultipleCategories", AllowMultipleCategories.ToString()); + writer.WriteElementString("VocabularyId", VocabularyId.ToString()); + writer.WriteElementString("AllowAttachments", AllowAttachments.ToString()); + writer.WriteElementString("SummaryModel", SummaryModel.ToString()); + writer.WriteElementString("StyleDetectionUrl", StyleDetectionUrl); + writer.WriteElementString("WLWRecentPostsMax", WLWRecentPostsMax.ToString()); + writer.WriteElementString("ModifyPageDetails", ModifyPageDetails.ToString()); + writer.WriteElementString("AutoGenerateMissingSummary", AutoGenerateMissingSummary.ToString()); + writer.WriteElementString("AutoGeneratedSummaryLength", AutoGeneratedSummaryLength.ToString()); + writer.WriteElementString("FacebookAppId", FacebookAppId); + writer.WriteElementString("FacebookProfileIdProperty", FacebookProfileIdProperty.ToString()); + + writer.WriteElementString("RssEmail", RssEmail); + writer.WriteElementString("RssDefaultNrItems", RssDefaultNrItems.ToString()); + writer.WriteElementString("RssMaxNrItems", RssMaxNrItems.ToString()); + writer.WriteElementString("RssTtl", RssTtl.ToString()); + writer.WriteElementString("RssImageWidth", RssImageWidth.ToString()); + writer.WriteElementString("RssImageHeight", RssImageHeight.ToString()); + writer.WriteElementString("RssImageSizeAllowOverride", RssImageSizeAllowOverride.ToString()); + writer.WriteElementString("RssAllowContentInFeed", RssAllowContentInFeed.ToString()); + writer.WriteElementString("RssDefaultCopyright", RssDefaultCopyright); + writer.WriteElementString("IncrementViewCount", IncrementViewCount.ToString()); + writer.WriteEndElement(); // settings + } + + public void FromXml(XmlNode xml) + { + if (xml is null) + return; + Extensions.ReadValue(ref xml, "ModuleID", ref _importedModuleId); + bool argVariable = AllowWLW; + Extensions.ReadValue(ref xml, "AllowWLW", ref argVariable); + AllowWLW = argVariable; + bool argVariable1 = AllowMultipleCategories; + Extensions.ReadValue(ref xml, "AllowMultipleCategories", ref argVariable1); + AllowMultipleCategories = argVariable1; + int argVariable2 = VocabularyId; + Extensions.ReadValue(ref xml, "VocabularyId", ref argVariable2); + VocabularyId = argVariable2; + bool argVariable3 = AllowAttachments; + Extensions.ReadValue(ref xml, "AllowAttachments", ref argVariable3); + AllowAttachments = argVariable3; + var argVariable4 = SummaryModel; + Extensions.ReadValue(ref xml, "SummaryModel", ref argVariable4); + SummaryModel = argVariable4; + string argVariable5 = StyleDetectionUrl; + Extensions.ReadValue(ref xml, "StyleDetectionUrl", ref argVariable5); + StyleDetectionUrl = argVariable5; + int argVariable6 = WLWRecentPostsMax; + Extensions.ReadValue(ref xml, "WLWRecentPostsMax", ref argVariable6); + WLWRecentPostsMax = argVariable6; + bool argVariable7 = ModifyPageDetails; + Extensions.ReadValue(ref xml, "ModifyPageDetails", ref argVariable7); + ModifyPageDetails = argVariable7; + bool argVariable8 = AutoGenerateMissingSummary; + Extensions.ReadValue(ref xml, "AutoGenerateMissingSummary", ref argVariable8); + AutoGenerateMissingSummary = argVariable8; + int argVariable9 = AutoGeneratedSummaryLength; + Extensions.ReadValue(ref xml, "AutoGeneratedSummaryLength", ref argVariable9); + AutoGeneratedSummaryLength = argVariable9; + string argVariable10 = FacebookAppId; + Extensions.ReadValue(ref xml, "FacebookAppId", ref argVariable10); + FacebookAppId = argVariable10; + int argVariable11 = FacebookProfileIdProperty; + Extensions.ReadValue(ref xml, "FacebookProfileIdProperty", ref argVariable11); + FacebookProfileIdProperty = argVariable11; + + string argVariable12 = RssEmail; + Extensions.ReadValue(ref xml, "RssEmail", ref argVariable12); + RssEmail = argVariable12; + int argVariable13 = RssDefaultNrItems; + Extensions.ReadValue(ref xml, "RssDefaultNrItems", ref argVariable13); + RssDefaultNrItems = argVariable13; + int argVariable14 = RssMaxNrItems; + Extensions.ReadValue(ref xml, "RssMaxNrItems", ref argVariable14); + RssMaxNrItems = argVariable14; + int argVariable15 = RssTtl; + Extensions.ReadValue(ref xml, "RssTtl", ref argVariable15); + RssTtl = argVariable15; + int argVariable16 = RssImageWidth; + Extensions.ReadValue(ref xml, "RssImageWidth", ref argVariable16); + RssImageWidth = argVariable16; + int argVariable17 = RssImageHeight; + Extensions.ReadValue(ref xml, "RssImageHeight", ref argVariable17); + RssImageHeight = argVariable17; + bool argVariable18 = RssImageSizeAllowOverride; + Extensions.ReadValue(ref xml, "RssImageSizeAllowOverride", ref argVariable18); + RssImageSizeAllowOverride = argVariable18; + bool argVariable19 = RssAllowContentInFeed; + Extensions.ReadValue(ref xml, "RssAllowContentInFeed", ref argVariable19); + RssAllowContentInFeed = argVariable19; + string argVariable20 = RssDefaultCopyright; + Extensions.ReadValue(ref xml, "RssDefaultCopyright", ref argVariable20); + RssDefaultCopyright = argVariable20; + int argVariable21 = IncrementViewCount; + Extensions.ReadValue(ref xml, "IncrementViewCount", ref argVariable21); + IncrementViewCount = argVariable21; + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Common/ModuleUrls.cs b/Server/Core/Common/ModuleUrls.cs new file mode 100644 index 00000000..96aacaf9 --- /dev/null +++ b/Server/Core/Common/ModuleUrls.cs @@ -0,0 +1,266 @@ +using System.Collections.Generic; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Services.Tokens; + +namespace DotNetNuke.Modules.Blog.Common +{ + public class ModuleUrls : IPropertyAccess + { + + #region Properties + public int TabId { get; set; } = -1; + public int ParentTabId { get; set; } = -1; + public int BlogId { get; set; } = -1; + public int ContentItemId { get; set; } = -1; + public int TermId { get; set; } = -1; + public int AuthorId { get; set; } = -1; + private Dictionary Cache { get; set; } = new Dictionary(); + #endregion + + #region Constructors + public ModuleUrls(int tabId, int blogId, int contentItemId, int termId, int authorId) + { + TabId = tabId; + BlogId = blogId; + ContentItemId = contentItemId; + TermId = termId; + AuthorId = authorId; + } + + public ModuleUrls(int tabId, int parenttabId, int blogId, int contentItemId, int termId, int authorId) + { + TabId = tabId; + ParentTabId = parenttabId; + BlogId = blogId; + ContentItemId = contentItemId; + TermId = termId; + AuthorId = authorId; + } + #endregion + + #region Public Methods + public string GetUrl(bool includeBlog, bool includePost, bool includeTerm, bool includeAuthor, bool includeEnding) + { + string urlType = ""; + if (includeBlog) + urlType = "blog"; + if (includePost) + urlType += "post"; + if (includeTerm) + urlType += "term"; + if (includeAuthor) + urlType += "author"; + string cacheKey = string.Format("{0}:{1}", urlType, includeEnding.ToString().ToLower()); + if (Cache.ContainsKey(cacheKey)) + return Cache[cacheKey]; + BuildUrl(urlType); + return Cache[cacheKey]; + } + #endregion + + #region Private Methods + private void BuildUrl(string urlType) + { + var @params = new List(); + switch (urlType ?? "") + { + case "blog": + { + if (BlogId > -1) + @params.Add("Blog=" + BlogId.ToString()); + break; + } + case "post": + { + if (ContentItemId > -1) + @params.Add("Post=" + ContentItemId.ToString()); + break; + } + case "term": + { + if (TermId > -1) + @params.Add("Term=" + TermId.ToString()); + break; + } + case "author": + { + if (AuthorId > -1) + @params.Add("Author=" + AuthorId.ToString()); + break; + } + case "blogpost": + { + if (BlogId > -1) + @params.Add("Blog=" + BlogId.ToString()); + if (ContentItemId > -1) + @params.Add("Post=" + ContentItemId.ToString()); + break; + } + case "blogterm": + { + if (BlogId > -1) + @params.Add("Blog=" + BlogId.ToString()); + if (TermId > -1) + @params.Add("Term=" + TermId.ToString()); + break; + } + case "blogauthor": + { + if (BlogId > -1) + @params.Add("Blog=" + BlogId.ToString()); + if (AuthorId > -1) + @params.Add("Author=" + AuthorId.ToString()); + break; + } + case "postterm": + { + if (ContentItemId > -1) + @params.Add("Post=" + ContentItemId.ToString()); + if (TermId > -1) + @params.Add("Term=" + TermId.ToString()); + break; + } + case "postauthor": + { + if (ContentItemId > -1) + @params.Add("Post=" + ContentItemId.ToString()); + if (AuthorId > -1) + @params.Add("Author=" + AuthorId.ToString()); + break; + } + case "termauthor": + { + if (TermId > -1) + @params.Add("Term=" + TermId.ToString()); + if (AuthorId > -1) + @params.Add("Author=" + AuthorId.ToString()); + break; + } + case "blogpostterm": + { + if (BlogId > -1) + @params.Add("Blog=" + BlogId.ToString()); + if (ContentItemId > -1) + @params.Add("Post=" + ContentItemId.ToString()); + if (TermId > -1) + @params.Add("Term=" + TermId.ToString()); + break; + } + case "blogpostauthor": + { + if (BlogId > -1) + @params.Add("Blog=" + BlogId.ToString()); + if (ContentItemId > -1) + @params.Add("Post=" + ContentItemId.ToString()); + if (AuthorId > -1) + @params.Add("Author=" + AuthorId.ToString()); + break; + } + case "blogtermauthor": + { + if (BlogId > -1) + @params.Add("Blog=" + BlogId.ToString()); + if (TermId > -1) + @params.Add("Term=" + TermId.ToString()); + if (AuthorId > -1) + @params.Add("Author=" + AuthorId.ToString()); + break; + } + case "posttermauthor": + { + if (ContentItemId > -1) + @params.Add("Post=" + ContentItemId.ToString()); + if (TermId > -1) + @params.Add("Term=" + TermId.ToString()); + if (AuthorId > -1) + @params.Add("Author=" + AuthorId.ToString()); + break; + } + case "blogposttermauthor": + case "all": + { + if (BlogId > -1) + @params.Add("Blog=" + BlogId.ToString()); + if (ContentItemId > -1) + @params.Add("Post=" + ContentItemId.ToString()); + if (TermId > -1) + @params.Add("Term=" + TermId.ToString()); + if (AuthorId > -1) + @params.Add("Author=" + AuthorId.ToString()); + break; + } + case "parenturl": + { + TabId = ParentTabId; + break; + } + } + string BaseUrl = DotNetNuke.Common.Globals.NavigateURL(TabId, "", @params.ToArray()); + string BaseUrlPlusEnding; + if (BaseUrl.Contains("?")) + { + BaseUrlPlusEnding = BaseUrl + "&"; + } + else + { + BaseUrlPlusEnding = BaseUrl + "?"; + } + Cache.Add(string.Format("{0}:false", urlType), BaseUrl); + Cache.Add(string.Format("{0}:true", urlType), BaseUrlPlusEnding); + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + strFormat = strFormat.ToLower(); + if (strFormat != "true" && strFormat != "false") + strFormat = "false"; + strPropertyName = strPropertyName.ToLower(); + string cacheKey = string.Format("{0}:{1}", strPropertyName, strFormat); + if (Cache.ContainsKey(cacheKey)) + return Cache[cacheKey]; + BuildUrl(strPropertyName); + return Cache[cacheKey]; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Common/PostBodyAndSummary.cs b/Server/Core/Common/PostBodyAndSummary.cs new file mode 100644 index 00000000..38d6cdc0 --- /dev/null +++ b/Server/Core/Common/PostBodyAndSummary.cs @@ -0,0 +1,221 @@ +using System.Web; +using static DotNetNuke.Modules.Blog.Common.Globals; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Modules.Blog.Entities.Posts; +using Microsoft.VisualBasic; + +namespace DotNetNuke.Modules.Blog.Common +{ + public class PostBodyAndSummary + { + + public string Body { get; set; } = ""; + public LocalizedText BodyLocalizations { get; set; } = new LocalizedText(); + public string Summary { get; set; } = ""; + public LocalizedText SummaryLocalizations { get; set; } = new LocalizedText(); + + #region Constructors + public PostBodyAndSummary(Controls.LongTextEdit contentEditor, Controls.LongTextEdit summaryEditor, SummaryType summaryModel, bool includeLocalizations, bool autoGenerateSummaryIfEmpty, int autoGenerateLength) + { + Body = contentEditor.DefaultText; + Summary = Strings.Trim(summaryEditor.DefaultText); + if (Summary == "<p>&#160;</p>") + Summary = ""; // an empty editor in DNN returns this + if (includeLocalizations) + { + BodyLocalizations = contentEditor.LocalizedTexts; + SummaryLocalizations = summaryEditor.LocalizedTexts; + } + switch (summaryModel) + { + case SummaryType.HtmlIndependent: + { + break; + } + case SummaryType.HtmlPrecedesPost: + { + Body = Summary + Body; + foreach (string l in SummaryLocalizations.Locales) + BodyLocalizations[l] = SummaryLocalizations[l] + BodyLocalizations[l]; + break; + } + case SummaryType.PlainTextIndependent: + { + Summary = RemoveHtmlTags(Summary); + foreach (string l in SummaryLocalizations.Locales) + SummaryLocalizations[l] = RemoveHtmlTags(SummaryLocalizations[l]); + break; + } + } + if (autoGenerateSummaryIfEmpty & autoGenerateLength > 0) + { + if (string.IsNullOrEmpty(Summary)) + Summary = GetSummary(Body, autoGenerateLength, summaryModel, true); + foreach (string l in SummaryLocalizations.Locales) + { + if (string.IsNullOrEmpty(SummaryLocalizations[l])) + SummaryLocalizations[l] = GetSummary(BodyLocalizations[l], autoGenerateLength, summaryModel, true); + } + } + } + + public PostBodyAndSummary(PostInfo Post, SummaryType summaryModel, bool includeLocalizations, bool autoGenerateSummaryIfEmpty, int autoGenerateLength) + { + Body = HttpUtility.HtmlDecode(Post.Content); + if (Body is null) + Body = ""; + if (summaryModel == SummaryType.PlainTextIndependent) + { + Summary = Post.Summary; + } + else + { + Summary = HttpUtility.HtmlDecode(Post.Summary); + } + if (summaryModel == SummaryType.HtmlPrecedesPost) + { + Body = Body.Substring(Summary.Length); + } + if (includeLocalizations) + { + foreach (string l in Post.TitleLocalizations.Locales) + { + string lBody = ""; + if (Post.ContentLocalizations.ContainsKey(l)) + lBody = Post.ContentLocalizations[l]; + string lSummary = ""; + if (Post.SummaryLocalizations.ContainsKey(l)) + lSummary = Post.SummaryLocalizations[l]; + BodyLocalizations.Add(l, lBody); + if (summaryModel == SummaryType.PlainTextIndependent) + { + SummaryLocalizations.Add(l, lSummary); + } + else + { + SummaryLocalizations.Add(l, HttpUtility.HtmlDecode(lSummary)); + } + if (summaryModel == SummaryType.HtmlPrecedesPost) + { + BodyLocalizations[l] = BodyLocalizations[l].Substring(SummaryLocalizations[l].Length); + } + } + } + if (autoGenerateSummaryIfEmpty & autoGenerateLength > 0) + { + if (string.IsNullOrEmpty(Summary)) + Summary = GetSummary(Body, autoGenerateLength, summaryModel, false); + foreach (string l in SummaryLocalizations.Locales) + { + if (string.IsNullOrEmpty(SummaryLocalizations[l])) + SummaryLocalizations[l] = GetSummary(BodyLocalizations[l], autoGenerateLength, summaryModel, false); + } + } + } + + public PostBodyAndSummary(Services.WLW.MetaWeblog.Post post, SummaryType summaryModel, bool autoGenerateSummaryIfEmpty, int autoGenerateLength) + { + switch (summaryModel) + { + case SummaryType.HtmlIndependent: + { + Body = post.description; + break; + } + case SummaryType.HtmlPrecedesPost: + { + Body = post.mt_text_more; + Summary = post.description; // plain text + break; + } + + default: + { + Body = post.description; + Summary = post.mt_excerpt; + break; + } + } + if (autoGenerateSummaryIfEmpty & autoGenerateLength > 0) + { + if (string.IsNullOrEmpty(Summary)) + Summary = GetSummary(Body, autoGenerateLength, summaryModel, false); + } + } + #endregion + + #region Writing + public void WriteToPost(ref PostInfo Post, SummaryType summaryModel, bool htmlEncode, bool includeLocalizations) + { + if (htmlEncode) + { + Body = HttpUtility.HtmlEncode(Body); + if (!(summaryModel == SummaryType.PlainTextIndependent)) + { + Summary = HttpUtility.HtmlEncode(Summary); + } + if (includeLocalizations) + { + foreach (string l in SummaryLocalizations.Locales) + { + BodyLocalizations[l] = HttpUtility.HtmlEncode(BodyLocalizations[l]); + SummaryLocalizations[l] = HttpUtility.HtmlEncode(SummaryLocalizations[l]); + } + } + } + Post.Content = Body; + Post.Summary = Summary; + if (includeLocalizations) + { + Post.ContentLocalizations = BodyLocalizations; + Post.SummaryLocalizations = SummaryLocalizations; + } + } + + public void WriteToPost(ref Services.WLW.MetaWeblog.Post post, SummaryType summaryModel) + { + switch (summaryModel) + { + case SummaryType.HtmlIndependent: + { + post.description = Body; + break; + } + case SummaryType.HtmlPrecedesPost: + { + post.mt_text_more = Body; + post.description = Summary; // plain text + break; + } + + default: + { + post.description = Body; + post.mt_excerpt = Summary; + break; + } + } + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Common/ViewSettings.cs b/Server/Core/Common/ViewSettings.cs new file mode 100644 index 00000000..0b20b184 --- /dev/null +++ b/Server/Core/Common/ViewSettings.cs @@ -0,0 +1,374 @@ +using System; +using System.Collections; +using System.Collections.Generic; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Xml; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Common +{ + [Serializable()] + public class ViewSettings : IPropertyAccess + { + + #region Private Members + private Hashtable _allSettings = null; + private int _tabModuleId = -1; + #endregion + + #region Properties + public string Template { get; set; } = "[G]_default"; + public int BlogModuleId { get; set; } = -1; + public bool ShowAllLocales { get; set; } = true; + public bool ModifyPageDetails { get; set; } = false; + public bool AddCanonicalTag { get; set; } = false; + public bool ShowManagementPanel { get; set; } = false; + public bool ShowManagementPanelViewMode { get; set; } = true; + public bool HideUnpublishedBlogsViewMode { get; set; } = false; + public bool HideUnpublishedBlogsEditMode { get; set; } = false; + public bool AllowComments { get; set; } = true; + public int BlogId { get; set; } = -1; + public string Categories { get; set; } = ""; + public int AuthorId { get; set; } = -1; + public Dictionary TemplateSettings { get; set; } = new Dictionary(); + private Templating.TemplateManager TemplateManager { get; set; } + internal bool CanCache { get; set; } = true; + #endregion + + #region ReadOnly Properties + private List _categoryList; + public List CategoryList + { + get + { + if (_categoryList is null) + { + _categoryList = new List(); + foreach (string c in Categories.Split(',')) + { + if (Information.IsNumeric(c)) + { + _categoryList.Add(int.Parse(c)); + } + } + } + return _categoryList; + } + } + #endregion + + #region Constructors + public ViewSettings(int tabModuleId) : this(tabModuleId, false) + { + } + + public ViewSettings(int tabModuleId, bool justLoadSettings) + { + + _tabModuleId = tabModuleId; + _allSettings = new DotNetNuke.Entities.Modules.ModuleController().GetTabModule(tabModuleId).TabModuleSettings; + string argVariable = Template; + Extensions.ReadValue(ref _allSettings, "Template", ref argVariable); + Template = argVariable; + int argVariable1 = BlogModuleId; + Extensions.ReadValue(ref _allSettings, "BlogModuleId", ref argVariable1); + BlogModuleId = argVariable1; + bool argVariable2 = ShowAllLocales; + Extensions.ReadValue(ref _allSettings, "ShowAllLocales", ref argVariable2); + ShowAllLocales = argVariable2; + bool argVariable3 = ModifyPageDetails; + Extensions.ReadValue(ref _allSettings, "ModifyPageDetails", ref argVariable3); + ModifyPageDetails = argVariable3; + bool argVariable4 = AddCanonicalTag; + Extensions.ReadValue(ref _allSettings, "AddCanonicalTag", ref argVariable4); + AddCanonicalTag = argVariable4; + bool argVariable5 = ShowManagementPanel; + Extensions.ReadValue(ref _allSettings, "ShowManagementPanel", ref argVariable5); + ShowManagementPanel = argVariable5; + bool argVariable6 = ShowManagementPanelViewMode; + Extensions.ReadValue(ref _allSettings, "ShowManagementPanelViewMode", ref argVariable6); + ShowManagementPanelViewMode = argVariable6; + bool argVariable7 = HideUnpublishedBlogsViewMode; + Extensions.ReadValue(ref _allSettings, "HideUnpublishedBlogsViewMode", ref argVariable7); + HideUnpublishedBlogsViewMode = argVariable7; + bool argVariable8 = HideUnpublishedBlogsEditMode; + Extensions.ReadValue(ref _allSettings, "HideUnpublishedBlogsEditMode", ref argVariable8); + HideUnpublishedBlogsEditMode = argVariable8; + bool argVariable9 = AllowComments; + Extensions.ReadValue(ref _allSettings, "AllowComments", ref argVariable9); + AllowComments = argVariable9; + int argVariable10 = BlogId; + Extensions.ReadValue(ref _allSettings, "BlogId", ref argVariable10); + BlogId = argVariable10; + string argVariable11 = Categories; + Extensions.ReadValue(ref _allSettings, "Categories", ref argVariable11); + Categories = argVariable11; + int argVariable12 = AuthorId; + Extensions.ReadValue(ref _allSettings, "AuthorId", ref argVariable12); + AuthorId = argVariable12; + if (BlogModuleId > -1 & tabModuleId > -1) // security check + { + var parentModule = new DotNetNuke.Entities.Modules.ModuleController().GetModule(BlogModuleId); + var thisTabModule = new DotNetNuke.Entities.Modules.ModuleController().GetTabModule(tabModuleId); + if (parentModule is null || parentModule.PortalID != thisTabModule.PortalID) + { + BlogModuleId = -1; + CanCache = false; + } + } + if (justLoadSettings) + return; + + // Template Settings - first load defaults + SetTemplate(Template); + + } + + public static ViewSettings GetViewSettings(int tabModuleId) + { + string CacheKey = "Blog_TabModuleSettings" + tabModuleId.ToString(); + ViewSettings settings = (ViewSettings)DotNetNuke.Common.Utilities.DataCache.GetCache(CacheKey); + if (settings is null) + { + settings = new ViewSettings(tabModuleId); + if (settings.CanCache) + DotNetNuke.Common.Utilities.DataCache.SetCache(CacheKey, settings); + } + return settings; + } + #endregion + + #region Public Members + public virtual void UpdateSettings() + { + UpdateSettings(_tabModuleId); + } + + public virtual void UpdateSettings(int tabModuleId) + { + + var objModules = new DotNetNuke.Entities.Modules.ModuleController(); + objModules.UpdateTabModuleSetting(tabModuleId, "Template", Template); + objModules.UpdateTabModuleSetting(tabModuleId, "BlogModuleId", BlogModuleId.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "ShowAllLocales", ShowAllLocales.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "ModifyPageDetails", ModifyPageDetails.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "AddCanonicalTag", AddCanonicalTag.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "ShowManagementPanel", ShowManagementPanel.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "ShowManagementPanelViewMode", ShowManagementPanelViewMode.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "HideUnpublishedBlogsViewMode", HideUnpublishedBlogsViewMode.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "HideUnpublishedBlogsEditMode", HideUnpublishedBlogsEditMode.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "AllowComments", AllowComments.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "BlogId", BlogId.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "Categories", Categories.ToString()); + objModules.UpdateTabModuleSetting(tabModuleId, "AuthorId", AuthorId.ToString()); + _categoryList = null; + + string CacheKey = "Blog_TabModuleSettings" + tabModuleId.ToString(); + DotNetNuke.Common.Utilities.DataCache.SetCache(CacheKey, this); + + } + + public void SaveTemplateSettings() + { + var objModules = new DotNetNuke.Entities.Modules.ModuleController(); + foreach (string key in TemplateSettings.Keys) + objModules.UpdateTabModuleSetting(_tabModuleId, "t_" + key, TemplateSettings[key]); + string CacheKey = "Blog_TabModuleSettings" + _tabModuleId.ToString(); + DotNetNuke.Common.Utilities.DataCache.SetCache(CacheKey, this); + } + + public void SetTemplateSetting(string key, string value) + { + if (!TemplateSettings.ContainsKey(key)) + { + TemplateSettings.Add(key, value); + } + else + { + TemplateSettings[key] = value; + } + } + #endregion + + #region Private Methods + private void SetTemplate(string template) + { + TemplateManager = new Templating.TemplateManager(DotNetNuke.Entities.Portals.PortalSettings.Current, template); + TemplateSettings.Clear(); + foreach (Templating.TemplateSetting st in TemplateManager.TemplateSettings.Settings) + TemplateSettings.Add(st.Key, st.DefaultValue); + foreach (string key in _allSettings.Keys) + { + if (key.StartsWith("t_")) + { + SetTemplateSetting(Strings.Mid(key, 3), Conversions.ToString(_allSettings[key])); + } + } + } + #endregion + + #region IPropertyAccess + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "tabmoduleid": + { + return _tabModuleId.ToString(OutputFormat, formatProvider); + } + case "templatepath": + { + return PropertyAccess.FormatString(TemplateManager.TemplatePath, strFormat); + } + case "templatemappath": + { + return PropertyAccess.FormatString(TemplateManager.TemplateMapPath, strFormat); + } + + default: + { + if (TemplateSettings.ContainsKey(strPropertyName)) + { + return PropertyAccess.FormatString(TemplateSettings[strPropertyName], strFormat); + } + if (strPropertyName.StartsWith("t_")) + strPropertyName = Strings.Mid(strPropertyName, 3); + if (TemplateSettings.ContainsKey(strPropertyName)) + { + return PropertyAccess.FormatString(TemplateSettings[strPropertyName], strFormat); + } + switch (strPropertyName.ToLower() ?? "") + { + case "termid": + case "categories": // termid is for legacy purposes + { + return Categories; + } + case "authorid": + { + return AuthorId.ToString(OutputFormat, formatProvider); + } + case "blogid": + { + return BlogId.ToString(OutputFormat, formatProvider); + } + case "blogmoduleid": + { + return BlogModuleId.ToString(OutputFormat, formatProvider); + } + + default: + { + return ""; + } + } + + break; + } + } + } + #endregion + + #region Serialization + public void Serialize(XmlWriter writer) + { + writer.WriteStartElement("ViewSettings"); + writer.WriteElementString("Template", Template); + writer.WriteElementString("BlogModuleId", BlogModuleId.ToString()); + writer.WriteElementString("ShowAllLocales", ShowAllLocales.ToString()); + writer.WriteElementString("ModifyPageDetails", ModifyPageDetails.ToString()); + writer.WriteElementString("AddCanonicalTag", AddCanonicalTag.ToString()); + writer.WriteElementString("ShowManagementPanel", ShowManagementPanel.ToString()); + writer.WriteElementString("ShowManagementPanelViewMode", ShowManagementPanelViewMode.ToString()); + writer.WriteElementString("HideUnpublishedBlogsViewMode", HideUnpublishedBlogsViewMode.ToString()); + writer.WriteElementString("HideUnpublishedBlogsEditMode", HideUnpublishedBlogsEditMode.ToString()); + writer.WriteElementString("AllowComments", AllowComments.ToString()); + writer.WriteElementString("BlogId", BlogId.ToString()); + writer.WriteElementString("AuthorId", AuthorId.ToString()); + writer.WriteEndElement(); // viewsettings + } + + public void FromXml(XmlNode xml) + { + if (xml is null) + return; + string argVariable = Template; + Extensions.ReadValue(ref xml, "Template", ref argVariable); + Template = argVariable; + int argVariable1 = BlogModuleId; + Extensions.ReadValue(ref xml, "BlogModuleId", ref argVariable1); + BlogModuleId = argVariable1; + bool argVariable2 = ShowAllLocales; + Extensions.ReadValue(ref xml, "ShowAllLocales", ref argVariable2); + ShowAllLocales = argVariable2; + bool argVariable3 = ModifyPageDetails; + Extensions.ReadValue(ref xml, "ModifyPageDetails", ref argVariable3); + ModifyPageDetails = argVariable3; + bool argVariable4 = AddCanonicalTag; + Extensions.ReadValue(ref xml, "AddCanonicalTag", ref argVariable4); + AddCanonicalTag = argVariable4; + bool argVariable5 = ShowManagementPanel; + Extensions.ReadValue(ref xml, "ShowManagementPanel", ref argVariable5); + ShowManagementPanel = argVariable5; + bool argVariable6 = ShowManagementPanelViewMode; + Extensions.ReadValue(ref xml, "ShowManagementPanelViewMode", ref argVariable6); + ShowManagementPanelViewMode = argVariable6; + bool argVariable7 = HideUnpublishedBlogsViewMode; + Extensions.ReadValue(ref xml, "HideUnpublishedBlogsViewMode", ref argVariable7); + HideUnpublishedBlogsViewMode = argVariable7; + bool argVariable8 = HideUnpublishedBlogsEditMode; + Extensions.ReadValue(ref xml, "HideUnpublishedBlogsEditMode", ref argVariable8); + HideUnpublishedBlogsEditMode = argVariable8; + bool argVariable9 = AllowComments; + Extensions.ReadValue(ref xml, "AllowComments", ref argVariable9); + AllowComments = argVariable9; + int argVariable10 = BlogId; + Extensions.ReadValue(ref xml, "BlogId", ref argVariable10); + BlogId = argVariable10; + int argVariable11 = AuthorId; + Extensions.ReadValue(ref xml, "AuthorId", ref argVariable11); + AuthorId = argVariable11; + _categoryList = null; + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Common/WebPage.cs b/Server/Core/Common/WebPage.cs new file mode 100644 index 00000000..e253bd86 --- /dev/null +++ b/Server/Core/Common/WebPage.cs @@ -0,0 +1,119 @@ +using System; +using System.IO; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Net; + +namespace DotNetNuke.Modules.Blog.Common +{ + public class WebPage + { + + #region Properties + private readonly Uri url; + public Uri Uri + { + get + { + return url; + } + } + #endregion + + #region Constructors + internal WebPage(Uri filePath) + { + if (filePath is null) + { + throw new ArgumentNullException("filePath"); + } + url = filePath; + } + #endregion + + #region Public Methods + public WebResponse GetWebResponse() + { + var response = GetWebRequest().GetResponse(); + long contentLength = response.ContentLength; + if (contentLength == -1) + { + string headerContentLength = response.Headers["Content-Length"]; + if (!string.IsNullOrEmpty(headerContentLength)) + { + contentLength = long.Parse(headerContentLength); + } + } + if (contentLength <= -1) + { + response.Close(); + return null; + } + return response; + } + + private WebRequest _webRequest; + + public string GetFileAsString() + { + try + { + using (var response = GetWebResponse()) + { + if (response is null) + { + return string.Empty; + } + using (var reader = new StreamReader(response.GetResponseStream())) + { + return reader.ReadToEnd(); + } + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(new Exception(string.Format("Track/Pingback Verification Request To '{0}' Failed", Uri.PathAndQuery), ex)); + return ""; + } + } + #endregion + + #region Private Methods + private WebRequest GetWebRequest() + { + + if (_webRequest is null) + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Uri); + request.Headers["Accept-Encoding"] = "gzip"; + request.Headers["Accept-Language"] = "en-us"; + request.Credentials = CredentialCache.DefaultNetworkCredentials; + request.AutomaticDecompression = DecompressionMethods.GZip; + request.Timeout = 1000 * 30; // 30 secs timeout + _webRequest = request; + } + return _webRequest; + + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Data/DataProvider.cs b/Server/Core/Data/DataProvider.cs new file mode 100644 index 00000000..f8a6d0de --- /dev/null +++ b/Server/Core/Data/DataProvider.cs @@ -0,0 +1,30 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +namespace DotNetNuke.Modules.Blog.Data +{ + + public abstract partial class DataProvider + { + + } +} \ No newline at end of file diff --git a/Server/Core/Data/DataProvider_CMD.cs b/Server/Core/Data/DataProvider_CMD.cs new file mode 100644 index 00000000..ff2f47e1 --- /dev/null +++ b/Server/Core/Data/DataProvider_CMD.cs @@ -0,0 +1,68 @@ +using System; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +namespace DotNetNuke.Modules.Blog.Data +{ + + public abstract partial class DataProvider + { + + public abstract void AddPostView(int contentItemId); + public abstract void ApproveComment(int commentId); + public abstract int AddCommentKarma(int commentId, int userId, int karma); + public abstract void DeleteBlogPermissions(int blogId); + public abstract IDataReader GetAuthors(int moduleId, int blogID); + public abstract IDataReader GetBlog(int blogId, int userId, string locale); + public abstract IDataReader GetBlogCalendar(int moduleId, int blogId, string locale); + public abstract IDataReader GetBlogLocalizations(int blogId); + public abstract IDataReader GetBlogPermissionsByBlog(int blogId); + public abstract IDataReader GetBlogsByModule(int moduleId, int userId, string locale); + public abstract IDataReader GetBlogsByPortal(int portalId, int userId, string locale); + public abstract IDataReader GetComment(int commentID, int userID); + public abstract IDataReader GetCommentsByContentItem(int contentItemId, bool includeNonApproved, int userID); + public abstract IDataReader GetCommentsByModuleId(int moduleId, int userID, int pageIndex, int pageSize, string orderBy); + public abstract IDataReader GetPostByLegacyEntryId(int entryId, int portalId, string locale); + public abstract IDataReader GetPostByLegacyUrl(string url, int portalId, string locale); + public abstract IDataReader GetPostLocalizations(int contentItemId); + public abstract IDataReader GetPosts(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, int published, string limitToLocale, DateTime endDate, int authorUserId, bool onlyActionable, int pageIndex, int pageSize, string orderBy); + public abstract IDataReader GetPostsByTerm(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, int termID, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy); + public abstract IDataReader GetPostsByCategory(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, string categories, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy); + public abstract IDataReader GetTerm(int termId, int moduleId, string locale); + public abstract IDataReader GetTermLocalizations(int termId); + public abstract IDataReader GetTermsByModule(int moduleId, string locale); + public abstract IDataReader GetTermsByPost(int contentItemId, int moduleId, string locale); + public abstract IDataReader GetTermsByVocabulary(int moduleId, int vocabularyId, string locale); + public abstract IDataReader GetUserPermissionsByModule(int moduleID, int userId); + public abstract IDataReader GetUsersByBlogPermission(int portalId, int blogId, int permissionId); + public abstract IDataReader SearchPosts(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, string searchText, bool searchTitle, bool searchContents, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy); + public abstract IDataReader SearchPostsByTerm(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, int termID, string searchText, bool searchTitle, bool searchContents, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy); + public abstract IDataReader SearchPostsByCategory(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, string categories, string searchText, bool searchTitle, bool searchContents, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy); + public abstract void SetBlogLocalization(int blogID, string locale, string title, string description); + public abstract void SetPostLocalization(int postID, string locale, string title, string summary, string content, int updatedByUser); + public abstract int SetTerm(int termID, int vocabularyID, int parentTermID, int viewOrder, string name, string description, int createdByUserID); + public abstract void SetTermLocalization(int termID, string locale, string name, string description); + public abstract void UpdateModuleWiring(int portalId, int oldModuleId, int newModuleId); + + } + +} \ No newline at end of file diff --git a/Server/Core/Data/DataProvider_CRUD.cs b/Server/Core/Data/DataProvider_CRUD.cs new file mode 100644 index 00000000..e78fc54d --- /dev/null +++ b/Server/Core/Data/DataProvider_CRUD.cs @@ -0,0 +1,91 @@ +using System; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +namespace DotNetNuke.Modules.Blog.Data +{ + + public abstract partial class DataProvider + { + + #region Shared/Static Methods + + // singleton reference to the instantiated object + private static DataProvider objProvider = null; + + // constructor + static DataProvider() + { + CreateProvider(); + } + + // dynamically create provider + private static void CreateProvider() + { + objProvider = (DataProvider)Framework.Reflection.CreateObject("data", "DotNetNuke.Modules.Blog.Data", ""); + } + + // return the provider + public static new DataProvider Instance() + { + return objProvider; + } + + #endregion + + #region General Methods + public abstract object GetNull(object Field); + #endregion + + #region BlogPermission Methods + public abstract IDataReader GetBlogPermission(int blogId, int permissionId, int roleId, int userId); + public abstract void AddBlogPermission(bool allowAccess, int blogId, DateTime expires, int permissionId, int roleId, int userId); + public abstract void UpdateBlogPermission(bool allowAccess, int blogId, DateTime expires, int permissionId, int roleId, int userId); + public abstract void DeleteBlogPermission(int blogId, int permissionId, int roleId, int userId); + #endregion + + #region Blog Methods + public abstract int AddBlog(bool autoApprovePingBack, int moduleID, bool autoApproveTrackBack, string copyright, string description, bool enablePingBackReceive, bool enablePingBackSend, bool enableTrackBackReceive, bool enableTrackBackSend, bool fullLocalization, string image, bool includeAuthorInFeed, bool includeImagesInFeed, string locale, bool mustApproveGhostPosts, int ownerUserId, bool publishAsOwner, bool published, bool syndicated, string syndicationEmail, string title, int createdByUser); + public abstract void UpdateBlog(bool autoApprovePingBack, int moduleID, bool autoApproveTrackBack, int blogID, string copyright, string description, bool enablePingBackReceive, bool enablePingBackSend, bool enableTrackBackReceive, bool enableTrackBackSend, bool fullLocalization, string image, bool includeAuthorInFeed, bool includeImagesInFeed, string locale, bool mustApproveGhostPosts, int ownerUserId, bool publishAsOwner, bool published, bool syndicated, string syndicationEmail, string title, int updatedByUser); + public abstract void DeleteBlog(int blogID); + #endregion + + #region Comment Methods + public abstract int AddComment(bool approved, string author, string comment, int contentItemId, string email, int parentId, string website, int createdByUser); + public abstract void UpdateComment(bool approved, string author, string comment, int commentID, int contentItemId, string email, int parentId, string website, int updatedByUser); + public abstract void DeleteComment(int commentID); + #endregion + + #region LegacyUrl Methods + public abstract void AddLegacyUrl(int contentItemId, int entryId, string url); + #endregion + + #region Post Methods + public abstract IDataReader GetPost(int contentItemId, int moduleId, string locale); + public abstract int AddPost(bool allowComments, int blogID, string content, string copyright, bool displayCopyright, string image, string locale, bool published, DateTime publishedOnDate, string summary, string termIds, string title, int viewCount, int createdByUser); + public abstract void UpdatePost(bool allowComments, int blogID, string content, int contentItemId, string copyright, bool displayCopyright, string image, string locale, bool published, DateTime publishedOnDate, string summary, string termIds, string title, int viewCount, int updatedByUser); + public abstract void DeletePost(int contentItemId); + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Data/DataProvider_FK.cs b/Server/Core/Data/DataProvider_FK.cs new file mode 100644 index 00000000..cda5752b --- /dev/null +++ b/Server/Core/Data/DataProvider_FK.cs @@ -0,0 +1,46 @@ +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +namespace DotNetNuke.Modules.Blog.Data +{ + + public abstract partial class DataProvider + { + + #region BlogPermission Methods + public abstract IDataReader GetBlogPermissionsByBlog(int blogID, int StartRowIndex, int MaximumRows, string OrderBy); + #endregion + + #region Blog Methods + public abstract IDataReader GetBlogsByCreatedByUser(int userID, int StartRowIndex, int MaximumRows, string OrderBy); + #endregion + + #region Comment Methods + #endregion + + #region Post Methods + public abstract IDataReader GetPostsByBlog(int blogID, string displayLocale, int pageIndex, int pageSize, string orderBy); + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Data/SqlDataProvider.cs b/Server/Core/Data/SqlDataProvider.cs new file mode 100644 index 00000000..b1d86dfc --- /dev/null +++ b/Server/Core/Data/SqlDataProvider.cs @@ -0,0 +1,31 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +namespace DotNetNuke.Modules.Blog.Data +{ + + public partial class SqlDataProvider + { + + } + +} \ No newline at end of file diff --git a/Server/Core/Data/SqlDataProvider_CMD.cs b/Server/Core/Data/SqlDataProvider_CMD.cs new file mode 100644 index 00000000..15c99073 --- /dev/null +++ b/Server/Core/Data/SqlDataProvider_CMD.cs @@ -0,0 +1,210 @@ +using System; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using Microsoft.ApplicationBlocks.Data; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Data +{ + + public partial class SqlDataProvider + { + + public override int AddCommentKarma(int commentId, int userId, int karma) + { + return Conversions.ToInteger(SqlHelper.ExecuteScalar(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "AddCommentKarma", commentId, userId, karma)); + } + + public override void AddPostView(int contentItemId) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "AddPostView", contentItemId); + } + + public override void ApproveComment(int commentId) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "ApproveComment", commentId); + } + + public override void DeleteBlogPermissions(int blogId) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "DeleteBlogPermissions", blogId); + } + + public override IDataReader GetAuthors(int moduleId, int blogID) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetAuthors", moduleId, blogID); + } + + public override IDataReader GetBlog(int blogId, int userId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetBlog", blogId, userId, locale); + } + + public override IDataReader GetBlogCalendar(int moduleId, int blogId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetBlogCalendar", moduleId, blogId, GetNull(locale)); + } + + public override IDataReader GetBlogLocalizations(int blogId) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetBlogLocalizations", blogId); + } + + public override IDataReader GetBlogPermissionsByBlog(int blogId) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetBlogPermissionsByBlog", blogId); + } + + public override IDataReader GetBlogsByModule(int moduleId, int userId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetBlogsByModule", moduleId, userId, locale); + } + + public override IDataReader GetBlogsByPortal(int portalId, int userId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetBlogsByPortal", portalId, userId, locale); + } + + public override IDataReader GetComment(int commentID, int userID) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetComment", commentID, userID); + } + + public override IDataReader GetCommentsByContentItem(int contentItemId, bool includeNonApproved, int userID) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetCommentsByContentItem", contentItemId, includeNonApproved, userID); + } + + public override IDataReader GetCommentsByModuleId(int moduleId, int userID, int pageIndex, int pageSize, string orderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetCommentsByModuleId", moduleId, userID, pageIndex, pageSize, orderBy); + } + + public override IDataReader GetPostByLegacyEntryId(int entryId, int portalId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetPostByLegacyEntryId", entryId, portalId, locale); + } + + public override IDataReader GetPostByLegacyUrl(string url, int portalId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetPostByLegacyUrl", url, portalId, locale); + } + + public override IDataReader GetPostLocalizations(int contentItemId) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetPostLocalizations", contentItemId); + } + + public override IDataReader GetPosts(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, int published, string limitToLocale, DateTime endDate, int authorUserId, bool onlyActionable, int pageIndex, int pageSize, string orderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetPosts", moduleId, blogID, displayLocale, userId, userIsAdmin, published, GetNull(limitToLocale), GetNull(endDate), authorUserId, onlyActionable, pageIndex, pageSize, orderBy); + } + + public override IDataReader GetPostsByTerm(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, int termID, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetPostsByTerm", moduleId, blogID, displayLocale, userId, userIsAdmin, termID, published, GetNull(limitToLocale), GetNull(endDate), authorUserId, pageIndex, pageSize, orderBy); + } + + public override IDataReader GetPostsByCategory(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, string categories, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetPostsByCategory", moduleId, blogID, displayLocale, userId, userIsAdmin, categories, published, GetNull(limitToLocale), GetNull(endDate), authorUserId, pageIndex, pageSize, orderBy); + } + + public override IDataReader GetTerm(int termId, int moduleId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetTerm", termId, moduleId, locale); + } + + public override IDataReader GetTermLocalizations(int termId) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetTermLocalizations", termId); + } + + public override IDataReader GetTermsByModule(int moduleId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetTermsByModule", moduleId, locale); + } + + public override IDataReader GetTermsByPost(int contentItemId, int moduleId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetTermsByPost", contentItemId, moduleId, locale); + } + + public override IDataReader GetTermsByVocabulary(int moduleId, int vocabularyId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetTermsByVocabulary", moduleId, vocabularyId, locale); + } + + public override IDataReader GetUserPermissionsByModule(int moduleID, int userId) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetUserPermissionsByModule", moduleID, userId); + } + + public override IDataReader GetUsersByBlogPermission(int portalId, int blogId, int permissionId) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetUsersByBlogPermission", portalId, blogId, permissionId); + } + + public override IDataReader SearchPosts(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, string searchText, bool searchTitle, bool searchContents, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "SearchPosts", moduleId, blogID, displayLocale, userId, userIsAdmin, searchText, searchTitle, searchContents, published, GetNull(limitToLocale), GetNull(endDate), authorUserId, pageIndex, pageSize, orderBy); + } + + public override IDataReader SearchPostsByTerm(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, int termID, string searchText, bool searchTitle, bool searchContents, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "SearchPostsByTerm", moduleId, blogID, displayLocale, userId, userIsAdmin, termID, searchText, searchTitle, searchContents, published, GetNull(limitToLocale), GetNull(endDate), authorUserId, pageIndex, pageSize, orderBy); + } + + public override IDataReader SearchPostsByCategory(int moduleId, int blogID, string displayLocale, int userId, bool userIsAdmin, string categories, string searchText, bool searchTitle, bool searchContents, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "SearchPostsByCategory", moduleId, blogID, displayLocale, userId, userIsAdmin, categories, searchText, searchTitle, searchContents, published, GetNull(limitToLocale), GetNull(endDate), authorUserId, pageIndex, pageSize, orderBy); + } + + + public override void SetBlogLocalization(int blogID, string locale, string title, string description) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "SetBlogLocalization", blogID, locale, title, description); + } + + public override void SetPostLocalization(int postID, string locale, string title, string summary, string content, int updatedByUser) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "SetPostLocalization", postID, locale, title, summary, content, updatedByUser); + } + + public override int SetTerm(int termID, int vocabularyID, int parentTermID, int viewOrder, string name, string description, int createdByUserID) + { + return Conversions.ToInteger(SqlHelper.ExecuteScalar(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "SetTerm", termID, vocabularyID, parentTermID, viewOrder, name, description, createdByUserID)); + } + + public override void SetTermLocalization(int termID, string locale, string name, string description) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "SetTermLocalization", termID, locale, name, description); + } + + public override void UpdateModuleWiring(int portalId, int oldModuleId, int newModuleId) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "UpdateModuleWiring", portalId, oldModuleId, newModuleId); + } + + } + +} \ No newline at end of file diff --git a/Server/Core/Data/SqlDataProvider_CRUD.cs b/Server/Core/Data/SqlDataProvider_CRUD.cs new file mode 100644 index 00000000..3046963a --- /dev/null +++ b/Server/Core/Data/SqlDataProvider_CRUD.cs @@ -0,0 +1,221 @@ +using System; +using System.Data; +using DotNetNuke.Framework.Providers; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using Microsoft.ApplicationBlocks.Data; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Data +{ + + public partial class SqlDataProvider : DataProvider + { + + #region Private Members + + private const string ProviderType = "data"; + private const string ModuleQualifier = "Blog_"; + + private ProviderConfiguration _providerConfiguration = ProviderConfiguration.GetProviderConfiguration(ProviderType); + private string _connectionString; + private string _providerPath; + private string _objectQualifier; + private string _databaseOwner; + + #endregion + + #region Constructors + + public SqlDataProvider() + { + + // Read the configuration specific information for this provider + Provider objProvider = (Provider)_providerConfiguration.Providers[_providerConfiguration.DefaultProvider]; + + // Get Connection string from web.config + _connectionString = DotNetNuke.Common.Utilities.Config.GetConnectionString(); + + if (string.IsNullOrEmpty(_connectionString)) + { + // Use connection string specified in provider + _connectionString = objProvider.Attributes["connectionString"]; + } + + _providerPath = objProvider.Attributes["providerPath"]; + + _objectQualifier = objProvider.Attributes["objectQualifier"]; + if (!string.IsNullOrEmpty(_objectQualifier) & _objectQualifier.EndsWith("_") == false) + { + _objectQualifier += "_"; + } + + _databaseOwner = objProvider.Attributes["databaseOwner"]; + if (!string.IsNullOrEmpty(_databaseOwner) & _databaseOwner.EndsWith(".") == false) + { + _databaseOwner += "."; + } + + } + + #endregion + + #region Properties + + public string ConnectionString + { + get + { + return _connectionString; + } + } + + public string ProviderPath + { + get + { + return _providerPath; + } + } + + public string ObjectQualifier + { + get + { + return _objectQualifier; + } + } + + public string DatabaseOwner + { + get + { + return _databaseOwner; + } + } + + #endregion + + #region General Methods + public override object GetNull(object Field) + { + return DotNetNuke.Common.Utilities.Null.GetNull(Field, DBNull.Value); + } + #endregion + + + #region BlogPermission Methods + + public override IDataReader GetBlogPermission(int blogId, int permissionId, int roleId, int userId) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetBlogPermission", blogId, permissionId, roleId, userId); + } + + public override void AddBlogPermission(bool allowAccess, int blogId, DateTime expires, int permissionId, int roleId, int userId) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "AddBlogPermission", allowAccess, blogId, GetNull(expires), permissionId, roleId, userId); + } + + public override void UpdateBlogPermission(bool allowAccess, int blogId, DateTime expires, int permissionId, int roleId, int userId) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "UpdateBlogPermission", allowAccess, blogId, GetNull(expires), permissionId, roleId, userId); + } + + public override void DeleteBlogPermission(int blogId, int permissionId, int roleId, int userId) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "DeleteBlogPermission", blogId, permissionId, roleId, userId); + } + + #endregion + + #region Blog Methods + + public override int AddBlog(bool autoApprovePingBack, int moduleID, bool autoApproveTrackBack, string copyright, string description, bool enablePingBackReceive, bool enablePingBackSend, bool enableTrackBackReceive, bool enableTrackBackSend, bool fullLocalization, string image, bool includeAuthorInFeed, bool includeImagesInFeed, string locale, bool mustApproveGhostPosts, int ownerUserId, bool publishAsOwner, bool published, bool syndicated, string syndicationEmail, string title, int createdByUser) + { + return Conversions.ToInteger(SqlHelper.ExecuteScalar(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "AddBlog", autoApprovePingBack, moduleID, autoApproveTrackBack, GetNull(copyright), GetNull(description), enablePingBackReceive, enablePingBackSend, enableTrackBackReceive, enableTrackBackSend, fullLocalization, GetNull(image), includeAuthorInFeed, includeImagesInFeed, locale, mustApproveGhostPosts, ownerUserId, publishAsOwner, published, syndicated, GetNull(syndicationEmail), title, createdByUser)); + } + + public override void UpdateBlog(bool autoApprovePingBack, int moduleID, bool autoApproveTrackBack, int blogID, string copyright, string description, bool enablePingBackReceive, bool enablePingBackSend, bool enableTrackBackReceive, bool enableTrackBackSend, bool fullLocalization, string image, bool includeAuthorInFeed, bool includeImagesInFeed, string locale, bool mustApproveGhostPosts, int ownerUserId, bool publishAsOwner, bool published, bool syndicated, string syndicationEmail, string title, int updatedByUser) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "UpdateBlog", autoApprovePingBack, moduleID, autoApproveTrackBack, blogID, GetNull(copyright), GetNull(description), enablePingBackReceive, enablePingBackSend, enableTrackBackReceive, enableTrackBackSend, fullLocalization, GetNull(image), includeAuthorInFeed, includeImagesInFeed, locale, mustApproveGhostPosts, ownerUserId, publishAsOwner, published, syndicated, GetNull(syndicationEmail), title, updatedByUser); + } + + public override void DeleteBlog(int blogID) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "DeleteBlog", blogID); + } + + #endregion + + #region Comment Methods + + public override int AddComment(bool approved, string author, string comment, int contentItemId, string email, int parentId, string website, int createdByUser) + { + return Conversions.ToInteger(SqlHelper.ExecuteScalar(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "AddComment", approved, GetNull(author), comment, contentItemId, GetNull(email), GetNull(parentId), GetNull(website), createdByUser)); + } + + public override void UpdateComment(bool approved, string author, string comment, int commentID, int contentItemId, string email, int parentId, string website, int updatedByUser) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "UpdateComment", approved, GetNull(author), comment, commentID, contentItemId, GetNull(email), GetNull(parentId), GetNull(website), updatedByUser); + } + + public override void DeleteComment(int commentID) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "DeleteComment", commentID); + } + + #endregion + + #region LegacyUrl Methods + public override void AddLegacyUrl(int contentItemId, int entryId, string url) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "AddLegacyUrl", contentItemId, GetNull(entryId), url); + } + #endregion + + #region Post Methods + + public override IDataReader GetPost(int contentItemId, int moduleId, string locale) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetPost", contentItemId, moduleId, locale); + } + + public override int AddPost(bool allowComments, int blogID, string content, string copyright, bool displayCopyright, string image, string locale, bool published, DateTime publishedOnDate, string summary, string termIds, string title, int viewCount, int createdByUser) + { + return Conversions.ToInteger(SqlHelper.ExecuteScalar(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "AddPost", allowComments, blogID, content, copyright, displayCopyright, image, GetNull(locale), published, publishedOnDate, summary, termIds, title, viewCount, createdByUser)); + } + + public override void UpdatePost(bool allowComments, int blogID, string content, int contentItemId, string copyright, bool displayCopyright, string image, string locale, bool published, DateTime publishedOnDate, string summary, string termIds, string title, int viewCount, int updatedByUser) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "UpdatePost", allowComments, blogID, content, contentItemId, copyright, displayCopyright, image, GetNull(locale), published, publishedOnDate, summary, termIds, title, viewCount, updatedByUser); + } + + public override void DeletePost(int contentItemId) + { + SqlHelper.ExecuteNonQuery(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "DeletePost", contentItemId); + } + + #endregion + + + } + +} \ No newline at end of file diff --git a/Server/Core/Data/SqlDataProvider_FK.cs b/Server/Core/Data/SqlDataProvider_FK.cs new file mode 100644 index 00000000..2e175ba9 --- /dev/null +++ b/Server/Core/Data/SqlDataProvider_FK.cs @@ -0,0 +1,59 @@ +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using Microsoft.ApplicationBlocks.Data; + +namespace DotNetNuke.Modules.Blog.Data +{ + + public partial class SqlDataProvider + { + + #region BlogPermission Methods + public override IDataReader GetBlogPermissionsByBlog(int blogID, int StartRowIndex, int MaximumRows, string OrderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetBlogPermissionsByBlog", blogID, StartRowIndex, MaximumRows, OrderBy.ToUpper()); + } + + #endregion + + #region Blog Methods + + public override IDataReader GetBlogsByCreatedByUser(int userID, int StartRowIndex, int MaximumRows, string OrderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetBlogsByCreatedByUser", userID, StartRowIndex, MaximumRows, OrderBy.ToUpper()); + } + + #endregion + + #region Comment Methods + #endregion + + #region Post Methods + public override IDataReader GetPostsByBlog(int blogID, string displayLocale, int pageIndex, int pageSize, string orderBy) + { + return SqlHelper.ExecuteReader(ConnectionString, DatabaseOwner + ObjectQualifier + ModuleQualifier + "GetPostsByBlog", blogID, displayLocale, pageIndex, pageSize, orderBy); + } + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/DotNetNuke.Modules.Blog.Core.csproj b/Server/Core/DotNetNuke.Modules.Blog.Core.csproj new file mode 100644 index 00000000..89088153 --- /dev/null +++ b/Server/Core/DotNetNuke.Modules.Blog.Core.csproj @@ -0,0 +1,30 @@ + + + DotNetNuke.Modules.Blog.Core + net472 + bin + false + false + Peter Donker + DotNetNuke Community + Blog + 2025 + Blog + 0.0.1.0 + 0.0.1.0 + The DotNetNuke Blog module is an easy to use content publishing module that is tightly integrated with the core DotNetNuke framework. It can be used in single or multi-author environments and also permits content authoring using off-site tools such as Windows Live Writer. + en-US + + Library + + Portable + + + + + + + + + + diff --git a/Server/Core/Entities/Blogs/BlogCalendarInfo.cs b/Server/Core/Entities/Blogs/BlogCalendarInfo.cs new file mode 100644 index 00000000..419e0363 --- /dev/null +++ b/Server/Core/Entities/Blogs/BlogCalendarInfo.cs @@ -0,0 +1,219 @@ +using System; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic; + +namespace DotNetNuke.Modules.Blog.Entities.Blogs +{ + public class BlogCalendarInfo : IHydratable, IPropertyAccess + { + + #region ML Properties + public int ParentTabID { get; set; } = -1; + #endregion + + #region Public Properties + [DataMember()] + public int PostYear { get; set; } = -1; + [DataMember()] + public int PostMonth { get; set; } = -1; + [DataMember()] + public int PostCount { get; set; } = -1; + [DataMember()] + public int ViewCount { get; set; } = -1; + + private DateTime _FirstDay = DateTime.MinValue; + public DateTime FirstDay + { + get + { + if (_FirstDay == DateTime.MinValue) + { + _FirstDay = DateAndTime.DateSerial(PostYear, PostMonth, 1); + } + return _FirstDay; + } + } + + private DateTime _FirstDayNextMonth = DateTime.MinValue; + public DateTime FirstDayNextMonth + { + get + { + if (_FirstDayNextMonth == DateTime.MinValue) + { + _FirstDayNextMonth = DateAndTime.DateSerial(PostYear, PostMonth, 1).AddMonths(1); + } + return _FirstDayNextMonth; + } + } + + private DateTime _LastDay = DateTime.MinValue; + public DateTime LastDay + { + get + { + if (_LastDay == DateTime.MinValue) + { + _LastDay = DateAndTime.DateSerial(PostYear, PostMonth, 1).AddMonths(1).AddDays(-1); + } + return _LastDay; + } + } + #endregion + + #region IHydratable Implementation + /// ----------------------------------------------------------------------------- + /// + /// Fill hydrates the object from a Datareader + /// + /// The Fill method is used by the CBO method to hydrtae the object + /// rather than using the more expensive Refection methods. + /// + /// [pdonker] 02/16/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void Fill(IDataReader dr) + { + PostYear = Convert.ToInt32(Null.SetNull(dr["PostYear"], PostYear)); + PostMonth = Convert.ToInt32(Null.SetNull(dr["PostMonth"], PostMonth)); + PostCount = Convert.ToInt32(Null.SetNull(dr["PostCount"], PostCount)); + ViewCount = Convert.ToInt32(Null.SetNull(dr["ViewCount"], ViewCount)); + } + /// ----------------------------------------------------------------------------- + /// + /// Gets and sets the Key ID + /// + /// The KeyID property is part of the IHydratble interface. It is used + /// as the key property when creating a Dictionary + /// + /// [pdonker] 02/16/2013 Created + /// + /// ----------------------------------------------------------------------------- + public int KeyID + { + get + { + return default; + } + set + { + } + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "postyear": + { + return PostYear.ToString(OutputFormat, formatProvider); + } + case "postmonth": + { + return PostMonth.ToString(OutputFormat, formatProvider); + } + case "postcount": + { + return PostCount.ToString(OutputFormat, formatProvider); + } + case "viewcount": + { + return ViewCount.ToString(OutputFormat, formatProvider); + } + case "firstday": + { + return FirstDay.ToString(OutputFormat, formatProvider); + } + case "lastday": + { + return LastDay.ToString(OutputFormat, formatProvider); + } + case "firstdaynextmonth": + { + return FirstDayNextMonth.ToString(OutputFormat, formatProvider); + } + case "parenturl": + { + return PermaLink(ParentTabID); + } + + default: + { + PropertyNotFound = true; + break; + } + } + return Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + public string PermaLink(int strParentTabID) + { + var oTabController = new DotNetNuke.Entities.Tabs.TabController(); + var oParentTab = oTabController.GetTab(strParentTabID, DotNetNuke.Entities.Portals.PortalSettings.Current.PortalId, false); + _permaLink = string.Empty; + return PermaLink(oParentTab); + } + + public string PermaLink(DotNetNuke.Entities.Portals.PortalSettings portalSettings) + { + return PermaLink(portalSettings.ActiveTab); + } + + private string _permaLink = ""; + public string PermaLink(DotNetNuke.Entities.Tabs.TabInfo tab) + { + if (string.IsNullOrEmpty(_permaLink)) + { + _permaLink = DotNetNuke.Common.Globals.ApplicationURL(tab.TabID) + "&end=" + FirstDayNextMonth.ToString(); + _permaLink = DotNetNuke.Common.Globals.FriendlyUrl(tab, _permaLink); + } + return _permaLink; + } + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Blogs/BlogInfo.cs b/Server/Core/Entities/Blogs/BlogInfo.cs new file mode 100644 index 00000000..2056ffe2 --- /dev/null +++ b/Server/Core/Entities/Blogs/BlogInfo.cs @@ -0,0 +1,91 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; +using static DotNetNuke.Common.Globals; +using static DotNetNuke.Modules.Blog.Common.Globals; + +namespace DotNetNuke.Modules.Blog.Entities.Blogs +{ + + public partial class BlogInfo + { + + private Security.Permissions.BlogPermissionCollection _permissions; + public Security.Permissions.BlogPermissionCollection Permissions + { + get + { + if (_permissions is null) + { + _permissions = Security.Permissions.BlogPermissionsController.GetBlogPermissionsCollection(BlogID); + } + return _permissions; + } + set + { + _permissions = value; + } + } + + [DataMember()] + public bool CanEdit { get; set; } = false; + [DataMember()] + public bool CanAdd { get; set; } = false; + [DataMember()] + public bool CanApprove { get; set; } = false; + [DataMember()] + public bool IsOwner { get; set; } = false; + + public string PermaLink(int strParentTabID) + { + var oTabController = new DotNetNuke.Entities.Tabs.TabController(); + var oParentTab = oTabController.GetTab(strParentTabID, DotNetNuke.Entities.Portals.PortalSettings.Current.PortalId, false); + _permaLink = string.Empty; + return PermaLink(oParentTab); + } + + public string PermaLink(DotNetNuke.Entities.Portals.PortalSettings portalSettings) + { + return PermaLink(portalSettings.ActiveTab); + } + + private string _permaLink = ""; + public string PermaLink(DotNetNuke.Entities.Tabs.TabInfo tab) + { + if (string.IsNullOrEmpty(_permaLink)) + { + _permaLink = ApplicationURL(tab.TabID) + "&Blog=" + BlogID.ToString(); + if (DotNetNuke.Entities.Host.Host.UseFriendlyUrls) + { + _permaLink = FriendlyUrl(tab, _permaLink, GetSafePageName(LocalizedTitle)); + } + else + { + _permaLink = ResolveUrl(_permaLink); + } + } + return _permaLink; + } + + } + +} \ No newline at end of file diff --git a/Server/Core/Entities/Blogs/BlogInfo_Interfaces.cs b/Server/Core/Entities/Blogs/BlogInfo_Interfaces.cs new file mode 100644 index 00000000..541dcaf8 --- /dev/null +++ b/Server/Core/Entities/Blogs/BlogInfo_Interfaces.cs @@ -0,0 +1,583 @@ +using System; +using System.Collections.Generic; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Modules; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Entities.Blogs +{ + + [Serializable()] + [XmlRoot("Blog")] + [DataContract()] + public partial class BlogInfo : IHydratable, IPropertyAccess, IXmlSerializable + { + + #region ML Properties + public int ParentTabID { get; set; } = -1; + #endregion + + #region IHydratable Implementation + /// ----------------------------------------------------------------------------- + /// + /// Fill hydrates the object from a Datareader + /// + /// The Fill method is used by the CBO method to hydrtae the object + /// rather than using the more expensive Refection methods. + /// + /// [pdonker] 02/16/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void Fill(IDataReader dr) + { + BlogID = Convert.ToInt32(Null.SetNull(dr["BlogID"], BlogID)); + ModuleID = Convert.ToInt32(Null.SetNull(dr["ModuleID"], ModuleID)); + Title = Convert.ToString(Null.SetNull(dr["Title"], Title)); + Description = Convert.ToString(Null.SetNull(dr["Description"], Description)); + Image = Convert.ToString(Null.SetNull(dr["Image"], Image)); + Locale = Convert.ToString(Null.SetNull(dr["Locale"], Locale)); + FullLocalization = Convert.ToBoolean(Null.SetNull(dr["FullLocalization"], FullLocalization)); + Published = Convert.ToBoolean(Null.SetNull(dr["Published"], Published)); + IncludeImagesInFeed = Convert.ToBoolean(Null.SetNull(dr["IncludeImagesInFeed"], IncludeImagesInFeed)); + IncludeAuthorInFeed = Convert.ToBoolean(Null.SetNull(dr["IncludeAuthorInFeed"], IncludeAuthorInFeed)); + Syndicated = Convert.ToBoolean(Null.SetNull(dr["Syndicated"], Syndicated)); + SyndicationEmail = Convert.ToString(Null.SetNull(dr["SyndicationEmail"], SyndicationEmail)); + Copyright = Convert.ToString(Null.SetNull(dr["Copyright"], Copyright)); + MustApproveGhostPosts = Convert.ToBoolean(Null.SetNull(dr["MustApproveGhostPosts"], MustApproveGhostPosts)); + PublishAsOwner = Convert.ToBoolean(Null.SetNull(dr["PublishAsOwner"], PublishAsOwner)); + EnablePingBackSend = Convert.ToBoolean(Null.SetNull(dr["EnablePingBackSend"], EnablePingBackSend)); + EnablePingBackReceive = Convert.ToBoolean(Null.SetNull(dr["EnablePingBackReceive"], EnablePingBackReceive)); + AutoApprovePingBack = Convert.ToBoolean(Null.SetNull(dr["AutoApprovePingBack"], AutoApprovePingBack)); + EnableTrackBackSend = Convert.ToBoolean(Null.SetNull(dr["EnableTrackBackSend"], EnableTrackBackSend)); + EnableTrackBackReceive = Convert.ToBoolean(Null.SetNull(dr["EnableTrackBackReceive"], EnableTrackBackReceive)); + AutoApproveTrackBack = Convert.ToBoolean(Null.SetNull(dr["AutoApproveTrackBack"], AutoApproveTrackBack)); + OwnerUserId = Convert.ToInt32(Null.SetNull(dr["OwnerUserId"], OwnerUserId)); + CreatedByUserID = Convert.ToInt32(Null.SetNull(dr["CreatedByUserID"], CreatedByUserID)); + CreatedOnDate = Conversions.ToDate(Null.SetNull(dr["CreatedOnDate"], CreatedOnDate)); + LastModifiedByUserID = Convert.ToInt32(Null.SetNull(dr["LastModifiedByUserID"], LastModifiedByUserID)); + LastModifiedOnDate = Conversions.ToDate(Null.SetNull(dr["LastModifiedOnDate"], LastModifiedOnDate)); + DisplayName = Convert.ToString(Null.SetNull(dr["DisplayName"], DisplayName)); + Email = Convert.ToString(Null.SetNull(dr["Email"], Email)); + Username = Convert.ToString(Null.SetNull(dr["Username"], Username)); + NrPosts = Convert.ToInt32(Null.SetNull(dr["NrPosts"], NrPosts)); + LastPublishDate = Conversions.ToDate(Null.SetNull(dr["LastPublishDate"], LastPublishDate)); + NrViews = Convert.ToInt32(Null.SetNull(dr["NrViews"], NrViews)); + FirstPublishDate = Conversions.ToDate(Null.SetNull(dr["FirstPublishDate"], FirstPublishDate)); + AltLocale = Convert.ToString(Null.SetNull(dr["AltLocale"], AltLocale)); + AltTitle = Convert.ToString(Null.SetNull(dr["AltTitle"], AltTitle)); + AltDescription = Convert.ToString(Null.SetNull(dr["AltDescription"], AltDescription)); + CanEdit = Convert.ToBoolean(Null.SetNull(dr["CanEdit"], CanEdit)); + CanAdd = Convert.ToBoolean(Null.SetNull(dr["CanAdd"], CanAdd)); + CanApprove = Convert.ToBoolean(Null.SetNull(dr["CanApprove"], CanApprove)); + + } + /// ----------------------------------------------------------------------------- + /// + /// Gets and sets the Key ID + /// + /// The KeyID property is part of the IHydratble interface. It is used + /// as the key property when creating a Dictionary + /// + /// [pdonker] 02/16/2013 Created + /// + /// ----------------------------------------------------------------------------- + public int KeyID + { + get + { + return BlogID; + } + set + { + BlogID = value; + } + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "blogid": + { + return BlogID.ToString(OutputFormat, formatProvider); + } + case "moduleid": + { + return ModuleID.ToString(OutputFormat, formatProvider); + } + case "title": + { + return PropertyAccess.FormatString(Title, strFormat); + } + case "description": + { + return PropertyAccess.FormatString(Description, strFormat); + } + case "image": + { + return PropertyAccess.FormatString(Image, strFormat); + } + case "hasimage": + { + return (!string.IsNullOrEmpty(Image)).ToString(formatProvider); + } + case "locale": + { + return PropertyAccess.FormatString(Locale, strFormat); + } + case "fulllocalization": + { + return FullLocalization.ToString(); + } + case "fulllocalizationyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(FullLocalization, formatProvider); + } + case "published": + { + return Published.ToString(); + } + case "publishedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(Published, formatProvider); + } + case "includeimagesinfeed": + { + return IncludeImagesInFeed.ToString(); + } + case "includeimagesinfeedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(IncludeImagesInFeed, formatProvider); + } + case "includeauthorinfeed": + { + return IncludeAuthorInFeed.ToString(); + } + case "includeauthorinfeedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(IncludeAuthorInFeed, formatProvider); + } + case "syndicated": + { + return Syndicated.ToString(); + } + case "syndicatedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(Syndicated, formatProvider); + } + case "syndicationemail": + { + return PropertyAccess.FormatString(SyndicationEmail, strFormat); + } + case "copyright": + { + return PropertyAccess.FormatString(Copyright, strFormat); + } + case "mustapproveghostposts": + { + return MustApproveGhostPosts.ToString(); + } + case "mustapproveghostpostsyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(MustApproveGhostPosts, formatProvider); + } + case "publishasowner": + { + return PublishAsOwner.ToString(); + } + case "publishasowneryesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(PublishAsOwner, formatProvider); + } + case "enablepingbacksend": + { + return EnablePingBackSend.ToString(); + } + case "enablepingbacksendyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(EnablePingBackSend, formatProvider); + } + case "enablepingbackreceive": + { + return EnablePingBackReceive.ToString(); + } + case "enablepingbackreceiveyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(EnablePingBackReceive, formatProvider); + } + case "autoapprovepingback": + { + return AutoApprovePingBack.ToString(); + } + case "autoapprovepingbackyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(AutoApprovePingBack, formatProvider); + } + case "enabletrackbacksend": + { + return EnableTrackBackSend.ToString(); + } + case "enabletrackbacksendyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(EnableTrackBackSend, formatProvider); + } + case "enabletrackbackreceive": + { + return EnableTrackBackReceive.ToString(); + } + case "enabletrackbackreceiveyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(EnableTrackBackReceive, formatProvider); + } + case "autoapprovetrackback": + { + return AutoApproveTrackBack.ToString(); + } + case "autoapprovetrackbackyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(AutoApproveTrackBack, formatProvider); + } + case "owneruserid": + { + return OwnerUserId.ToString(OutputFormat, formatProvider); + } + case "createdbyuserid": + { + return CreatedByUserID.ToString(OutputFormat, formatProvider); + } + case "createdondate": + { + return CreatedOnDate.ToString(OutputFormat, formatProvider); + } + case "lastmodifiedbyuserid": + { + return LastModifiedByUserID.ToString(OutputFormat, formatProvider); + } + case "lastmodifiedondate": + { + return LastModifiedOnDate.ToString(OutputFormat, formatProvider); + } + case "displayname": + { + return PropertyAccess.FormatString(DisplayName, strFormat); + } + case "email": + { + return PropertyAccess.FormatString(Email, strFormat); + } + case "username": + { + return PropertyAccess.FormatString(Username, strFormat); + } + case "nrposts": + { + return NrPosts.ToString(OutputFormat, formatProvider); + } + case "lastpublishdate": + { + return LastPublishDate.ToString(OutputFormat, formatProvider); + } + case "nrviews": + { + return NrViews.ToString(OutputFormat, formatProvider); + } + case "firstpublishdate": + { + return FirstPublishDate.ToString(OutputFormat, formatProvider); + } + case "altlocale": + { + return PropertyAccess.FormatString(AltLocale, strFormat); + } + case "alttitle": + { + return PropertyAccess.FormatString(AltTitle, strFormat); + } + case "altdescription": + { + return PropertyAccess.FormatString(AltDescription, strFormat); + } + case "localizedtitle": + { + return PropertyAccess.FormatString(LocalizedTitle, strFormat); + } + case "localizeddescription": + { + return PropertyAccess.FormatString(LocalizedDescription, strFormat); + } + case "link": + case "permalink": + { + return PermaLink(DotNetNuke.Entities.Portals.PortalSettings.Current); + } + case "parenturl": + { + return PermaLink(ParentTabID); + } + + default: + { + PropertyNotFound = true; + break; + } + } + + return Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + #region IXmlSerializable Implementation + /// ----------------------------------------------------------------------------- + /// + /// GetSchema returns the XmlSchema for this class + /// + /// GetSchema is implemented as a stub method as it is not required + /// + /// [pdonker] 02/16/2013 Created + /// + /// ----------------------------------------------------------------------------- + public XmlSchema GetSchema() + { + return null; + } + + private string readElement(XmlReader reader, string ElementName) + { + if (!(reader.NodeType == XmlNodeType.Element) || (reader.Name ?? "") != (ElementName ?? "")) + { + reader.ReadToFollowing(ElementName); + } + if (reader.NodeType == XmlNodeType.Element) + { + return reader.ReadElementContentAsString(); + } + else + { + return ""; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// ReadXml fills the object (de-serializes it) from the XmlReader passed + /// + /// + /// The XmlReader that contains the xml for the object + /// + /// [pdonker] 02/16/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void ReadXml(XmlReader reader) + { + // not implemented + } + + internal int ImportedBlogId { get; set; } = -1; + internal List ImportedPosts { get; set; } + internal List ImportedFiles { get; set; } + + public void FromXml(XmlNode xml) + { + if (xml is null) + return; + + int argVariable = ImportedBlogId; + Common.Extensions.ReadValue(ref xml, "BlogId", ref argVariable); + ImportedBlogId = argVariable; + string argVariable1 = Title; + Common.Extensions.ReadValue(ref xml, "Title", ref argVariable1); + Title = argVariable1; + var argVariable2 = TitleLocalizations; + Common.Extensions.ReadValue(ref xml, "TitleLocalizations", ref argVariable2); + TitleLocalizations = argVariable2; + string argVariable3 = Description; + Common.Extensions.ReadValue(ref xml, "Description", ref argVariable3); + Description = argVariable3; + var argVariable4 = DescriptionLocalizations; + Common.Extensions.ReadValue(ref xml, "DescriptionLocalizations", ref argVariable4); + DescriptionLocalizations = argVariable4; + string argVariable5 = Image; + Common.Extensions.ReadValue(ref xml, "Image", ref argVariable5); + Image = argVariable5; + string argVariable6 = Locale; + Common.Extensions.ReadValue(ref xml, "Locale", ref argVariable6); + Locale = argVariable6; + bool argVariable7 = FullLocalization; + Common.Extensions.ReadValue(ref xml, "FullLocalization", ref argVariable7); + FullLocalization = argVariable7; + bool argVariable8 = Published; + Common.Extensions.ReadValue(ref xml, "Published", ref argVariable8); + Published = argVariable8; + bool argVariable9 = IncludeImagesInFeed; + Common.Extensions.ReadValue(ref xml, "IncludeImagesInFeed", ref argVariable9); + IncludeImagesInFeed = argVariable9; + bool argVariable10 = IncludeAuthorInFeed; + Common.Extensions.ReadValue(ref xml, "IncludeAuthorInFeed", ref argVariable10); + IncludeAuthorInFeed = argVariable10; + bool argVariable11 = Syndicated; + Common.Extensions.ReadValue(ref xml, "Syndicated", ref argVariable11); + Syndicated = argVariable11; + string argVariable12 = SyndicationEmail; + Common.Extensions.ReadValue(ref xml, "SyndicationEmail", ref argVariable12); + SyndicationEmail = argVariable12; + string argVariable13 = Copyright; + Common.Extensions.ReadValue(ref xml, "Copyright", ref argVariable13); + Copyright = argVariable13; + bool argVariable14 = MustApproveGhostPosts; + Common.Extensions.ReadValue(ref xml, "MustApproveGhostPosts", ref argVariable14); + MustApproveGhostPosts = argVariable14; + bool argVariable15 = PublishAsOwner; + Common.Extensions.ReadValue(ref xml, "PublishAsOwner", ref argVariable15); + PublishAsOwner = argVariable15; + bool argVariable16 = EnablePingBackSend; + Common.Extensions.ReadValue(ref xml, "EnablePingBackSend", ref argVariable16); + EnablePingBackSend = argVariable16; + bool argVariable17 = EnablePingBackReceive; + Common.Extensions.ReadValue(ref xml, "EnablePingBackReceive", ref argVariable17); + EnablePingBackReceive = argVariable17; + bool argVariable18 = AutoApprovePingBack; + Common.Extensions.ReadValue(ref xml, "AutoApprovePingBack", ref argVariable18); + AutoApprovePingBack = argVariable18; + bool argVariable19 = EnableTrackBackSend; + Common.Extensions.ReadValue(ref xml, "EnableTrackBackSend", ref argVariable19); + EnableTrackBackSend = argVariable19; + bool argVariable20 = EnableTrackBackReceive; + Common.Extensions.ReadValue(ref xml, "EnableTrackBackReceive", ref argVariable20); + EnableTrackBackReceive = argVariable20; + bool argVariable21 = AutoApproveTrackBack; + Common.Extensions.ReadValue(ref xml, "AutoApproveTrackBack", ref argVariable21); + AutoApproveTrackBack = argVariable21; + string argVariable22 = Username; + Common.Extensions.ReadValue(ref xml, "Username", ref argVariable22); + Username = argVariable22; + string argVariable23 = Email; + Common.Extensions.ReadValue(ref xml, "Email", ref argVariable23); + Email = argVariable23; + + ImportedPosts = new List(); + foreach (XmlNode xPost in xml.SelectNodes("Posts/Post")) + { + var post = new Posts.PostInfo(); + post.FromXml(xPost); + ImportedPosts.Add(post); + } + + ImportedFiles = new List(); + foreach (XmlNode xFile in xml.SelectNodes("Files/File")) + ImportedFiles.Add(xFile.InnerText); + + } + + /// ----------------------------------------------------------------------------- + /// + /// WriteXml converts the object to Xml (serializes it) and writes it using the XmlWriter passed + /// + /// + /// The XmlWriter that contains the xml for the object + /// + /// [pdonker] 02/16/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void WriteXml(XmlWriter writer) + { + writer.WriteStartElement("Blog"); + writer.WriteElementString("BlogId", BlogID.ToString()); + writer.WriteElementString("Title", Title); + writer.WriteElementString("TitleLocalizations", TitleLocalizations.ToString()); + writer.WriteElementString("Description", Description); + writer.WriteElementString("DescriptionLocalizations", DescriptionLocalizations.ToString()); + writer.WriteElementString("Image", Image); + writer.WriteElementString("Locale", Locale); + writer.WriteElementString("FullLocalization", FullLocalization.ToString()); + writer.WriteElementString("Published", Published.ToString()); + writer.WriteElementString("IncludeImagesInFeed", IncludeImagesInFeed.ToString()); + writer.WriteElementString("IncludeAuthorInFeed", IncludeAuthorInFeed.ToString()); + writer.WriteElementString("Syndicated", Syndicated.ToString()); + writer.WriteElementString("SyndicationEmail", SyndicationEmail); + writer.WriteElementString("Copyright", Copyright); + writer.WriteElementString("MustApproveGhostPosts", MustApproveGhostPosts.ToString()); + writer.WriteElementString("PublishAsOwner", PublishAsOwner.ToString()); + writer.WriteElementString("EnablePingBackSend", EnablePingBackSend.ToString()); + writer.WriteElementString("EnablePingBackReceive", EnablePingBackReceive.ToString()); + writer.WriteElementString("AutoApprovePingBack", AutoApprovePingBack.ToString()); + writer.WriteElementString("EnableTrackBackSend", EnableTrackBackSend.ToString()); + writer.WriteElementString("EnableTrackBackReceive", EnableTrackBackReceive.ToString()); + writer.WriteElementString("AutoApproveTrackBack", AutoApproveTrackBack.ToString()); + writer.WriteElementString("Username", Username); + writer.WriteElementString("Email", Email); + writer.WriteStartElement("Posts"); + int page = 0; + int totalRecords = 1; + while (page * 10 < totalRecords) + { + foreach (Posts.PostInfo p in Posts.PostsController.GetPostsByBlog(ModuleID, BlogID, "", -1, page, 20, "PUBLISHEDONDATE DESC", ref totalRecords).Values) + p.WriteXml(writer); + page += 1; + } + writer.WriteEndElement(); // Posts + writer.WriteStartElement("Files"); + // pack files + string postDir = GetBlogDirectoryMapPath(BlogID); + if (System.IO.Directory.Exists(postDir)) + { + foreach (string f in System.IO.Directory.GetFiles(postDir)) + { + string fileName = System.IO.Path.GetFileName(f); + writer.WriteElementString("File", fileName); + } + } + writer.WriteEndElement(); // Files + writer.WriteEndElement(); // Blog + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Blogs/BlogInfo_Properties.cs b/Server/Core/Entities/Blogs/BlogInfo_Properties.cs new file mode 100644 index 00000000..6a37869c --- /dev/null +++ b/Server/Core/Entities/Blogs/BlogInfo_Properties.cs @@ -0,0 +1,203 @@ +using System; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; +using DotNetNuke.Modules.Blog.Common; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Entities.Blogs +{ + public partial class BlogInfo + { + + #region Private Members + #endregion + + #region Constructors + public BlogInfo() + { + try + { + Locale = DotNetNuke.Entities.Portals.PortalSettings.Current.DefaultLanguage; + } + catch (Exception ex) + { + } + } + #endregion + + #region Public Properties + [DataMember()] + public int BlogID { get; set; } = -1; + [DataMember()] + public int ModuleID { get; set; } = -1; + [DataMember()] + public string Title { get; set; } = ""; + [DataMember()] + public string Description { get; set; } = ""; + [DataMember()] + public string Image { get; set; } = ""; + [DataMember()] + public string Locale { get; set; } = ""; + [DataMember()] + public bool FullLocalization { get; set; } = false; + [DataMember()] + public bool Published { get; set; } = true; + [DataMember()] + public bool IncludeImagesInFeed { get; set; } = true; + [DataMember()] + public bool IncludeAuthorInFeed { get; set; } = false; + [DataMember()] + public bool Syndicated { get; set; } = true; + [DataMember()] + public string SyndicationEmail { get; set; } = ""; + [DataMember()] + public string Copyright { get; set; } = ""; + [DataMember()] + public bool MustApproveGhostPosts { get; set; } = false; + [DataMember()] + public bool PublishAsOwner { get; set; } = false; + [DataMember()] + public bool EnablePingBackSend { get; set; } = true; + [DataMember()] + public bool EnablePingBackReceive { get; set; } = true; + [DataMember()] + public bool AutoApprovePingBack { get; set; } = false; + [DataMember()] + public bool EnableTrackBackSend { get; set; } = true; + [DataMember()] + public bool EnableTrackBackReceive { get; set; } = false; + [DataMember()] + public bool AutoApproveTrackBack { get; set; } = false; + [DataMember()] + public int OwnerUserId { get; set; } = -1; + [DataMember()] + public int CreatedByUserID { get; set; } = -1; + [DataMember()] + public DateTime CreatedOnDate { get; set; } = DateTime.MinValue; + [DataMember()] + public int LastModifiedByUserID { get; set; } = -1; + [DataMember()] + public DateTime LastModifiedOnDate { get; set; } = DateTime.MinValue; + [DataMember()] + public string DisplayName { get; set; } = ""; + [DataMember()] + public string Email { get; set; } = ""; + [DataMember()] + public string Username { get; set; } = ""; + [DataMember()] + public int NrPosts { get; set; } = -1; + [DataMember()] + public DateTime LastPublishDate { get; set; } = DateTime.MinValue; + [DataMember()] + public int NrViews { get; set; } = -1; + [DataMember()] + public DateTime FirstPublishDate { get; set; } = DateTime.MinValue; + #endregion + + #region ML Properties + [DataMember()] + public string AltLocale { get; set; } = ""; + [DataMember()] + public string AltTitle { get; set; } = ""; + [DataMember()] + public string AltDescription { get; set; } = ""; + + public string LocalizedTitle + { + get + { + return Conversions.ToString(Interaction.IIf(string.IsNullOrEmpty(AltTitle), Title, AltTitle)); + } + } + + public string LocalizedDescription + { + get + { + return Conversions.ToString(Interaction.IIf(string.IsNullOrEmpty(AltDescription), Description, AltDescription)); + } + } + + /// + /// ML text type to handle the title of the blog + /// + /// + /// + /// + public LocalizedText TitleLocalizations + { + get + { + if (_titleLocalizations is null) + { + if (BlogID == -1) + { + _titleLocalizations = new LocalizedText(); + } + else + { + _titleLocalizations = new LocalizedText(Data.DataProvider.Instance().GetBlogLocalizations(BlogID), "Title"); + } + } + return _titleLocalizations; + } + set + { + _titleLocalizations = value; + } + } + private LocalizedText _titleLocalizations; + + /// + /// ML text type to handle the description of the blog + /// + /// + /// + /// + public LocalizedText DescriptionLocalizations + { + get + { + if (_descriptionLocalizations is null) + { + if (BlogID == -1) + { + _descriptionLocalizations = new LocalizedText(); + } + else + { + _descriptionLocalizations = new LocalizedText(Data.DataProvider.Instance().GetBlogLocalizations(BlogID), "Description"); + } + } + return _descriptionLocalizations; + } + set + { + _descriptionLocalizations = value; + } + } + private LocalizedText _descriptionLocalizations; + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Blogs/BlogsController.cs b/Server/Core/Entities/Blogs/BlogsController.cs new file mode 100644 index 00000000..c5922648 --- /dev/null +++ b/Server/Core/Entities/Blogs/BlogsController.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; +using DotNetNuke.Common.Utilities; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Modules.Blog.Data; + +namespace DotNetNuke.Modules.Blog.Entities.Blogs +{ + + public partial class BlogsController + { + + public static BlogInfo GetBlog(int blogID, int userId, string locale) + { + + return CBO.FillObject(DataProvider.Instance().GetBlog(blogID, userId, locale)); + + } + + public static Dictionary GetBlogsByModule(int moduleID, string locale) + { + + return GetBlogsByModule(moduleID, -1, locale); + + } + + public static Dictionary GetBlogsByModule(int moduleID, int userId, string locale) + { + + var res = CBO.FillDictionary("BlogID", DataProvider.Instance().GetBlogsByModule(moduleID, userId, locale)); + if (userId > -1) + { + foreach (BlogInfo b in res.Values) + { + if (b.OwnerUserId == userId) + { + b.CanAdd = true; + b.CanEdit = true; + b.CanApprove = true; + b.IsOwner = true; + } + } + } + return res; + + } + + public static Dictionary GetBlogsByPortal(int portalId, int userId, string locale) + { + + var res = CBO.FillDictionary("BlogID", DataProvider.Instance().GetBlogsByPortal(portalId, userId, locale)); + if (userId > -1) + { + foreach (BlogInfo b in res.Values) + { + if (b.OwnerUserId == userId) + { + b.CanAdd = true; + b.CanEdit = true; + b.CanApprove = true; + b.IsOwner = true; + } + } + } + return res; + + } + + public static List GetBlogCalendar(int moduleId, int blogId, string locale) + { + return CBO.FillCollection(DataProvider.Instance().GetBlogCalendar(moduleId, blogId, locale)); + } + + } + +} \ No newline at end of file diff --git a/Server/Core/Entities/Blogs/BlogsController_CRUD.cs b/Server/Core/Entities/Blogs/BlogsController_CRUD.cs new file mode 100644 index 00000000..c9d29adb --- /dev/null +++ b/Server/Core/Entities/Blogs/BlogsController_CRUD.cs @@ -0,0 +1,64 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + + +using DotNetNuke.Modules.Blog.Data; + +namespace DotNetNuke.Modules.Blog.Entities.Blogs +{ + + public partial class BlogsController + { + + public static int AddBlog(ref BlogInfo objBlog, int createdByUser) + { + + objBlog.BlogID = DataProvider.Instance().AddBlog(objBlog.AutoApprovePingBack, objBlog.ModuleID, objBlog.AutoApproveTrackBack, objBlog.Copyright, objBlog.Description, objBlog.EnablePingBackReceive, objBlog.EnablePingBackSend, objBlog.EnableTrackBackReceive, objBlog.EnableTrackBackSend, objBlog.FullLocalization, objBlog.Image, objBlog.IncludeAuthorInFeed, objBlog.IncludeImagesInFeed, objBlog.Locale, objBlog.MustApproveGhostPosts, objBlog.OwnerUserId, objBlog.PublishAsOwner, objBlog.Published, objBlog.Syndicated, objBlog.SyndicationEmail, objBlog.Title, createdByUser); + + // localization + foreach (string l in objBlog.TitleLocalizations.Locales) + DataProvider.Instance().SetBlogLocalization(objBlog.BlogID, l, objBlog.TitleLocalizations[l], objBlog.DescriptionLocalizations[l]); + + return objBlog.BlogID; + + } + + public static void UpdateBlog(BlogInfo objBlog, int updatedByUser) + { + + DataProvider.Instance().UpdateBlog(objBlog.AutoApprovePingBack, objBlog.ModuleID, objBlog.AutoApproveTrackBack, objBlog.BlogID, objBlog.Copyright, objBlog.Description, objBlog.EnablePingBackReceive, objBlog.EnablePingBackSend, objBlog.EnableTrackBackReceive, objBlog.EnableTrackBackSend, objBlog.FullLocalization, objBlog.Image, objBlog.IncludeAuthorInFeed, objBlog.IncludeImagesInFeed, objBlog.Locale, objBlog.MustApproveGhostPosts, objBlog.OwnerUserId, objBlog.PublishAsOwner, objBlog.Published, objBlog.Syndicated, objBlog.SyndicationEmail, objBlog.Title, updatedByUser); + + // localization + foreach (string l in objBlog.TitleLocalizations.Locales) + DataProvider.Instance().SetBlogLocalization(objBlog.BlogID, l, objBlog.TitleLocalizations[l], objBlog.DescriptionLocalizations[l]); + + } + + public static void DeleteBlog(int blogID) + { + + DataProvider.Instance().DeleteBlog(blogID); + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Blogs/BlogsController_FK.cs b/Server/Core/Entities/Blogs/BlogsController_FK.cs new file mode 100644 index 00000000..5d56c760 --- /dev/null +++ b/Server/Core/Entities/Blogs/BlogsController_FK.cs @@ -0,0 +1,33 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + + + +namespace DotNetNuke.Modules.Blog.Entities.Blogs +{ + + public partial class BlogsController + { + + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Blogs/BlogsController_Service.cs b/Server/Core/Entities/Blogs/BlogsController_Service.cs new file mode 100644 index 00000000..d160408b --- /dev/null +++ b/Server/Core/Entities/Blogs/BlogsController_Service.cs @@ -0,0 +1,221 @@ +using System; +using System.IO.Compression; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Net; +using System.Net.Http; +using System.Text.RegularExpressions; +using System.Web; +using System.Web.Http; +using System.Xml; +using DotNetNuke.Modules.Blog.BlogML.Xml; +using DotNetNuke.Modules.Blog.Common; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Entities.Comments; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Modules.Blog.Entities.Terms; +using DotNetNuke.Modules.Blog.Services; +using DotNetNuke.Web.Api; + +namespace DotNetNuke.Modules.Blog.Entities.Blogs +{ + public partial class BlogsController : DnnApiController + { + + public class BlogDTO + { + public int BlogId { get; set; } + } + + #region Private Members + private BlogInfo Blog { get; set; } = null; + private ModuleSettings Settings { get; set; } = null; + #endregion + + #region Service Methods + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.Owner | SecurityAccessLevel.Admin)] + [ValidateAntiForgeryToken()] + [ActionName("Export")] + public HttpResponseMessage ExportBlog(BlogDTO postData) + { + SetContext(postData); + + var saveDir = new System.IO.DirectoryInfo(GetBlogDirectoryMapPath(Blog.BlogID)); + if (!saveDir.Exists) + saveDir.Create(); + RemoveOldTimeStampedFiles(saveDir); + + var newBlogML = new BlogMLBlog(); + newBlogML.Title = Blog.Title; + newBlogML.SubTitle = Blog.Description; + newBlogML.Authors.Add(new BlogMLAuthor() { Title = Blog.DisplayName }); + newBlogML.DateCreated = Blog.CreatedOnDate; + AddCategories(ref newBlogML); + AddPosts(ref newBlogML); + string blogMLFile = DateTime.Now.ToString("yyyy-MM-dd") + "-" + Guid.NewGuid().ToString("D"); + + using (var objZipOutputStream = new ZipArchive(System.IO.File.Create(GetBlogDirectoryMapPath(Blog.BlogID) + blogMLFile + ".zip"), ZipArchiveMode.Create)) + { + var objZipEntry = objZipOutputStream.CreateEntry(blogMLFile + ".xml"); + using (var stream = XmlWriter.Create(objZipEntry.Open())) + { + BlogMLSerializer.Serialize(stream, newBlogML); + stream.Flush(); + } + } + + return Request.CreateResponse(HttpStatusCode.OK, new { Result = GetBlogDirectoryPath(Blog.BlogID) + blogMLFile + ".zip" }); + } + #endregion + + #region Private Methods + private void SetContext(BlogDTO data) + { + Blog = GetBlog(data.BlogId, UserInfo.UserID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + Settings = ModuleSettings.GetModuleSettings(ActiveModule.ModuleID); + } + + private void AddCategories(ref BlogMLBlog TargetBlogML) + { + if (Settings.VocabularyId > -1) + { + foreach (TermInfo c in TermsController.GetTermsByVocabulary(ActiveModule.ModuleID, Settings.VocabularyId, System.Threading.Thread.CurrentThread.CurrentCulture.Name).Values) + { + var categoryML = new BlogMLCategory(); + categoryML.Approved = true; + categoryML.DateCreated = c.CreatedOnDate; + categoryML.Description = ""; + categoryML.Title = c.Name; + categoryML.ID = c.TermId.ToString(); + categoryML.ParentRef = c.ParentTermId.ToStringOrZero(); + TargetBlogML.Categories.Add(categoryML); + } + } + } + + private void AddPosts(ref BlogMLBlog TargetBlogML) + { + int totalRecs = 0; + int handledRecs = 0; + int page = 0; + do + { + foreach (PostInfo post in PostsController.GetPostsByBlog(ActiveModule.ModuleID, Blog.BlogID, System.Threading.Thread.CurrentThread.CurrentCulture.Name, -1, page, 10, "PUBLISHEDONDATE", ref totalRecs).Values) + { + handledRecs += 1; + TargetBlogML.Posts.Add(ConvertPost(post)); + } + page += 1; + } + while (totalRecs > handledRecs); + } + + private BlogMLPost ConvertPost(PostInfo post) + { + + var newPostML = new BlogMLPost(); + newPostML.Approved = post.Published; + newPostML.Title = post.Title; + newPostML.Content = BlogMLContent.Create(HttpUtility.HtmlDecode(post.Content), BlogML.ContentTypes.Html); + foreach (TermInfo t in post.PostCategories) + newPostML.Categories.Add(new BlogMLCategoryReference() { Ref = t.TermId.ToString() }); + newPostML.Authors.Add(post.DisplayName); + newPostML.PostType = BlogML.BlogPostTypes.Normal; + newPostML.DateCreated = post.PublishedOnDate; + if (!string.IsNullOrEmpty(post.Summary)) + { + if (Settings.SummaryModel == SummaryType.PlainTextIndependent) + { + newPostML.Excerpt = BlogMLContent.Create(post.Summary, BlogML.ContentTypes.Text); + } + else + { + newPostML.Excerpt = BlogMLContent.Create(HttpUtility.HtmlDecode(post.Summary), BlogML.ContentTypes.Html); + } + newPostML.HasExcerpt = true; + } + else + { + newPostML.HasExcerpt = false; + } + newPostML.ID = post.ContentItemId.ToString(); + newPostML.PostUrl = post.PermaLink(); + newPostML.Image = post.Image; + newPostML.AllowComments = post.AllowComments; + newPostML.DisplayCopyright = post.DisplayCopyright; + newPostML.Copyright = post.Copyright; + newPostML.Locale = post.Locale; + + // pack files + string postDir = GetPostDirectoryMapPath(post.BlogID, post.ContentItemId); + if (System.IO.Directory.Exists(postDir)) + { + foreach (string f in System.IO.Directory.GetFiles(postDir)) + { + string fileName = System.IO.Path.GetFileName(f); + string regexPattern = @""([^\s]*)\/" + fileName + """; + var options = RegexOptions.Singleline | RegexOptions.IgnoreCase; + if (newPostML.HasExcerpt) + { + newPostML.Excerpt.Text = Regex.Replace(newPostML.Excerpt.Text, regexPattern, """ + fileName + """, options); + } + newPostML.Content.Text = Regex.Replace(newPostML.Content.Text, regexPattern, """ + fileName + """, options); + var att = new BlogMLAttachment() { Embedded = true, Path = fileName }; + using (var fs = new System.IO.FileStream(f, System.IO.FileMode.Open)) + { + var fileData = new byte[(int)(fs.Length - 1L) + 1]; + if (fs.Length > 0L) + { + fs.Read(fileData, 0, (int)fs.Length); + att.Data = fileData; + att.Embedded = true; + } + else + { + // Empty File + } + } + newPostML.Attachments.Add(att); + } + } + + foreach (CommentInfo comment in CommentsController.GetCommentsByContentItem(post.ContentItemId, false, UserInfo.UserID)) + { + var newComment = new BlogMLComment(); + newComment.Approved = comment.Approved; + newComment.Content = new BlogMLContent(); + newComment.Content.Text = comment.Comment; + newComment.DateCreated = comment.CreatedOnDate; + newComment.Title = ""; + newComment.UserEMail = comment.Email; + newComment.UserName = comment.Username; + newComment.UserUrl = comment.Website; + newPostML.Comments.Add(newComment); + } + + return newPostML; + + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Comments/CommentInfo.cs b/Server/Core/Entities/Comments/CommentInfo.cs new file mode 100644 index 00000000..bfeb47d9 --- /dev/null +++ b/Server/Core/Entities/Comments/CommentInfo.cs @@ -0,0 +1,30 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +namespace DotNetNuke.Modules.Blog.Entities.Comments +{ + + public partial class CommentInfo + { + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Comments/CommentInfo_Interfaces.cs b/Server/Core/Entities/Comments/CommentInfo_Interfaces.cs new file mode 100644 index 00000000..fe9846b1 --- /dev/null +++ b/Server/Core/Entities/Comments/CommentInfo_Interfaces.cs @@ -0,0 +1,457 @@ +using System; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Modules.Blog.Common; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Entities.Comments +{ + + [Serializable()] + [XmlRoot("Comment")] + [DataContract()] + public partial class CommentInfo : IHydratable, IPropertyAccess, IXmlSerializable + { + + #region IHydratable Implementation + /// ----------------------------------------------------------------------------- + /// + /// Fill hydrates the object from a Datareader + /// + /// The Fill method is used by the CBO method to hydrtae the object + /// rather than using the more expensive Refection methods. + /// + /// [pdonker] 02/24/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void Fill(IDataReader dr) + { + CommentID = Convert.ToInt32(Null.SetNull(dr["CommentID"], CommentID)); + ContentItemId = Convert.ToInt32(Null.SetNull(dr["ContentItemId"], ContentItemId)); + ParentId = Convert.ToInt32(Null.SetNull(dr["ParentId"], ParentId)); + Comment = Convert.ToString(Null.SetNull(dr["Comment"], Comment)); + Approved = Convert.ToBoolean(Null.SetNull(dr["Approved"], Approved)); + Author = Convert.ToString(Null.SetNull(dr["Author"], Author)); + Website = Convert.ToString(Null.SetNull(dr["Website"], Website)); + Email = Convert.ToString(Null.SetNull(dr["Email"], Email)); + CreatedByUserID = Convert.ToInt32(Null.SetNull(dr["CreatedByUserID"], CreatedByUserID)); + CreatedOnDate = Conversions.ToDate(Null.SetNull(dr["CreatedOnDate"], CreatedOnDate)); + LastModifiedByUserID = Convert.ToInt32(Null.SetNull(dr["LastModifiedByUserID"], LastModifiedByUserID)); + LastModifiedOnDate = Conversions.ToDate(Null.SetNull(dr["LastModifiedOnDate"], LastModifiedOnDate)); + Username = Convert.ToString(Null.SetNull(dr["Username"], Username)); + DisplayName = Convert.ToString(Null.SetNull(dr["DisplayName"], DisplayName)); + Likes = Convert.ToInt32(Null.SetNull(dr["Likes"], Likes)); + Dislikes = Convert.ToInt32(Null.SetNull(dr["Dislikes"], Dislikes)); + Reports = Convert.ToInt32(Null.SetNull(dr["Reports"], Reports)); + Liked = Convert.ToInt32(Null.SetNull(dr["Liked"], Likes)); + Disliked = Convert.ToInt32(Null.SetNull(dr["Disliked"], Dislikes)); + Reported = Convert.ToInt32(Null.SetNull(dr["Reported"], Reports)); + } + /// ----------------------------------------------------------------------------- + /// + /// Gets and sets the Key ID + /// + /// The KeyID property is part of the IHydratble interface. It is used + /// as the key property when creating a Dictionary + /// + /// [pdonker] 02/24/2013 Created + /// + /// ----------------------------------------------------------------------------- + public int KeyID + { + get + { + return CommentID; + } + set + { + CommentID = value; + } + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "commentid": + { + return CommentID.ToString(OutputFormat, formatProvider); + } + case "contentitemid": + { + return ContentItemId.ToString(OutputFormat, formatProvider); + } + case "parentid": + { + return ParentId.ToString(OutputFormat, formatProvider); + } + case "comment": + { + return Comment.OutputHtml(strFormat); + } + case "approved": + { + return Approved.ToString(); + } + case "approvedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(Approved, formatProvider); + } + case "author": + { + return PropertyAccess.FormatString(Author, strFormat); + } + case "website": + { + return PropertyAccess.FormatString(Website, strFormat); + } + case "email": + { + return PropertyAccess.FormatString(Email, strFormat); + } + case "createdbyuserid": + { + return CreatedByUserID.ToString(OutputFormat, formatProvider); + } + case "createdondate": + { + return CreatedOnDate.ToString(OutputFormat, formatProvider); + } + case "createdondateutc": + { + return CreatedOnDate.ToUniversalTime().ToString(OutputFormat, formatProvider); + } + case "lastmodifiedbyuserid": + { + return LastModifiedByUserID.ToString(OutputFormat, formatProvider); + } + case "lastmodifiedondate": + { + return LastModifiedOnDate.ToString(OutputFormat, formatProvider); + } + case "lastmodifiedondateutc": + { + return LastModifiedOnDate.ToUniversalTime().ToString(OutputFormat, formatProvider); + } + case "username": + { + return PropertyAccess.FormatString(Username, strFormat); + } + case "displayname": + { + return PropertyAccess.FormatString(DisplayName, strFormat); + } + case "likes": + { + return Likes.ToString(OutputFormat, formatProvider); + } + case "dislikes": + { + return Dislikes.ToString(OutputFormat, formatProvider); + } + case "reports": + { + return Reports.ToString(OutputFormat, formatProvider); + } + case "liked": + { + return Liked.ToBool().ToString(); + } + case "likedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(Liked.ToBool(), formatProvider); + } + case "disliked": + { + return Disliked.ToBool().ToString(); + } + case "dislikedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(Disliked.ToBool(), formatProvider); + } + case "reported": + { + return Reported.ToBool().ToString(); + } + case "reportedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(Reported.ToBool(), formatProvider); + } + case "karmaed": + { + return (Reported + Liked + Disliked).ToBool().ToString(); + } + case "karmaedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo((Reported + Liked + Disliked).ToBool(), formatProvider); + } + case "posturl": + { + string _Link = DotNetNuke.Common.Globals.ApplicationURL(DotNetNuke.Entities.Portals.PortalSettings.Current.ActiveTab.TabID) + "&Post=" + ContentItemId.ToString(); + return DotNetNuke.Common.Globals.FriendlyUrl(DotNetNuke.Entities.Portals.PortalSettings.Current.ActiveTab, _Link); + } + + default: + { + PropertyNotFound = true; + break; + } + } + + return Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + #region IXmlSerializable Implementation + /// ----------------------------------------------------------------------------- + /// + /// GetSchema returns the XmlSchema for this class + /// + /// GetSchema is implemented as a stub method as it is not required + /// + /// [pdonker] 02/24/2013 Created + /// + /// ----------------------------------------------------------------------------- + public XmlSchema GetSchema() + { + return null; + } + + private string readElement(XmlReader reader, string ElementName) + { + if (!(reader.NodeType == XmlNodeType.Element) || (reader.Name ?? "") != (ElementName ?? "")) + { + reader.ReadToFollowing(ElementName); + } + if (reader.NodeType == XmlNodeType.Element) + { + return reader.ReadElementContentAsString(); + } + else + { + return ""; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// ReadXml fills the object (de-serializes it) from the XmlReader passed + /// + /// + /// The XmlReader that contains the xml for the object + /// + /// [pdonker] 02/24/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void ReadXml(XmlReader reader) + { + try + { + + bool localTryParse() { int argresult = CommentID; var ret = int.TryParse(readElement(reader, "CommentID"), out argresult); CommentID = argresult; return ret; } + + if (!localTryParse()) + { + CommentID = Null.NullInteger; + } + bool localTryParse1() { int argresult1 = ContentItemId; var ret = int.TryParse(readElement(reader, "ContentItemId"), out argresult1); ContentItemId = argresult1; return ret; } + + if (!localTryParse1()) + { + ContentItemId = Null.NullInteger; + } + bool localTryParse2() { int argresult2 = ParentId; var ret = int.TryParse(readElement(reader, "ParentId"), out argresult2); ParentId = argresult2; return ret; } + + if (!localTryParse2()) + { + ParentId = Null.NullInteger; + } + Comment = readElement(reader, "Comment"); + bool argresult = Approved; + bool.TryParse(readElement(reader, "Approved"), out argresult); + Approved = argresult; + Author = readElement(reader, "Author"); + Website = readElement(reader, "Website"); + Email = readElement(reader, "Email"); + bool localTryParse3() { int argresult3 = CreatedByUserID; var ret = int.TryParse(readElement(reader, "CreatedByUserID"), out argresult3); CreatedByUserID = argresult3; return ret; } + + if (!localTryParse3()) + { + CreatedByUserID = Null.NullInteger; + } + var argresult1 = CreatedOnDate; + DateTime.TryParse(readElement(reader, "CreatedOnDate"), out argresult1); + CreatedOnDate = argresult1; + bool localTryParse4() { int argresult4 = LastModifiedByUserID; var ret = int.TryParse(readElement(reader, "LastModifiedByUserID"), out argresult4); LastModifiedByUserID = argresult4; return ret; } + + if (!localTryParse4()) + { + LastModifiedByUserID = Null.NullInteger; + } + var argresult2 = LastModifiedOnDate; + DateTime.TryParse(readElement(reader, "LastModifiedOnDate"), out argresult2); + LastModifiedOnDate = argresult2; + Username = readElement(reader, "Username"); + DisplayName = readElement(reader, "DisplayName"); + bool localTryParse5() { int argresult5 = Likes; var ret = int.TryParse(readElement(reader, "Likes"), out argresult5); Likes = argresult5; return ret; } + + if (!localTryParse5()) + { + Likes = Null.NullInteger; + } + bool localTryParse6() { int argresult6 = Dislikes; var ret = int.TryParse(readElement(reader, "Dislikes"), out argresult6); Dislikes = argresult6; return ret; } + + if (!localTryParse6()) + { + Dislikes = Null.NullInteger; + } + bool localTryParse7() { int argresult7 = Reports; var ret = int.TryParse(readElement(reader, "Reports"), out argresult7); Reports = argresult7; return ret; } + + if (!localTryParse7()) + { + Reports = Null.NullInteger; + } + } + catch (Exception ex) + { + // log exception as DNN import routine does not do that + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + // re-raise exception to make sure import routine displays a visible error to the user + throw new Exception("An error occured during import of an Comment", ex); + } + + } + + /// ----------------------------------------------------------------------------- + /// + /// WriteXml converts the object to Xml (serializes it) and writes it using the XmlWriter passed + /// + /// + /// The XmlWriter that contains the xml for the object + /// + /// [pdonker] 02/24/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void WriteXml(XmlWriter writer) + { + writer.WriteStartElement("Comment"); + writer.WriteElementString("CommentID", CommentID.ToString()); + writer.WriteElementString("ContentItemId", ContentItemId.ToString()); + writer.WriteElementString("ParentId", ParentId.ToString()); + writer.WriteElementString("Comment", Comment); + writer.WriteElementString("Approved", Approved.ToString()); + writer.WriteElementString("Author", Author); + writer.WriteElementString("Website", Website); + writer.WriteElementString("Email", Email); + writer.WriteElementString("CreatedByUserID", CreatedByUserID.ToString()); + writer.WriteElementString("CreatedOnDate", CreatedOnDate.ToString()); + writer.WriteElementString("LastModifiedByUserID", LastModifiedByUserID.ToString()); + writer.WriteElementString("LastModifiedOnDate", LastModifiedOnDate.ToString()); + writer.WriteElementString("Username", Username); + writer.WriteElementString("DisplayName", DisplayName); + writer.WriteElementString("Likes", Likes.ToString()); + writer.WriteElementString("Dislikes", Dislikes.ToString()); + writer.WriteElementString("Reports", Reports.ToString()); + writer.WriteEndElement(); + } + #endregion + + #region ToXml Methods + public string ToXml() + { + return ToXml("Comment"); + } + + public string ToXml(string elementName) + { + var xml = new StringBuilder(); + xml.Append("<"); + xml.Append(elementName); + AddAttribute(ref xml, "CommentID", CommentID.ToString()); + AddAttribute(ref xml, "ContentItemId", ContentItemId.ToString()); + AddAttribute(ref xml, "ParentId", ParentId.ToString()); + AddAttribute(ref xml, "Comment", Comment); + AddAttribute(ref xml, "Approved", Approved.ToString()); + AddAttribute(ref xml, "Author", Author); + AddAttribute(ref xml, "Website", Website); + AddAttribute(ref xml, "Email", Email); + AddAttribute(ref xml, "CreatedByUserID", CreatedByUserID.ToString()); + AddAttribute(ref xml, "CreatedOnDate", CreatedOnDate.ToUniversalTime().ToString("u")); + AddAttribute(ref xml, "LastModifiedByUserID", LastModifiedByUserID.ToString()); + AddAttribute(ref xml, "LastModifiedOnDate", LastModifiedOnDate.ToUniversalTime().ToString("u")); + AddAttribute(ref xml, "Username", Username); + AddAttribute(ref xml, "DisplayName", DisplayName); + AddAttribute(ref xml, "Likes", Likes.ToString()); + AddAttribute(ref xml, "Dislikes", Dislikes.ToString()); + AddAttribute(ref xml, "Reports", Reports.ToString()); + xml.Append(" />"); + return xml.ToString(); + } + + private void AddAttribute(ref StringBuilder xml, string attributeName, string attributeValue) + { + xml.Append(" " + attributeName); + xml.Append("=\"" + attributeValue + "\""); + } + #endregion + + #region JSON Serialization + public void WriteJSON(ref Stream s) + { + var ser = new DataContractJsonSerializer(typeof(CommentInfo)); + ser.WriteObject(s, this); + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Comments/CommentInfo_Properties.cs b/Server/Core/Entities/Comments/CommentInfo_Properties.cs new file mode 100644 index 00000000..7187b7bf --- /dev/null +++ b/Server/Core/Entities/Comments/CommentInfo_Properties.cs @@ -0,0 +1,82 @@ +using System; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; + +namespace DotNetNuke.Modules.Blog.Entities.Comments +{ + public partial class CommentInfo + { + + #region Private Members + #endregion + + #region Constructors + public CommentInfo() + { + } + #endregion + + #region Public Properties + [DataMember()] + public int CommentID { get; set; } = -1; + [DataMember()] + public int ContentItemId { get; set; } = -1; + [DataMember()] + public int ParentId { get; set; } = -1; + [DataMember()] + public string Comment { get; set; } = ""; + [DataMember()] + public bool Approved { get; set; } = false; + [DataMember()] + public string Author { get; set; } = ""; + [DataMember()] + public string Website { get; set; } = ""; + [DataMember()] + public string Email { get; set; } = ""; + [DataMember()] + public int CreatedByUserID { get; set; } = -1; + [DataMember()] + public DateTime CreatedOnDate { get; set; } = DateTime.MinValue; + [DataMember()] + public int LastModifiedByUserID { get; set; } = -1; + [DataMember()] + public DateTime LastModifiedOnDate { get; set; } = DateTime.MinValue; + [DataMember()] + public string Username { get; set; } = ""; + [DataMember()] + public string DisplayName { get; set; } = ""; + [DataMember()] + public int Likes { get; set; } = 0; + [DataMember()] + public int Dislikes { get; set; } = 0; + [DataMember()] + public int Reports { get; set; } = 0; + [DataMember()] + public int Liked { get; set; } = 0; + [DataMember()] + public int Disliked { get; set; } = 0; + [DataMember()] + public int Reported { get; set; } = 0; + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Comments/CommentsController.cs b/Server/Core/Entities/Comments/CommentsController.cs new file mode 100644 index 00000000..f5484c0d --- /dev/null +++ b/Server/Core/Entities/Comments/CommentsController.cs @@ -0,0 +1,142 @@ +using System.Collections.Generic; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Entities.Portals; +using static DotNetNuke.Modules.Blog.Common.Globals; + +using DotNetNuke.Modules.Blog.Data; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Modules.Blog.Integration; +using static DotNetNuke.Services.Localization.Localization; + +namespace DotNetNuke.Modules.Blog.Entities.Comments +{ + + public partial class CommentsController + { + + public static CommentInfo GetComment(int commentID, int userId) + { + + return CBO.FillObject(DataProvider.Instance().GetComment(commentID, userId)); + + } + + public static Dictionary GetCommentsByModule(int moduleId, int userID, int pageIndex, int pageSize, string orderBy, ref int totalRecords) + { + + if (pageIndex < 0) + { + pageIndex = 0; + pageSize = int.MaxValue; + } + + var res = new Dictionary(); + using (var ir = DataProvider.Instance().GetCommentsByModuleId(moduleId, userID, pageIndex, pageSize, orderBy)) + { + res = CBO.FillDictionary("CommentId", ir, false); + ir.NextResult(); + var argdr = ir; + totalRecords = DotNetNuke.Common.Globals.GetTotalRecords(ref argdr); + } + return res; + + } + + public static int AddComment(BlogInfo blog, PostInfo Post, ref CommentInfo comment) + { + + AddComment(ref comment, PortalSettings.Current.UserId); + if (comment.Approved) + { + JournalController.AddOrUpdateCommentInJournal(blog, Post, comment, PortalSettings.Current.PortalId, PortalSettings.Current.ActiveTab.TabID, PortalSettings.Current.UserId, Post.PermaLink(PortalSettings.Current)); + } + else + { + string title = GetString("CommentPendingNotify.Subject", SharedResourceFileName); + string summary = string.Format(GetString("CommentPendingNotify.Body", SharedResourceFileName), Post.PermaLink(PortalSettings.Current), comment.CommentID, Post.Title, comment.Comment); + NotificationController.CommentPendingApproval(comment, blog, Post, PortalSettings.Current.PortalId, summary, title); + } + return comment.CommentID; + + } + + public static void UpdateComment(BlogInfo blog, PostInfo Post, CommentInfo comment) + { + + UpdateComment(comment, PortalSettings.Current.UserId); + NotificationController.RemoveCommentPendingNotification(blog.ModuleID, blog.BlogID, comment.ContentItemId, comment.CommentID); + if (comment.Approved) + { + JournalController.AddOrUpdateCommentInJournal(blog, Post, comment, PortalSettings.Current.PortalId, PortalSettings.Current.ActiveTab.TabID, PortalSettings.Current.UserId, Post.PermaLink(PortalSettings.Current)); + } + else + { + string title = GetString("CommentPendingNotify.Subject", SharedResourceFileName); + string summary = string.Format(GetString("CommentPendingNotify.Body", SharedResourceFileName), Post.PermaLink(PortalSettings.Current), comment.CommentID, Post.Title, comment.Comment); + NotificationController.CommentPendingApproval(comment, blog, Post, PortalSettings.Current.PortalId, summary, title); + } + + } + + public static void ApproveComment(int moduleId, int blogId, CommentInfo comment) + { + + DataProvider.Instance().ApproveComment(comment.CommentID); + NotificationController.RemoveCommentPendingNotification(moduleId, blogId, comment.ContentItemId, comment.CommentID); + + } + + public static void DeleteComment(int moduleId, int blogId, CommentInfo comment) + { + + DataProvider.Instance().DeleteComment(comment.CommentID); + NotificationController.RemoveCommentPendingNotification(moduleId, blogId, comment.ContentItemId, comment.CommentID); + + } + + public static int CommentKarma(ModuleInfo callingModule, CommentInfo comment, DotNetNuke.Entities.Users.UserInfo user, int karma) + { + + if (user.UserID < 0) + return -1; + int ret = DataProvider.Instance().AddCommentKarma(comment.CommentID, user.UserID, karma); + if (ret > -1) + { + if (karma == 2) // reporting comment as inappropriate + { + string title = string.Format(GetString("CommentReportedNotify", SharedResourceFileName), user.DisplayName); + var post = PostsController.GetPost(comment.ContentItemId, callingModule.ModuleID, ""); + string summary = string.Format(GetString("CommentReportedNotify.Body", SharedResourceFileName), user.DisplayName, comment.DisplayName, comment.Comment, post.PermaLink(PortalSettings.Current), post.Title); + NotificationController.ReportComment(comment, post.Blog, post, callingModule.PortalID, summary, title); + } + return ret; + } + return 0; + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Comments/CommentsController_CRUD.cs b/Server/Core/Entities/Comments/CommentsController_CRUD.cs new file mode 100644 index 00000000..00d22d8a --- /dev/null +++ b/Server/Core/Entities/Comments/CommentsController_CRUD.cs @@ -0,0 +1,55 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + + +using DotNetNuke.Modules.Blog.Data; + +namespace DotNetNuke.Modules.Blog.Entities.Comments +{ + + public partial class CommentsController + { + + public static int AddComment(ref CommentInfo objComment, int createdByUser) + { + + objComment.CommentID = DataProvider.Instance().AddComment(objComment.Approved, objComment.Author, objComment.Comment, objComment.ContentItemId, objComment.Email, objComment.ParentId, objComment.Website, createdByUser); + return objComment.CommentID; + + } + + public static void UpdateComment(CommentInfo objComment, int updatedByUser) + { + + DataProvider.Instance().UpdateComment(objComment.Approved, objComment.Author, objComment.Comment, objComment.CommentID, objComment.ContentItemId, objComment.Email, objComment.ParentId, objComment.Website, updatedByUser); + + } + + public static void DeleteComment(int commentID) + { + + DataProvider.Instance().DeleteComment(commentID); + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Comments/CommentsController_FK.cs b/Server/Core/Entities/Comments/CommentsController_FK.cs new file mode 100644 index 00000000..308a287c --- /dev/null +++ b/Server/Core/Entities/Comments/CommentsController_FK.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + + +using DotNetNuke.Modules.Blog.Data; + +namespace DotNetNuke.Modules.Blog.Entities.Comments +{ + + public partial class CommentsController + { + + public static List GetCommentsByContentItem(int contentItemId, bool IncludeNonApproved, int userId) + { + + return DotNetNuke.Common.Utilities.CBO.FillCollection(DataProvider.Instance().GetCommentsByContentItem(contentItemId, IncludeNonApproved, userId)); + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Comments/CommentsController_Service.cs b/Server/Core/Entities/Comments/CommentsController_Service.cs new file mode 100644 index 00000000..6c26436a --- /dev/null +++ b/Server/Core/Entities/Comments/CommentsController_Service.cs @@ -0,0 +1,505 @@ +using System; +using System.Collections.Generic; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; +using System.Web.Http; +using System.Xml; +using DotNetNuke.Modules.Blog.Common; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Modules.Blog.Security; +using DotNetNuke.Modules.Blog.Services; +using DotNetNuke.Modules.Blog.Templating; +using DotNetNuke.Web.Api; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Entities.Comments +{ + public partial class CommentsController : DnnApiController + { + + public class CommentDTO + { + public int BlogId { get; set; } + public int CommentId { get; set; } + public int Karma { get; set; } + } + + public class FullCommentDTO + { + public int BlogId { get; set; } + public int PostId { get; set; } + public int ParentId { get; set; } + public string Comment { get; set; } + public string Author { get; set; } + public string Website { get; set; } + public string Email { get; set; } + } + + #region Private Members + private BlogInfo Blog { get; set; } = null; + private PostInfo Post { get; set; } = null; + private CommentInfo Comment { get; set; } = null; + private List AllComments { get; set; } = new List(); + + private ModuleSettings _Settings; + private ModuleSettings Settings + { + get + { + if (_Settings is null) + { + _Settings = ModuleSettings.GetModuleSettings(ActiveModule.ModuleID); + } + return _Settings; + } + set + { + _Settings = value; + } + } + + private ViewSettings _viewSettings; + private ViewSettings ViewSettings + { + get + { + if (_viewSettings is null) + { + _viewSettings = ViewSettings.GetViewSettings(ActiveModule.TabModuleID); + } + return _viewSettings; + } + set + { + _viewSettings = value; + } + } + + private ContextSecurity _Security; + private ContextSecurity Security + { + get + { + if (_Security is null) + { + _Security = new ContextSecurity(ActiveModule.ModuleID, ActiveModule.TabID, Blog, UserInfo); + } + return _Security; + } + set + { + _Security = value; + } + } + #endregion + + #region Service Methods + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.ApproveComment)] + [ValidateAntiForgeryToken()] + [ActionName("Approve")] + public HttpResponseMessage ApproveComment(CommentDTO postData) + { + SetContext(postData); + if (Blog is null | Comment is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + ApproveComment(ActiveModule.ModuleID, Blog.BlogID, Comment); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.EditPost)] + [ValidateAntiForgeryToken()] + [ActionName("Delete")] + public HttpResponseMessage DeleteComment(CommentDTO postData) + { + SetContext(postData); + if (Blog is null | Comment is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + DeleteComment(ActiveModule.ModuleID, Blog.BlogID, Comment); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.AddComment)] + [ValidateAntiForgeryToken()] + [ActionName("Karma")] + public HttpResponseMessage ReportComment(CommentDTO postData) + { + SetContext(postData); + if (Blog is null | Comment is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + if (UserInfo.UserID < 0) + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + int ret = Data.DataProvider.Instance().AddCommentKarma(postData.CommentId, UserInfo.UserID, postData.Karma); + if (ret == -1) + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "exists" }); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.AddComment)] + [ValidateAntiForgeryToken()] + [ActionName("Add")] + public HttpResponseMessage AddComment(FullCommentDTO postData) + { + SetContext(postData); + Post = PostsController.GetPost(postData.PostId, ActiveModule.ModuleID, ""); + if (Blog is null | Post is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + var objComment = new CommentInfo(); + objComment.ContentItemId = Post.ContentItemId; + objComment.CreatedByUserID = UserInfo.UserID; + objComment.ParentId = postData.ParentId; + objComment.Comment = HttpUtility.HtmlEncode(SafeStringSimpleHtml(postData.Comment).Replace(Constants.vbCrLf, "
")); + objComment.Approved = Security.CanAutoApproveComment | Security.CanApproveComment | Post.CreatedByUserID == UserInfo.UserID; + objComment.Author = SafeString(postData.Author); + objComment.Email = SafeString(postData.Email); + objComment.Website = SafeString(postData.Website); + objComment.CommentID = AddComment(Blog, Post, ref objComment); + if (!objComment.Approved) + { + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "successnotapproved" }); + } + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + + [HttpGet()] + [BlogAuthorize(SecurityAccessLevel.ViewModule)] + [ValidateAntiForgeryToken()] + [ActionName("List")] + public HttpResponseMessage ListComments() + { + int BlogId = -1; + int PostId = -1; + Extensions.ReadValue(ref HttpContext.Current.Request.Params, "blogId", ref BlogId); + Extensions.ReadValue(ref HttpContext.Current.Request.Params, "postId", ref PostId); + Blog = BlogsController.GetBlog(BlogId, UserInfo.UserID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + Post = PostsController.GetPost(PostId, ActiveModule.ModuleID, ""); + if (Blog is null | Post is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + if (!Security.CanViewComments) + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "" }); + var ViewSettings = Common.ViewSettings.GetViewSettings(ActiveModule.TabModuleID); + AllComments = GetCommentsByContentItem(Post.ContentItemId, Security.CanApproveComment, UserInfo.UserID); + var vt = new ViewTemplate(); + var tmgr = new TemplateManager(PortalSettings, ViewSettings.Template); + vt.TemplatePath = tmgr.TemplatePath; + vt.TemplateRelPath = tmgr.TemplateRelPath; + vt.TemplateMapPath = tmgr.TemplateMapPath; + vt.DefaultReplacer = new BlogTokenReplace(ActiveModule, Security, Blog, Post, Settings, ViewSettings); + vt.StartTemplate = "CommentsTemplate.html"; + vt.GetData += TemplateGetData; + vt.DataBind(); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = vt.GetContentsAsString() }); + } + + [HttpPost()] + [AllowAnonymous()] + [ActionName("Pingback")] + public HttpResponseMessage Pingback() + { + + int BlogId = -1; + int PostId = -1; + Extensions.ReadValue(ref HttpContext.Current.Request.Params, "blogId", ref BlogId); + Extensions.ReadValue(ref HttpContext.Current.Request.Params, "postId", ref PostId); + Blog = BlogsController.GetBlog(BlogId, UserInfo.UserID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + if (!Blog.EnablePingBackReceive) + { + return Request.CreateResponse(HttpStatusCode.NotFound, new { Result = "This blog does not accept pingbacks" }); + } + Post = PostsController.GetPost(PostId, ActiveModule.ModuleID, ""); + if (Post is null) + { + return PingBackError(32, "The specified target URI does not exist."); + } + + var doc = RetrieveXmlDocument(HttpContext.Current); + var list = doc.SelectNodes("methodCall/params/param/value/string") ?? doc.SelectNodes("methodCall/params/param/value"); + + if (list is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "Cannot parse the request" }); + } + + string sourceUrl = SafeString(list[0].InnerText.Trim()); + string targetUrl = SafeString(list[1].InnerText.Trim()); + + bool containsHtml = false; + bool sourceHasLink = false; + string title = sourceUrl; + + try + { + CheckSourcePage(sourceUrl, targetUrl, ref sourceHasLink, ref title); + } + catch (Exception ex) + { + } + + if (!IsFirstPingBack(Post, sourceUrl)) + { + return PingBackError(48, "The pingback has already been registered."); + } + + if (!sourceHasLink) + { + return PingBackError(17, "The source URI does not contain a link to the target URI, and so cannot be used as a source."); + } + + if (containsHtml) + { + // spam + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "Cannot parse the request" }); + } + else + { + var objComment = new CommentInfo() { ContentItemId = Post.ContentItemId, Author = GetDomain(sourceUrl), Website = sourceUrl }; + string comment = string.Format(DotNetNuke.Services.Localization.Localization.GetString("PingbackComment", SharedResourceFileName), objComment.Author, sourceUrl, title); + objComment.Comment = HttpUtility.HtmlEncode(comment); + objComment.Approved = Blog.AutoApprovePingBack; + objComment.CommentID = AddComment(Blog, Post, ref objComment); + return PingBackSuccess(); + } + + } + + [HttpPost()] + [AllowAnonymous()] + [ActionName("Trackback")] + public HttpResponseMessage Trackback() + { + + int BlogId = -1; + int PostId = -1; + Extensions.ReadValue(ref HttpContext.Current.Request.Params, "blogId", ref BlogId); + Extensions.ReadValue(ref HttpContext.Current.Request.Params, "postId", ref PostId); + Blog = BlogsController.GetBlog(BlogId, UserInfo.UserID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + if (!Blog.EnableTrackBackReceive) + { + return Request.CreateResponse(HttpStatusCode.NotFound, new { Result = "This blog does not accept trackbacks" }); + } + Post = PostsController.GetPost(PostId, ActiveModule.ModuleID, ""); + if (Post is null) + { + return TrackBackResponse("The source page does not link"); + } + + string title = SafeString(HttpContext.Current.Request.Params["title"]); + string excerpt = SafeString(HttpContext.Current.Request.Params["excerpt"]); + string blogName = SafeString(HttpContext.Current.Request.Params["blog_name"]); + string sourceUrl = string.Empty; + if (HttpContext.Current.Request.Params["url"] is not null) + { + sourceUrl = SafeString(HttpContext.Current.Request.Params["url"].Split(',')[0], DotNetNuke.Security.PortalSecurity.FilterFlag.NoSQL & DotNetNuke.Security.PortalSecurity.FilterFlag.NoScripting); + } + + bool sourceHasLink = false; + + try + { + CheckSourcePage(sourceUrl, Post.PermaLink(PortalSettings), ref sourceHasLink, ref title); + } + catch (Exception ex) + { + } + + if (!IsFirstPingBack(Post, sourceUrl)) + { + return TrackBackResponse("Trackback already registered"); + } + + if (!sourceHasLink) + { + return TrackBackResponse("The source page does not link"); + } + + var objComment = new CommentInfo() { ContentItemId = Post.ContentItemId, Author = blogName, Website = sourceUrl }; + string comment = string.Format(DotNetNuke.Services.Localization.Localization.GetString("TrackbackComment", SharedResourceFileName), blogName, sourceUrl, title); + objComment.Comment = HttpUtility.HtmlEncode(comment); + objComment.Approved = Blog.AutoApproveTrackBack; + objComment.CommentID = AddComment(Blog, Post, ref objComment); + return TrackBackResponse(); + + } + #endregion + + #region Private Methods + private void SetContext(CommentDTO data) + { + Blog = BlogsController.GetBlog(data.BlogId, UserInfo.UserID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + Comment = GetComment(data.CommentId, UserInfo.UserID); + } + + private void SetContext(FullCommentDTO data) + { + Blog = BlogsController.GetBlog(data.BlogId, UserInfo.UserID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + } + + private void TemplateGetData(string DataSource, Dictionary Parameters, ref List Replacers, ref List Arguments, object callingObject) + { + + switch (DataSource.ToLower() ?? "") + { + + case "comments": + { + + if (callingObject is not null && callingObject is CommentInfo) + { + int parent = ((CommentInfo)callingObject).CommentID; + foreach (CommentInfo c in AllComments.Where(cmt => cmt.ParentId == parent).OrderBy(cmt => cmt.CreatedOnDate)) + Replacers.Add(new BlogTokenReplace(ActiveModule, Security, Blog, Post, Settings, ViewSettings, c)); + } + else + { + foreach (CommentInfo c in AllComments.Where(cmt => cmt.ParentId == -1).OrderBy(cmt => cmt.CreatedOnDate)) + Replacers.Add(new BlogTokenReplace(ActiveModule, Security, Blog, Post, Settings, ViewSettings, c)); + } + + break; + } + + } + + } + + private static XmlDocument RetrieveXmlDocument(HttpContext context) + { + string xml = ParseRequest(context); + if (!xml.Contains("pingback.ping")) + { + context.Response.StatusCode = 404; + context.Response.End(); + } + var doc = new XmlDocument(); + doc.LoadXml(xml); + return doc; + } + + private static string ParseRequest(HttpContext context) + { + var buffer = new byte[(int)(context.Request.InputStream.Length - 1L) + 1]; + context.Request.InputStream.Read(buffer, 0, buffer.Length); + return Encoding.Default.GetString(buffer); + } + + private static bool IsFirstPingBack(PostInfo post, string sourceUrl) + { + foreach (CommentInfo c in GetCommentsByContentItem(post.ContentItemId, true, -1)) + { + if (c.Website.ToString().Equals(sourceUrl, StringComparison.OrdinalIgnoreCase)) + return false; + } + return true; + } + + private static HttpResponseMessage TrackBackResponse() + { + return TrackBackResponse("0"); + } + private static HttpResponseMessage TrackBackResponse(string status) + { + string reply = string.Format("{0}", status); + var res = new HttpResponseMessage(HttpStatusCode.OK); + res.Content = new StringContent(reply, Encoding.UTF8, "application/xml"); + return res; + } + + private static HttpResponseMessage PingBackSuccess() + { + string Success = "Thanks!"; + var res = new HttpResponseMessage(HttpStatusCode.OK); + res.Content = new StringContent(Success, Encoding.UTF8, "application/xml"); + return res; + } + + private static HttpResponseMessage PingBackError(int code, string message) + { + var sb = new StringBuilder(); + sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append("faultCode"); + sb.AppendFormat("{0}", code); + sb.Append(""); + sb.Append(""); + sb.Append("faultString"); + sb.AppendFormat("{0}", message); + sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append(""); + var res = new HttpResponseMessage(HttpStatusCode.OK); + res.Content = new StringContent(sb.ToString(), Encoding.UTF8, "application/xml"); + return res; + } + + private static string GetDomain(string sourceUrl) + { + int start = sourceUrl.IndexOf("://") + 3; + int stop = sourceUrl.IndexOf("/", start); + return sourceUrl.Substring(start, stop - start).Replace("www.", string.Empty); + } + + private static void CheckSourcePage(string sourceUrl, string targetUrl, ref bool sourceContainsLink, ref string title) + { + + var remoteFile = new WebPage(new Uri(sourceUrl)); + string html = remoteFile.GetFileAsString(); + var RegexTitle = new Regex(@"(?<=)([\s\S]*)(?=)", RegexOptions.IgnoreCase | RegexOptions.Compiled); + var titleMatch = RegexTitle.Match(html); + if (titleMatch.Success) + title = SafeString(titleMatch.Value.Trim(Conversions.ToChar(Constants.vbCrLf)).Trim()); + html = html.ToUpperInvariant(); + targetUrl = targetUrl.ToUpperInvariant(); + sourceContainsLink = html.Contains("HREF=\"" + targetUrl + "\"") || html.Contains("HREF='" + targetUrl + "'"); + + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/LegacyUrls/LegacyUrlInfo_Interfaces.cs b/Server/Core/Entities/LegacyUrls/LegacyUrlInfo_Interfaces.cs new file mode 100644 index 00000000..3274bcc0 --- /dev/null +++ b/Server/Core/Entities/LegacyUrls/LegacyUrlInfo_Interfaces.cs @@ -0,0 +1,74 @@ +using System; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Modules; + +namespace DotNetNuke.Modules.Blog.Entities.LegacyUrls +{ + public partial class LegacyUrlInfo : IHydratable + { + + #region IHydratable Implementation + /// ----------------------------------------------------------------------------- + /// + /// Fill hydrates the object from a Datareader + /// + /// The Fill method is used by the CBO method to hydrtae the object + /// rather than using the more expensive Refection methods. + /// + /// [pdonker] 05/23/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void Fill(IDataReader dr) + { + + ContentItemId = Convert.ToInt32(Null.SetNull(dr["ContentItemId"], ContentItemId)); + EntryId = Convert.ToInt32(Null.SetNull(dr["EntryId"], EntryId)); + Url = Convert.ToString(Null.SetNull(dr["Url"], Url)); + + } + /// ----------------------------------------------------------------------------- + /// + /// Gets and sets the Key ID + /// + /// The KeyID property is part of the IHydratble interface. It is used + /// as the key property when creating a Dictionary + /// + /// [pdonker] 05/23/2013 Created + /// + /// ----------------------------------------------------------------------------- + public int KeyID + { + get + { + return default; + } + set + { + } + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/LegacyUrls/LegacyUrlInfo_Properties.cs b/Server/Core/Entities/LegacyUrls/LegacyUrlInfo_Properties.cs new file mode 100644 index 00000000..cfad337e --- /dev/null +++ b/Server/Core/Entities/LegacyUrls/LegacyUrlInfo_Properties.cs @@ -0,0 +1,55 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; + +namespace DotNetNuke.Modules.Blog.Entities.LegacyUrls +{ + public partial class LegacyUrlInfo + { + + #region Private Members + #endregion + + #region Constructors + public LegacyUrlInfo() + { + } + + public LegacyUrlInfo(string url, int contentItemId, int entryId) + { + ContentItemId = contentItemId; + EntryId = entryId; + Url = url; + } + #endregion + + #region Public Properties + [DataMember()] + public int ContentItemId { get; set; } = -1; + [DataMember()] + public int EntryId { get; set; } = -1; + [DataMember()] + public string Url { get; set; } = ""; + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/LegacyUrls/LegacyUrlsController_CRUD.cs b/Server/Core/Entities/LegacyUrls/LegacyUrlsController_CRUD.cs new file mode 100644 index 00000000..bfe52ddd --- /dev/null +++ b/Server/Core/Entities/LegacyUrls/LegacyUrlsController_CRUD.cs @@ -0,0 +1,39 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +using DotNetNuke.Modules.Blog.Data; + +namespace DotNetNuke.Modules.Blog.Entities.LegacyUrls +{ + + public partial class LegacyUrlsController + { + + public static void AddLegacyUrl(LegacyUrlInfo objLegacyUrl) + { + + DataProvider.Instance().AddLegacyUrl(objLegacyUrl.ContentItemId, objLegacyUrl.EntryId, objLegacyUrl.Url); + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Posts/PostAuthor.cs b/Server/Core/Entities/Posts/PostAuthor.cs new file mode 100644 index 00000000..3ffe36d8 --- /dev/null +++ b/Server/Core/Entities/Posts/PostAuthor.cs @@ -0,0 +1,182 @@ +using System; +using System.Data; +using System.Runtime.Serialization; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using static DotNetNuke.Common.Globals; +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Entities.Users; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Entities.Posts +{ + + public class PostAuthor : UserInfo, IHydratable, IPropertyAccess + { + + #region Public Properties + [DataMember()] + public int ParentTabID { get; set; } = -1; + public int NrPosts { get; set; } = 0; + [DataMember()] + public int NrViews { get; set; } = 0; + [DataMember()] + public DateTime LastPublishDate { get; set; } = DateTime.MinValue; + [DataMember()] + public DateTime FirstPublishDate { get; set; } = DateTime.MinValue; + #endregion + + #region IHydratable Implementation + /// ----------------------------------------------------------------------------- + /// + /// Fill hydrates the object from a Datareader + /// + /// The Fill method is used by the CBO method to hydrtae the object + /// rather than using the more expensive Refection methods. + /// + /// [pdonker] 02/16/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void Fill(IDataReader dr) + { + PortalID = Convert.ToInt32(Null.SetNull(dr["PortalID"], PortalID)); + IsSuperUser = Convert.ToBoolean(Null.SetNull(dr["IsSuperUser"], IsSuperUser)); + UserID = Convert.ToInt32(Null.SetNull(dr["UserID"], UserID)); + FirstName = Convert.ToString(Null.SetNull(dr["FirstName"], FirstName)); + LastName = Convert.ToString(Null.SetNull(dr["LastName"], LastName)); + DisplayName = Convert.ToString(Null.SetNull(dr["DisplayName"], DisplayName)); + Username = Convert.ToString(Null.SetNull(dr["Username"], Username)); + Email = Convert.ToString(Null.SetNull(dr["Email"], Email)); + NrPosts = Convert.ToInt32(Null.SetNull(dr["NrPosts"], NrPosts)); + NrViews = Convert.ToInt32(Null.SetNull(dr["NrViews"], NrViews)); + LastPublishDate = Conversions.ToDate(Null.SetNull(dr["LastPublishDate"], LastPublishDate)); + FirstPublishDate = Conversions.ToDate(Null.SetNull(dr["FirstPublishDate"], FirstPublishDate)); + } + /// ----------------------------------------------------------------------------- + /// + /// Gets and sets the Key ID + /// + /// The KeyID property is part of the IHydratble interface. It is used + /// as the key property when creating a Dictionary + /// + /// [pdonker] 02/16/2013 Created + /// + /// ----------------------------------------------------------------------------- + public int KeyID + { + get + { + return default; + } + set + { + } + } + #endregion + + #region IPropertyAccess Implementation + public new string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "nrposts": + { + return NrPosts.ToString(OutputFormat, formatProvider); + } + case "nrviews": + { + return NrViews.ToString(OutputFormat, formatProvider); + } + case "lastpublishdate": + { + return LastPublishDate.ToString(OutputFormat, formatProvider); + } + case "firstpublishdate": + { + return FirstPublishDate.ToString(OutputFormat, formatProvider); + } + case "parenturl": + { + return PermaLink(ParentTabID); + } + + default: + { + return base.GetProperty(strPropertyName, strFormat, formatProvider, AccessingUser, AccessLevel, ref PropertyNotFound); + } + } + } + + public new CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + #region Public Methods + public string PermaLink(DotNetNuke.Entities.Portals.PortalSettings portalSettings) + { + return PermaLink(portalSettings.ActiveTab); + } + public string PermaLink(int strParentTabID) + { + var oTabController = new DotNetNuke.Entities.Tabs.TabController(); + var oParentTab = oTabController.GetTab(strParentTabID, DotNetNuke.Entities.Portals.PortalSettings.Current.PortalId, false); + _permaLink = string.Empty; + return PermaLink(oParentTab); + } + + private string _permaLink = ""; + public string PermaLink(DotNetNuke.Entities.Tabs.TabInfo tab) + { + if (string.IsNullOrEmpty(_permaLink)) + { + _permaLink = ApplicationURL(tab.TabID) + "&author=" + UserID.ToString(); + if (DotNetNuke.Entities.Host.Host.UseFriendlyUrls) + { + _permaLink = FriendlyUrl(tab, _permaLink, ""); + } + else + { + _permaLink = ResolveUrl(_permaLink); + } + } + return _permaLink; + } + + #endregion + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Posts/PostInfo.cs b/Server/Core/Entities/Posts/PostInfo.cs new file mode 100644 index 00000000..453419db --- /dev/null +++ b/Server/Core/Entities/Posts/PostInfo.cs @@ -0,0 +1,131 @@ +using System.Collections.Generic; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Linq; +using System.Web.UI.WebControls; +using static DotNetNuke.Common.Globals; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Terms; + +namespace DotNetNuke.Modules.Blog.Entities.Posts +{ + + public partial class PostInfo + { + + public List PostCategories + { + get + { + return Terms.Where(t => t.VocabularyId != 1).ToList(); + } + } + + public List PostTags + { + get + { + return Terms.Where(t => t.VocabularyId == 1).ToList(); + } + } + + public string PermaLink(int strParentTabID) + { + var oTabController = new DotNetNuke.Entities.Tabs.TabController(); + var oParentTab = oTabController.GetTab(strParentTabID, DotNetNuke.Entities.Portals.PortalSettings.Current.PortalId, false); + _permaLink = string.Empty; + return PermaLink(oParentTab); + } + + public string PermaLink() + { + return PermaLink(DotNetNuke.Entities.Portals.PortalSettings.Current.ActiveTab); + } + + public string PermaLink(DotNetNuke.Entities.Portals.PortalSettings portalSettings) + { + return PermaLink(portalSettings.ActiveTab); + } + + private string _permaLink = ""; + public string PermaLink(DotNetNuke.Entities.Tabs.TabInfo tab) + { + if (string.IsNullOrEmpty(_permaLink)) + { + _permaLink = ApplicationURL(tab.TabID); + if (!string.IsNullOrEmpty(Locale)) + { + _permaLink += "&language=" + Locale; + } + _permaLink += "&Post=" + ContentItemId.ToString(); + if (DotNetNuke.Entities.Host.Host.UseFriendlyUrls) + { + _permaLink = FriendlyUrl(tab, _permaLink, GetSafePageName(LocalizedTitle)); + } + else + { + _permaLink = ResolveUrl(_permaLink); + } + } + return _permaLink; + } + + private List _terms; + public new List Terms + { + get + { + if (_terms is null) + { + _terms = TermsController.GetTermsByPost(ContentItemId, Blog.ModuleID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + } + if (_terms is null) + { + _terms = new List(); + } + return _terms; + } + set + { + _terms = value; + } + } + + private BlogInfo _blog = null; + public BlogInfo Blog + { + get + { + if (_blog is null) + { + _blog = BlogsController.GetBlog(BlogID, -1, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + } + return _blog; + } + set + { + _blog = value; + } + } + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Posts/PostInfo_Interfaces.cs b/Server/Core/Entities/Posts/PostInfo_Interfaces.cs new file mode 100644 index 00000000..38d0b411 --- /dev/null +++ b/Server/Core/Entities/Posts/PostInfo_Interfaces.cs @@ -0,0 +1,496 @@ +using System; +using System.Collections.Generic; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Modules.Blog.Common; + +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Entities.Posts +{ + + [Serializable()] + [XmlRoot("Post")] + [DataContract()] + public partial class PostInfo : IHydratable, IPropertyAccess, IXmlSerializable + { + + #region ML Properties + public int ParentTabID { get; set; } = -1; + #endregion + + #region IHydratable Implementation + /// ----------------------------------------------------------------------------- + /// + /// Fill hydrates the object from a Datareader + /// + /// The Fill method is used by the CBO method to hydrtae the object + /// rather than using the more expensive Refection methods. + /// + /// [pdonker] 02/19/2013 Created + /// + /// ----------------------------------------------------------------------------- + public override void Fill(IDataReader dr) + { + FillInternal(dr); + BlogID = Convert.ToInt32(Null.SetNull(dr["BlogID"], BlogID)); + Title = Convert.ToString(Null.SetNull(dr["Title"], Title)); + Summary = Convert.ToString(Null.SetNull(dr["Summary"], Summary)); + Image = Convert.ToString(Null.SetNull(dr["Image"], Image)); + Published = Convert.ToBoolean(Null.SetNull(dr["Published"], Published)); + PublishedOnDate = Conversions.ToDate(Null.SetNull(dr["PublishedOnDate"], PublishedOnDate)); + AllowComments = Convert.ToBoolean(Null.SetNull(dr["AllowComments"], AllowComments)); + DisplayCopyright = Convert.ToBoolean(Null.SetNull(dr["DisplayCopyright"], DisplayCopyright)); + Copyright = Convert.ToString(Null.SetNull(dr["Copyright"], Copyright)); + Locale = Convert.ToString(Null.SetNull(dr["Locale"], Locale)); + ViewCount = Convert.ToInt32(Null.SetNull(dr["ViewCount"], ViewCount)); + Username = Convert.ToString(Null.SetNull(dr["Username"], Username)); + Email = Convert.ToString(Null.SetNull(dr["Email"], Email)); + DisplayName = Convert.ToString(Null.SetNull(dr["DisplayName"], DisplayName)); + AltLocale = Convert.ToString(Null.SetNull(dr["AltLocale"], AltLocale)); + AltTitle = Convert.ToString(Null.SetNull(dr["AltTitle"], AltTitle)); + AltSummary = Convert.ToString(Null.SetNull(dr["AltSummary"], AltSummary)); + AltContent = Convert.ToString(Null.SetNull(dr["AltContent"], AltContent)); + NrComments = Convert.ToInt32(Null.SetNull(dr["NrComments"], NrComments)); + PublishedOnDate = DateTime.SpecifyKind(PublishedOnDate, DateTimeKind.Utc); + } + /// ----------------------------------------------------------------------------- + /// + /// Gets and sets the Key ID + /// + /// The KeyID property is part of the IHydratble interface. It is used + /// as the key property when creating a Dictionary + /// + /// [pdonker] 02/19/2013 Created + /// + /// ----------------------------------------------------------------------------- + public override int KeyID + { + get + { + return ContentItemId; + } + set + { + ContentItemId = value; + } + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "blogid": + { + return BlogID.ToString(OutputFormat, formatProvider); + } + case "title": + { + return PropertyAccess.FormatString(Title, strFormat); + } + case "summary": + { + return Summary.OutputHtml(strFormat); + } + case "image": + { + return PropertyAccess.FormatString(Image, strFormat); + } + case "isvisible": + { + return Published.ToString(); + } + case "published": + { + return (Published && PublishedOnDate < DateTime.UtcNow).ToString(); + } + case "publishedyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(Published, formatProvider); + } + case "publishedondate": + { + var userTimeZone = portalSettings.TimeZone; + if (AccessingUser.Profile.PreferredTimeZone is not null) + { + userTimeZone = AccessingUser.Profile.PreferredTimeZone; + } + return UtcToLocalTime(PublishedOnDate, userTimeZone).ToString(OutputFormat, formatProvider); + } + case "publishedondateutc": + { + return PublishedOnDate.ToString(OutputFormat, formatProvider); + } + case "allowcomments": + { + return AllowComments.ToString(); + } + case "allowcommentsyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(AllowComments, formatProvider); + } + case "displaycopyright": + { + return DisplayCopyright.ToString(); + } + case "displaycopyrightyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(DisplayCopyright, formatProvider); + } + case "copyright": + { + return PropertyAccess.FormatString(Copyright, strFormat); + } + case "locale": + { + return PropertyAccess.FormatString(Locale, strFormat); + } + case "nrcomments": + { + return NrComments.ToString(OutputFormat, formatProvider); + } + case "viewcount": + { + return ViewCount.ToString(OutputFormat, formatProvider); + } + case "username": + { + return PropertyAccess.FormatString(Username, strFormat); + } + case "email": + { + return PropertyAccess.FormatString(Email, strFormat); + } + case "displayname": + { + return PropertyAccess.FormatString(DisplayName, strFormat); + } + case "altlocale": + { + return PropertyAccess.FormatString(AltLocale, strFormat); + } + case "alttitle": + { + return PropertyAccess.FormatString(AltTitle, strFormat); + } + case "altsummary": + { + return PropertyAccess.FormatString(AltSummary, strFormat); + } + case "altcontent": + { + return PropertyAccess.FormatString(AltContent, strFormat); + } + case "localizedtitle": + { + return PropertyAccess.FormatString(LocalizedTitle, strFormat); + } + case "localizedsummary": + { + return LocalizedSummary.OutputHtml(strFormat); + } + case "localizedcontent": + { + return LocalizedContent.OutputHtml(strFormat); + } + case "contentitemid": + { + return ContentItemId.ToString(OutputFormat, formatProvider); + } + case "createdbyuserid": + { + return CreatedByUserID.ToString(OutputFormat, formatProvider); + } + case "createdondate": + { + return CreatedOnDate.ToString(OutputFormat, formatProvider); + } + case "lastmodifiedbyuserid": + { + return LastModifiedByUserID.ToString(OutputFormat, formatProvider); + } + case "lastmodifiedondate": + { + return LastModifiedOnDate.ToString(OutputFormat, formatProvider); + } + case "content": + case "contents": + { + return Content.OutputHtml(strFormat); + } + case "hasimage": + { + return (!string.IsNullOrEmpty(Image)).ToString(formatProvider); + } + case "link": + case "permalink": + { + return PermaLink(DotNetNuke.Entities.Portals.PortalSettings.Current); + } + case "parenturl": + { + return PermaLink(ParentTabID); + } + case "currentmode": + { + return DotNetNuke.Entities.Portals.PortalSettings.Current.UserMode.ToString(); + } + + default: + { + PropertyNotFound = true; + break; + } + } + + return Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + #region IXmlSerializable Implementation + /// ----------------------------------------------------------------------------- + /// + /// GetSchema returns the XmlSchema for this class + /// + /// GetSchema is implemented as a stub method as it is not required + /// + /// [pdonker] 05/03/2013 Created + /// + /// ----------------------------------------------------------------------------- + public XmlSchema GetSchema() + { + return null; + } + + /// ----------------------------------------------------------------------------- + /// + /// ReadXml fills the object (de-serializes it) from the XmlReader passed + /// + /// + /// The XmlReader that contains the xml for the object + /// + /// [pdonker] 05/03/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void ReadXml(XmlReader reader) + { + // not implemented + } + + internal int ImportedPostId { get; set; } = -1; + internal List ImportedFiles { get; set; } + internal List ImportedTags { get; set; } + internal List ImportedCategories { get; set; } + + public void FromXml(XmlNode xml) + { + if (xml is null) + return; + + int argVariable = ImportedPostId; + Common.Extensions.ReadValue(ref xml, "PostId", ref argVariable); + ImportedPostId = argVariable; + string argVariable1 = Title; + Common.Extensions.ReadValue(ref xml, "Title", ref argVariable1); + Title = argVariable1; + var argVariable2 = TitleLocalizations; + Common.Extensions.ReadValue(ref xml, "TitleLocalizations", ref argVariable2); + TitleLocalizations = argVariable2; + string argVariable3 = Summary; + Common.Extensions.ReadValue(ref xml, "Summary", ref argVariable3); + Summary = argVariable3; + var argVariable4 = SummaryLocalizations; + Common.Extensions.ReadValue(ref xml, "SummaryLocalizations", ref argVariable4); + SummaryLocalizations = argVariable4; + string argVariable5 = Content; + Common.Extensions.ReadValue(ref xml, "Content", ref argVariable5); + Content = argVariable5; + var argVariable6 = ContentLocalizations; + Common.Extensions.ReadValue(ref xml, "ContentLocalizations", ref argVariable6); + ContentLocalizations = argVariable6; + string argVariable7 = Image; + Common.Extensions.ReadValue(ref xml, "Image", ref argVariable7); + Image = argVariable7; + bool argVariable8 = Published; + Common.Extensions.ReadValue(ref xml, "Published", ref argVariable8); + Published = argVariable8; + var argVariable9 = PublishedOnDate; + Common.Extensions.ReadValue(ref xml, "PublishedOnDate", ref argVariable9); + PublishedOnDate = argVariable9; + bool argVariable10 = AllowComments; + Common.Extensions.ReadValue(ref xml, "AllowComments", ref argVariable10); + AllowComments = argVariable10; + bool argVariable11 = DisplayCopyright; + Common.Extensions.ReadValue(ref xml, "DisplayCopyright", ref argVariable11); + DisplayCopyright = argVariable11; + string argVariable12 = Copyright; + Common.Extensions.ReadValue(ref xml, "Copyright", ref argVariable12); + Copyright = argVariable12; + string argVariable13 = Locale; + Common.Extensions.ReadValue(ref xml, "Locale", ref argVariable13); + Locale = argVariable13; + string argVariable14 = Username; + Common.Extensions.ReadValue(ref xml, "Username", ref argVariable14); + Username = argVariable14; + string argVariable15 = Email; + Common.Extensions.ReadValue(ref xml, "Email", ref argVariable15); + Email = argVariable15; + + ImportedFiles = new List(); + foreach (XmlNode xFile in xml.SelectNodes("Files/File")) + ImportedFiles.Add(xFile.InnerText); + ImportedTags = new List(); + foreach (XmlNode xTag in xml.SelectNodes("Tag")) + ImportedTags.Add(xTag.InnerText); + ImportedCategories = new List(); + foreach (XmlNode xCategory in xml.SelectNodes("Category")) + ImportedCategories.Add(xCategory.InnerText); + + } + + /// ----------------------------------------------------------------------------- + /// + /// WriteXml converts the object to Xml (serializes it) and writes it using the XmlWriter passed + /// + /// + /// The XmlWriter that contains the xml for the object + /// + /// [pdonker] 05/03/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void WriteXml(XmlWriter writer) + { + writer.WriteStartElement("Post"); + writer.WriteElementString("PostId", ContentItemId.ToString()); + writer.WriteElementString("Title", Title); + writer.WriteElementString("TitleLocalizations", TitleLocalizations.ToString()); + writer.WriteElementString("Summary", Summary); + writer.WriteElementString("SummaryLocalizations", SummaryLocalizations.ToString()); + writer.WriteElementString("Content", Content); + writer.WriteElementString("ContentLocalizations", ContentLocalizations.ToString()); + writer.WriteElementString("Image", Image); + writer.WriteElementString("Published", Published.ToString()); + writer.WriteElementString("PublishedOnDate", PublishedOnDate.ToString()); + writer.WriteElementString("AllowComments", AllowComments.ToString()); + writer.WriteElementString("DisplayCopyright", DisplayCopyright.ToString()); + writer.WriteElementString("Copyright", Copyright); + writer.WriteElementString("Locale", Locale); + writer.WriteElementString("Username", Username); + writer.WriteElementString("Email", Email); + writer.WriteStartElement("Files"); + // pack files + string postDir = GetPostDirectoryMapPath(BlogID, ContentItemId); + + if (Directory.Exists(postDir)) + { + foreach (string fileName in from f in Directory.GetFiles(postDir) + select Path.GetFileName(f)) + writer.WriteElementString("File", fileName); + } + writer.WriteEndElement(); // Files + foreach (Terms.TermInfo t in PostTags) + writer.WriteElementString("Tag", t.Name); + foreach (Terms.TermInfo t in PostCategories) + writer.WriteElementString("Category", t.Name); + writer.WriteEndElement(); // Post + } + #endregion + + #region ToXml Methods + public string ToXml() + { + return ToXml("Post"); + } + + public string ToXml(string elementName) + { + var xml = new StringBuilder(); + xml.Append("<"); + xml.Append(elementName); + AddAttribute(ref xml, "BlogID", BlogID.ToString()); + AddAttribute(ref xml, "Title", Title); + AddAttribute(ref xml, "Summary", Summary); + AddAttribute(ref xml, "Image", Image); + AddAttribute(ref xml, "Published", Published.ToString()); + AddAttribute(ref xml, "PublishedOnDate", PublishedOnDate.ToUniversalTime().ToString("u")); + AddAttribute(ref xml, "AllowComments", AllowComments.ToString()); + AddAttribute(ref xml, "DisplayCopyright", DisplayCopyright.ToString()); + AddAttribute(ref xml, "Copyright", Copyright); + AddAttribute(ref xml, "Locale", Locale); + AddAttribute(ref xml, "ViewCount", ViewCount.ToString()); + AddAttribute(ref xml, "Username", Username); + AddAttribute(ref xml, "Email", Email); + AddAttribute(ref xml, "DisplayName", DisplayName); + xml.Append(" />"); + return xml.ToString(); + } + + private void AddAttribute(ref StringBuilder xml, string attributeName, string attributeValue) + { + xml.Append(" " + attributeName); + xml.Append("=\"" + attributeValue + "\""); + } + #endregion + + #region JSON Serialization + public void WriteJSON(ref Stream s) + { + var ser = new DataContractJsonSerializer(typeof(PostInfo)); + ser.WriteObject(s, this); + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Posts/PostInfo_Properties.cs b/Server/Core/Entities/Posts/PostInfo_Properties.cs new file mode 100644 index 00000000..09a1afa0 --- /dev/null +++ b/Server/Core/Entities/Posts/PostInfo_Properties.cs @@ -0,0 +1,200 @@ +using System; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; +using DotNetNuke.Modules.Blog.Common; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Entities.Posts +{ + public partial class PostInfo : DotNetNuke.Entities.Content.ContentItem + { + + #region Private Members + #endregion + + #region Constructors + public PostInfo() + { + } + #endregion + + #region Public Properties + [DataMember()] + public int BlogID { get; set; } = -1; + [DataMember()] + public string Title { get; set; } = ""; + [DataMember()] + public string Summary { get; set; } = ""; + [DataMember()] + public string Image { get; set; } = ""; + [DataMember()] + public bool Published { get; set; } = false; + [DataMember()] + public DateTime PublishedOnDate { get; set; } = DateTime.Now.ToUniversalTime(); + [DataMember()] + public bool AllowComments { get; set; } = true; + [DataMember()] + public bool DisplayCopyright { get; set; } = false; + [DataMember()] + public string Copyright { get; set; } = ""; + [DataMember()] + public string Locale { get; set; } = null; + [DataMember()] + public int ViewCount { get; set; } = 0; + [DataMember()] + public string Username { get; set; } = ""; + [DataMember()] + public string Email { get; set; } = ""; + [DataMember()] + public string DisplayName { get; set; } = ""; + [DataMember()] + public int NrComments { get; set; } = 0; + #endregion + + #region ML Properties + [DataMember()] + public string AltLocale { get; set; } = ""; + [DataMember()] + public string AltTitle { get; set; } = ""; + [DataMember()] + public string AltSummary { get; set; } = ""; + [DataMember()] + public string AltContent { get; set; } = ""; + + public string LocalizedTitle + { + get + { + return Conversions.ToString(Interaction.IIf(string.IsNullOrEmpty(AltTitle), Title, AltTitle)); + } + } + + public string LocalizedSummary + { + get + { + return Conversions.ToString(Interaction.IIf(string.IsNullOrEmpty(AltSummary), Summary, AltSummary)); + } + } + + public string LocalizedContent + { + get + { + return Conversions.ToString(Interaction.IIf(string.IsNullOrEmpty(AltContent), Content, AltContent)); + } + } + + /// + /// ML text type to handle the title of the post + /// + /// + /// + /// + public LocalizedText TitleLocalizations + { + get + { + if (_titleLocalizations is null) + { + if (ContentItemId == -1) + { + _titleLocalizations = new LocalizedText(); + } + else + { + _titleLocalizations = new LocalizedText(Data.DataProvider.Instance().GetPostLocalizations(ContentItemId), "Title"); + } + } + return _titleLocalizations; + } + set + { + _titleLocalizations = value; + } + } + private LocalizedText _titleLocalizations; + + /// + /// ML text type to handle the summary of the post + /// + /// + /// + /// + public LocalizedText SummaryLocalizations + { + get + { + if (_summaryLocalizations is null) + { + if (ContentItemId == -1) + { + _summaryLocalizations = new LocalizedText(); + } + else + { + _summaryLocalizations = new LocalizedText(Data.DataProvider.Instance().GetPostLocalizations(ContentItemId), "Summary"); + } + } + return _summaryLocalizations; + } + set + { + _summaryLocalizations = value; + } + } + private LocalizedText _summaryLocalizations; + + /// + /// ML text type to handle the content of the post + /// + /// + /// + /// + public LocalizedText ContentLocalizations + { + get + { + if (_contentLocalizations is null) + { + if (BlogID == -1) + { + _contentLocalizations = new LocalizedText(); + } + else + { + _contentLocalizations = new LocalizedText(Data.DataProvider.Instance().GetPostLocalizations(ContentItemId), "Content"); + } + } + return _contentLocalizations; + } + set + { + _contentLocalizations = value; + } + } + private LocalizedText _contentLocalizations; + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Posts/PostsController.cs b/Server/Core/Entities/Posts/PostsController.cs new file mode 100644 index 00000000..039a09db --- /dev/null +++ b/Server/Core/Entities/Posts/PostsController.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections.Generic; +using DotNetNuke.Common.Utilities; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Modules.Blog.Data; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Integration; + +namespace DotNetNuke.Modules.Blog.Entities.Posts +{ + + public partial class PostsController + { + + public static void PublishPost(PostInfo Post, bool publish, int publishedByUser) + { + + if (Post.Published == publish) + return; + Post.Published = publish; + UpdatePost(Post, publishedByUser); + PublishPost(Post, publishedByUser); + + } + + public static void PublishPost(PostInfo Post, int publishedByUser) + { + + var blog = BlogsController.GetBlog(Post.BlogID, publishedByUser, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + string journalUrl = Post.PermaLink(DotNetNuke.Entities.Portals.PortalSettings.Current); + int journalUserId = publishedByUser; + if (blog.PublishAsOwner) + journalUserId = blog.OwnerUserId; + JournalController.AddBlogPostToJournal(Post, DotNetNuke.Entities.Portals.PortalSettings.Current.PortalId, DotNetNuke.Entities.Portals.PortalSettings.Current.ActiveTab.TabID, journalUserId, journalUrl); + NotificationController.RemovePostPendingNotification(blog.ModuleID, blog.BlogID, Post.ContentItemId); + + var trackAndPingbacks = new Services.TrackAndPingBackController(Post); + var trd = new System.Threading.Thread(trackAndPingbacks.SendTrackAndPingBacks); + trd.IsBackground = true; + trd.Start(); + + } + + public static void DeletePost(PostInfo Post) + { + DataProvider.Instance().DeletePost(Post.ContentItemId); + var blog = BlogsController.GetBlog(Post.BlogID, -1, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + NotificationController.RemovePostPendingNotification(blog.ModuleID, blog.BlogID, Post.ContentItemId); + } + + public static void DeletePost(int contentItemId, int blogId, int portalId, int vocabularyId) + { + DataProvider.Instance().DeletePost(contentItemId); + } + + public static Dictionary GetPosts(int moduleId, int blogID, string displayLocale, int published, string limitToLocale, DateTime endDate, int authorUserId, bool onlyActionable, int pageIndex, int pageSize, string orderBy, ref int totalRecords, int userId, bool userIsAdmin) + { + + if (pageIndex < 0) + { + pageIndex = 0; + pageSize = int.MaxValue; + } + + var res = new Dictionary(); + using (var ir = DataProvider.Instance().GetPosts(moduleId, blogID, displayLocale, userId, userIsAdmin, published, limitToLocale, endDate, authorUserId, onlyActionable, pageIndex, pageSize, orderBy)) + { + res = CBO.FillDictionary("ContentItemID", ir, false); + ir.NextResult(); + var argdr = ir; + totalRecords = DotNetNuke.Common.Globals.GetTotalRecords(ref argdr); + } + return GetPostsWithBlog(res, blogID, moduleId, userId, displayLocale); + + } + + public static Dictionary GetPostsByTerm(int moduleId, int blogID, string displayLocale, int termId, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy, ref int totalRecords, int userId, bool userIsAdmin) + { + + if (pageIndex < 0) + { + pageIndex = 0; + pageSize = int.MaxValue; + } + + var res = new Dictionary(); + using (var ir = DataProvider.Instance().GetPostsByTerm(moduleId, blogID, displayLocale, userId, userIsAdmin, termId, published, limitToLocale, endDate, authorUserId, pageIndex, pageSize, orderBy)) + { + res = CBO.FillDictionary("ContentItemID", ir, false); + ir.NextResult(); + var argdr = ir; + totalRecords = DotNetNuke.Common.Globals.GetTotalRecords(ref argdr); + } + return GetPostsWithBlog(res, blogID, moduleId, userId, displayLocale); + + } + + public static Dictionary GetPostsByCategory(int moduleId, int blogID, string displayLocale, string categories, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy, ref int totalRecords, int userId, bool userIsAdmin) + { + + if (pageIndex < 0) + { + pageIndex = 0; + pageSize = int.MaxValue; + } + + var res = new Dictionary(); + using (var ir = DataProvider.Instance().GetPostsByCategory(moduleId, blogID, displayLocale, userId, userIsAdmin, categories, published, limitToLocale, endDate, authorUserId, pageIndex, pageSize, orderBy)) + { + res = CBO.FillDictionary("ContentItemID", ir, false); + ir.NextResult(); + var argdr = ir; + totalRecords = DotNetNuke.Common.Globals.GetTotalRecords(ref argdr); + } + return GetPostsWithBlog(res, blogID, moduleId, userId, displayLocale); + + } + + public static Dictionary GetPostsByBlog(int moduleId, int blogID, string displayLocale, int userId, int pageIndex, int pageSize, string orderBy, ref int totalRecords) + { + + if (pageIndex < 0) + { + pageIndex = 0; + pageSize = int.MaxValue; + } + + var res = new Dictionary(); + using (var ir = DataProvider.Instance().GetPostsByBlog(blogID, displayLocale, pageIndex, pageSize, orderBy)) + { + res = CBO.FillDictionary("ContentItemID", ir, false); + ir.NextResult(); + var argdr = ir; + totalRecords = DotNetNuke.Common.Globals.GetTotalRecords(ref argdr); + } + return GetPostsWithBlog(res, blogID, moduleId, userId, displayLocale); + + } + + public static Dictionary SearchPosts(int moduleId, int blogID, string displayLocale, string searchText, bool searchTitle, bool searchContents, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy, ref int totalRecords, int userId, bool userIsAdmin) + { + + if (pageIndex < 0) + { + pageIndex = 0; + pageSize = int.MaxValue; + } + + var res = new Dictionary(); + using (var ir = DataProvider.Instance().SearchPosts(moduleId, blogID, displayLocale, userId, userIsAdmin, searchText, searchTitle, searchContents, published, limitToLocale, endDate, authorUserId, pageIndex, pageSize, orderBy)) + { + res = CBO.FillDictionary("ContentItemID", ir, false); + ir.NextResult(); + var argdr = ir; + totalRecords = DotNetNuke.Common.Globals.GetTotalRecords(ref argdr); + } + return GetPostsWithBlog(res, blogID, moduleId, userId, displayLocale); + + } + + public static Dictionary SearchPostsByTerm(int moduleId, int blogID, string displayLocale, int termId, string searchText, bool searchTitle, bool searchContents, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy, ref int totalRecords, int userId, bool userIsAdmin) + { + + if (pageIndex < 0) + { + pageIndex = 0; + pageSize = int.MaxValue; + } + + var res = new Dictionary(); + using (var ir = DataProvider.Instance().SearchPostsByTerm(moduleId, blogID, displayLocale, userId, userIsAdmin, termId, searchText, searchTitle, searchContents, published, limitToLocale, endDate, authorUserId, pageIndex, pageSize, orderBy)) + { + res = CBO.FillDictionary("ContentItemID", ir, false); + ir.NextResult(); + var argdr = ir; + totalRecords = DotNetNuke.Common.Globals.GetTotalRecords(ref argdr); + } + return GetPostsWithBlog(res, blogID, moduleId, userId, displayLocale); + + } + + public static Dictionary SearchPostsByCategory(int moduleId, int blogID, string displayLocale, string categories, string searchText, bool searchTitle, bool searchContents, int published, string limitToLocale, DateTime endDate, int authorUserId, int pageIndex, int pageSize, string orderBy, ref int totalRecords, int userId, bool userIsAdmin) + { + + if (pageIndex < 0) + { + pageIndex = 0; + pageSize = int.MaxValue; + } + + var res = new Dictionary(); + using (var ir = DataProvider.Instance().SearchPostsByCategory(moduleId, blogID, displayLocale, userId, userIsAdmin, categories, searchText, searchTitle, searchContents, published, limitToLocale, endDate, authorUserId, pageIndex, pageSize, orderBy)) + { + res = CBO.FillDictionary("ContentItemID", ir, false); + ir.NextResult(); + var argdr = ir; + totalRecords = DotNetNuke.Common.Globals.GetTotalRecords(ref argdr); + } + return GetPostsWithBlog(res, blogID, moduleId, userId, displayLocale); + + } + + public static List GetAuthors(int moduleId, int blogId) + { + return CBO.FillCollection(DataProvider.Instance().GetAuthors(moduleId, blogId)); + } + + public static PostInfo GetPostByLegacyEntryId(int entryId, int portalId, string locale) + { + return CBO.FillObject(DataProvider.Instance().GetPostByLegacyEntryId(entryId, portalId, locale)); + } + + public static PostInfo GetPostByLegacyUrl(string url, int portalId, string locale) + { + return CBO.FillObject(DataProvider.Instance().GetPostByLegacyUrl(url, portalId, locale)); + } + + public static List GetChangedPosts(int moduleId, DateTime lastChange) + { + return CBO.FillCollection(DotNetNuke.Data.DataProvider.Instance().ExecuteReader("Blog_GetChangedPosts", moduleId, lastChange)); + } + + #region Private Methods + private static Dictionary GetPostsWithBlog(Dictionary selection, int blogId, int moduleId, int userId, string displayLocale) + { + + var res = new Dictionary(); + if (blogId == -1) + { + var blogs = BlogsController.GetBlogsByModule(moduleId, userId, displayLocale); + foreach (PostInfo e in selection.Values) + { + if (blogs.ContainsKey(e.BlogID)) + { + e.Blog = blogs[e.BlogID]; + res.Add(e.ContentItemId, e); + } + } + } + else + { + var blog = BlogsController.GetBlog(blogId, userId, displayLocale); + foreach (PostInfo e in selection.Values) + { + e.Blog = blog; + res.Add(e.ContentItemId, e); + } + } + return res; + + } + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Entities/Posts/PostsController_CRUD.cs b/Server/Core/Entities/Posts/PostsController_CRUD.cs new file mode 100644 index 00000000..0cc1a137 --- /dev/null +++ b/Server/Core/Entities/Posts/PostsController_CRUD.cs @@ -0,0 +1,71 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Modules.Blog.Common; +using DotNetNuke.Modules.Blog.Data; + +namespace DotNetNuke.Modules.Blog.Entities.Posts +{ + + public partial class PostsController + { + + public static PostInfo GetPost(int contentItemId, int moduleId, string locale) + { + + return CBO.FillObject(DataProvider.Instance().GetPost(contentItemId, moduleId, locale)); + + } + + public static int AddPost(ref PostInfo objPost, int createdByUser) + { + + objPost.ContentItemId = DataProvider.Instance().AddPost(objPost.AllowComments, objPost.BlogID, objPost.Content, objPost.Copyright, objPost.DisplayCopyright, objPost.Image, objPost.Locale, objPost.Published, objPost.PublishedOnDate, objPost.Summary, objPost.Terms.ToTermIDString(), objPost.Title, objPost.ViewCount, createdByUser); + + // localization + foreach (string l in objPost.TitleLocalizations.Locales) + DataProvider.Instance().SetPostLocalization(objPost.ContentItemId, l, objPost.TitleLocalizations[l], objPost.SummaryLocalizations[l], objPost.ContentLocalizations[l], createdByUser); + + return objPost.ContentItemId; + + } + + public static void UpdatePost(PostInfo objPost, int updatedByUser) + { + + DataProvider.Instance().UpdatePost(objPost.AllowComments, objPost.BlogID, objPost.Content, objPost.ContentItemId, objPost.Copyright, objPost.DisplayCopyright, objPost.Image, objPost.Locale, objPost.Published, objPost.PublishedOnDate, objPost.Summary, objPost.Terms.ToTermIDString(), objPost.Title, objPost.ViewCount, updatedByUser); + + // localization + foreach (string l in objPost.TitleLocalizations.Locales) + DataProvider.Instance().SetPostLocalization(objPost.ContentItemId, l, objPost.TitleLocalizations[l], objPost.SummaryLocalizations[l], objPost.ContentLocalizations[l], updatedByUser); + + } + + public static void DeletePost(int contentItemId) + { + + DataProvider.Instance().DeletePost(contentItemId); + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Posts/PostsController_Service.cs b/Server/Core/Entities/Posts/PostsController_Service.cs new file mode 100644 index 00000000..86d90941 --- /dev/null +++ b/Server/Core/Entities/Posts/PostsController_Service.cs @@ -0,0 +1,101 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Net; +using System.Net.Http; +using System.Web.Http; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Services; +using DotNetNuke.Web.Api; + +namespace DotNetNuke.Modules.Blog.Entities.Posts +{ + public partial class PostsController : DnnApiController + { + + public class PostDTO + { + public int BlogId { get; set; } + public int PostId { get; set; } + } + + #region Private Members + private BlogInfo Blog { get; set; } = null; + private PostInfo Post { get; set; } = null; + #endregion + + #region Service Methods + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.ApprovePost)] + [ValidateAntiForgeryToken()] + [ActionName("Approve")] + public HttpResponseMessage ApprovePost(PostDTO postData) + { + SetContext(postData); + if (Blog is null | Post is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + PublishPost(Post, true, UserInfo.UserID); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.EditPost)] + [ValidateAntiForgeryToken()] + [ActionName("Delete")] + public HttpResponseMessage DeletePost(PostDTO postData) + { + SetContext(postData); + if (Blog is null | Post is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + DeletePost(Post); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + + [HttpPost()] + [AllowAnonymous()] + [ValidateAntiForgeryToken()] + [ActionName("View")] + public HttpResponseMessage ViewPost(PostDTO postData) + { + SetContext(postData); + if (Blog is null | Post is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + Data.DataProvider.Instance().AddPostView(postData.PostId); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + #endregion + + #region Private Methods + private void SetContext(PostDTO data) + { + Blog = BlogsController.GetBlog(data.BlogId, UserInfo.UserID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + Post = GetPost(data.PostId, ActiveModule.ModuleID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Terms/TermInfo.cs b/Server/Core/Entities/Terms/TermInfo.cs new file mode 100644 index 00000000..ad0764c3 --- /dev/null +++ b/Server/Core/Entities/Terms/TermInfo.cs @@ -0,0 +1,367 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Xml; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using static DotNetNuke.Common.Globals; +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Content.Taxonomy; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Modules.Blog.Common; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Entities.Terms +{ + [Serializable()] + public class TermInfo : Term, IHydratable, IPropertyAccess + { + + #region Constructors + public TermInfo() + { + } + public TermInfo(string name) + { + Description = ""; + Name = name; + ParentTermId = 0; + TermId = -1; + } + #endregion + + #region Public Properties + public int TotalPosts { get; set; } + #endregion + + #region ML Properties + public int ParentTabID { get; set; } = -1; + public string AltLocale { get; set; } = ""; + public string AltName { get; set; } = ""; + public string AltDescription { get; set; } = ""; + + public string LocalizedName + { + get + { + return Conversions.ToString(Interaction.IIf(string.IsNullOrEmpty(AltName), Name, AltName)); + } + } + + public string LocalizedDescription + { + get + { + return Conversions.ToString(Interaction.IIf(string.IsNullOrEmpty(AltDescription), Description, AltDescription)); + } + } + + /// + /// ML text type to handle the name of the term + /// + /// + /// + /// + public LocalizedText NameLocalizations + { + get + { + if (_nameLocalizations is null) + { + if (TermId == -1) + { + _nameLocalizations = new LocalizedText(); + } + else + { + _nameLocalizations = new LocalizedText(Data.DataProvider.Instance().GetTermLocalizations(TermId), "Name"); + } + } + return _nameLocalizations; + } + set + { + _nameLocalizations = value; + } + } + private LocalizedText _nameLocalizations; + + /// + /// ML text type to handle the description of the term + /// + /// + /// + /// + public LocalizedText DescriptionLocalizations + { + get + { + if (_descriptionLocalizations is null) + { + if (TermId == -1) + { + _descriptionLocalizations = new LocalizedText(); + } + else + { + _descriptionLocalizations = new LocalizedText(Data.DataProvider.Instance().GetTermLocalizations(TermId), "Description"); + } + } + return _descriptionLocalizations; + } + set + { + _descriptionLocalizations = value; + } + } + private LocalizedText _descriptionLocalizations; + #endregion + + #region IHydratable Implementation + public override void Fill(IDataReader dr) + { + base.Fill(dr); + base.FillInternal(dr); + + TotalPosts = Null.SetNullInteger(dr["TotalPosts"]); + AltLocale = Convert.ToString(Null.SetNull(dr["AltLocale"], AltLocale)); + AltName = Convert.ToString(Null.SetNull(dr["AltName"], AltName)); + AltDescription = Convert.ToString(Null.SetNull(dr["AltDescription"], AltDescription)); + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + + var ParentModule = new ModuleInfo(); + // PropertySource(strObjectName.ToLower).GetProperty(strPropertyName, strFormat, formatProvider, AccessingUser, CurrentAccessLevel, PropertyNotFound) + + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "description": + { + return PropertyAccess.FormatString(Description, strFormat); + } + case "isheirarchical": + { + return IsHeirarchical.ToString(); + } + case "isheirarchicalyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(IsHeirarchical, formatProvider); + } + case "left": + { + return Left.ToString(OutputFormat, formatProvider); + } + case "title": + case "name": + { + return PropertyAccess.FormatString(Name, strFormat); + } + case "parenttermid": + { + return ParentTermId.ToStringOrZero(); + } + case "right": + { + return Right.ToString(OutputFormat, formatProvider); + } + case "termid": + { + return TermId.ToString(OutputFormat, formatProvider); + } + case "vocabularyid": + { + return VocabularyId.ToString(OutputFormat, formatProvider); + } + case "weight": + { + return Weight.ToString(OutputFormat, formatProvider); + } + case "createdbyuserid": + { + return CreatedByUserID.ToString(OutputFormat, formatProvider); + } + case "createdondate": + { + return CreatedOnDate.ToString(OutputFormat, formatProvider); + } + case "lastmodifiedbyuserid": + { + return LastModifiedByUserID.ToString(OutputFormat, formatProvider); + } + case "lastmodifiedondate": + { + return LastModifiedOnDate.ToString(OutputFormat, formatProvider); + } + case "totalposts": + { + return TotalPosts.ToString(OutputFormat, formatProvider); + } + case "altlocale": + { + return PropertyAccess.FormatString(AltLocale, strFormat); + } + case "altname": + { + return PropertyAccess.FormatString(AltName, strFormat); + } + case "altdescription": + { + return PropertyAccess.FormatString(AltDescription, strFormat); + } + case "localizedname": + { + return PropertyAccess.FormatString(LocalizedName, strFormat); + } + case "localizeddescription": + { + return PropertyAccess.FormatString(LocalizedDescription, strFormat); + } + case "link": + case "permalink": + { + return PermaLink(DotNetNuke.Entities.Portals.PortalSettings.Current); + } + case "parenturl": + { + return PermaLink(ParentTabID); + } + + default: + { + PropertyNotFound = true; + break; + } + } + + return Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + #region (De)serialization + internal List ImportedChildTerms { get; set; } + public void FromXml(XmlNode xml) + { + if (xml is null) + return; + string argVariable = Name; + Extensions.ReadValue(ref xml, "Name", ref argVariable); + Name = argVariable; + var argVariable1 = NameLocalizations; + Extensions.ReadValue(ref xml, "NameLocalizations", ref argVariable1); + NameLocalizations = argVariable1; + string argVariable2 = Description; + Extensions.ReadValue(ref xml, "Description", ref argVariable2); + Description = argVariable2; + var argVariable3 = DescriptionLocalizations; + Extensions.ReadValue(ref xml, "DescriptionLocalizations", ref argVariable3); + DescriptionLocalizations = argVariable3; + foreach (XmlNode xTerm in xml.SelectNodes("Term")) + { + var t = new TermInfo(); + t.FromXml(xTerm); + ImportedChildTerms.Add(t); + } + } + + public void WriteXml(XmlWriter writer, List vocabulary) + { + writer.WriteStartElement("Term"); + writer.WriteElementString("Name", Name); + writer.WriteElementString("NameLocalizations", NameLocalizations.ToString()); + writer.WriteElementString("Description", Description); + writer.WriteElementString("DescriptionLocalizations", DescriptionLocalizations.ToString()); + foreach (TermInfo t in vocabulary.Where(x => (bool)(x.ParentTermId is not null ? TermId is var arg4 && x.ParentTermId is { } arg5 ? arg5 == arg4 : null : (bool?)false))) + t.WriteXml(writer, vocabulary); + writer.WriteEndElement(); // Term + } + #endregion + + #region Public Methods + public string PermaLink(DotNetNuke.Entities.Portals.PortalSettings portalSettings) + { + return PermaLink(portalSettings.ActiveTab); + } + public string PermaLink(int strParentTabID) + { + var oTabController = new DotNetNuke.Entities.Tabs.TabController(); + var oParentTab = oTabController.GetTab(strParentTabID, DotNetNuke.Entities.Portals.PortalSettings.Current.PortalId, false); + _permaLink = string.Empty; + return PermaLink(oParentTab); + } + + private string _permaLink = ""; + public string PermaLink(DotNetNuke.Entities.Tabs.TabInfo tab) + { + if (string.IsNullOrEmpty(_permaLink)) + { + _permaLink = ApplicationURL(tab.TabID) + "&Term=" + TermId.ToString(); + if (DotNetNuke.Entities.Host.Host.UseFriendlyUrls) + { + _permaLink = FriendlyUrl(tab, _permaLink, GetSafePageName(LocalizedName)); + } + else + { + _permaLink = ResolveUrl(_permaLink); + } + } + return _permaLink; + } + + public TermInfo FlatClone() + { + var res = new TermInfo(); + res.Name = Name; + res.NameLocalizations = NameLocalizations; + res.Name = Description; + res.DescriptionLocalizations = DescriptionLocalizations; + res.Weight = Weight; + return res; + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Terms/TermsController.cs b/Server/Core/Entities/Terms/TermsController.cs new file mode 100644 index 00000000..a72dcbf3 --- /dev/null +++ b/Server/Core/Entities/Terms/TermsController.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Linq; +using System.Text; +using System.Web.UI.WebControls; +using System.Xml; + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Content.Taxonomy; +using Microsoft.VisualBasic; + +namespace DotNetNuke.Modules.Blog.Entities.Terms +{ + public partial class TermsController + { + + public static TermInfo GetTerm(int termId, int moduleId, string locale) + { + return CBO.FillObject(Data.DataProvider.Instance().GetTerm(termId, moduleId, locale)); + } + + public static List GetTermsByPost(int contentItemId, int moduleId, string locale) + { + return CBO.FillCollection(Data.DataProvider.Instance().GetTermsByPost(contentItemId, moduleId, locale)); + } + + public static List GetTermsByModule(int moduleId, string locale) + { + return CBO.FillCollection(Data.DataProvider.Instance().GetTermsByModule(moduleId, locale)); + } + + public static Dictionary GetTermsByVocabulary(int moduleId, int vocabularyId, string locale) + { + return GetTermsByVocabulary(moduleId, vocabularyId, locale, false); + } + + public static Dictionary GetTermsByVocabulary(int moduleId, int vocabularyId, string locale, bool clearCache) + { + string CacheKey = string.Format("BlogVocab-{0}-{1}-{2}", moduleId, vocabularyId, locale); + Dictionary res = (Dictionary)DataCache.GetCache(CacheKey); + if (res is null | clearCache) + { + res = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + CBO.FillDictionary("Name", Data.DataProvider.Instance().GetTermsByVocabulary(moduleId, vocabularyId, locale), res); + DataCache.SetCache(CacheKey, res); + } + return res; + } + + public static Dictionary GetTermsByVocabulary(int moduleId, int vocabularyId) + { + var res = new Dictionary(); + CBO.FillDictionary("TermID", Data.DataProvider.Instance().GetTermsByVocabulary(moduleId, vocabularyId, ""), res); + return res; + } + + public static List GetTermList(int moduleId, string termList, int vocabularyId, bool autoCreate, string locale) + { + if (termList is null) + termList = ""; + string[] termNames = termList.Replace(";", ",").Trim(',').Split(','); + return GetTermList(moduleId, termNames.ToList(), vocabularyId, autoCreate, locale); + } + + public static List GetTermList(int moduleId, List termList, int vocabularyId, bool autoCreate, string locale) + { + var vocab = GetTermsByVocabulary(moduleId, vocabularyId, locale, true); + var res = new List(); + foreach (string termName in termList) + { + string name = termName.Trim(); + TermInfo existantTerm = null; + if (vocab.ContainsKey(name)) + existantTerm = vocab[name]; + if (existantTerm is not null) + { + res.Add(existantTerm); + } + else if (autoCreate & !string.IsNullOrEmpty(name)) + { + int termId = DotNetNuke.Entities.Content.Common.Util.GetTermController().AddTerm(new Term(vocabularyId) { Name = name }); + res.Add(new TermInfo(name) { Description = "", TermId = termId, TotalPosts = 0, Weight = 0 }); + } + } + return res; + } + + #region (De)serialization + public static List FromXml(XmlNode xml) + { + var res = new List(); + if (xml is null) + return res; + foreach (XmlNode xTerm in xml.SelectNodes("Term")) + { + var t = new TermInfo(); + t.FromXml(xTerm); + res.Add(t); + } + return res; + } + + public static void WriteVocabulary(XmlTextWriter writer, string name, List vocabulary) + { + writer.WriteStartElement(name); + foreach (TermInfo t in vocabulary.Where(x => x.ParentTermId is null)) + t.WriteXml(writer, vocabulary); + writer.WriteEndElement(); // Vocabulary + } + + public static void AddTags(int moduleId, List tagList) + { + var allTags = GetTermsByVocabulary(moduleId, 1, ""); + foreach (TermInfo t in tagList) + { + if (!allTags.ContainsKey(t.Name)) + { + var newTerm = new Term(1) { Name = t.Name.Trim(), Description = t.Description }; + newTerm.TermId = DotNetNuke.Entities.Content.Common.Util.GetTermController().AddTerm(newTerm); + foreach (string l in t.NameLocalizations.Locales) + Data.DataProvider.Instance().SetTermLocalization(newTerm.TermId, l, t.NameLocalizations[l], t.DescriptionLocalizations[l]); + } + } + } + + public static void AddVocabulary(int vocabularyId, List vocabulary) + { + foreach (TermInfo t in vocabulary.Where(x => x.ParentTermId is null)) + AddTerm(vocabularyId, vocabulary, 0, t); + } + + private static void AddTerm(int vocabularyId, List vocabulary, int parentId, TermInfo term) + { + var newTerm = new Term(vocabularyId) { Name = term.Name.Trim(), Description = term.Description, ParentTermId = parentId }; + newTerm.TermId = DotNetNuke.Entities.Content.Common.Util.GetTermController().AddTerm(newTerm); + foreach (string l in term.NameLocalizations.Locales) + Data.DataProvider.Instance().SetTermLocalization(newTerm.TermId, l, term.NameLocalizations[l], term.DescriptionLocalizations[l]); + foreach (TermInfo t in vocabulary.Where(x => (bool)(term.TermId is var arg3 && x.ParentTermId is { } arg4 ? arg4 == arg3 : (bool?)null))) + AddTerm(vocabularyId, vocabulary, newTerm.TermId, t); + } + #endregion + + #region UI Functions + public static string GetCategoryTreeAsJson(Dictionary vocabulary) + { + return GetCategoryTreeAsJson(vocabulary, new List()); + } + + public static string GetCategoryTreeAsJson(Dictionary vocabulary, List selectedIds) + { + var childTreeBuilder = new StringBuilder(); + GetCategoryTree(childTreeBuilder, vocabulary, -1, selectedIds); + string res = childTreeBuilder.ToString(); + if (res.Length > 0) + { + res = res.Substring(14); // cut off the first children declaration + } + return res; + } + + private static void GetCategoryTree(StringBuilder @out, Dictionary vocabulary, int parentId, List selectedIds) + { + IEnumerable selection; + if (parentId == -1) + { + selection = vocabulary.Values.Where(t => t.ParentTermId is null); + } + else + { + selection = vocabulary.Values.Where(t => t.ParentTermId is not null && (bool)(t.ParentTermId is { } arg6 ? arg6 == parentId : (bool?)null)); + } + + if (selection.Count() > 0) + { + out.Append(", \"children\": ["); + bool first = true; + foreach (TermInfo cat in selection) + { + if (!first) + out.Append(","); + out.Append("{"); + out.Append(string.Format("\"title\": \"{0}\",", cat.LocalizedName)); + out.Append(string.Format("\"key\": \"{0}\",", cat.TermId)); + out.Append("\"icon\": false,"); + out.Append("\"expand\": true,"); + out.Append("\"isFolder\": true,"); + out.Append(string.Format("\"select\": {0}", Interaction.IIf(selectedIds.Contains(cat.TermId), "true", "false"))); + GetCategoryTree(out, vocabulary, cat.TermId, selectedIds); + out.Append("}"); + first = false; + } + out.Append("]"); + } + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Entities/Terms/TermsController_Service.cs b/Server/Core/Entities/Terms/TermsController_Service.cs new file mode 100644 index 00000000..86e3d5d3 --- /dev/null +++ b/Server/Core/Entities/Terms/TermsController_Service.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Web; +using System.Web.Http; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Web.Api; + +namespace DotNetNuke.Modules.Blog.Entities.Terms +{ + public partial class TermsController : DnnApiController + { + + private const string DisallowedCharacters = @"%?*&;:'\\"; + + #region Service Methods + [HttpGet()] + [DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.View)] + [ActionName("Search")] + public HttpResponseMessage Search() + { + var queryString = HttpUtility.ParseQueryString(Request.RequestUri.Query); + string searchString = queryString["term"]; + int vocab = int.Parse(queryString["vocab"]); + var colTerms = GetTermsByVocabulary(ActiveModule.ModuleID, vocab, System.Threading.Thread.CurrentThread.CurrentCulture.Name).Values.Where(t => t.LocalizedName.IndexOfAny(DisallowedCharacters.ToCharArray()) == -1 & t.LocalizedName.ToLower().Contains(searchString.ToLower())).Select(t => t.LocalizedName); + return Request.CreateResponse(HttpStatusCode.OK, colTerms); + } + + [HttpGet()] + [DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.View)] + [ActionName("VocabularyML")] + public HttpResponseMessage GetVocabularyML(int vocabularyId) + { + var res = new List(); + foreach (TermInfo t in GetTermsByVocabulary(ActiveModule.ModuleID, vocabularyId, "").Values) + res.Add(new TermML() { TermID = t.TermId, DefaultName = t.Name, LocNames = t.NameLocalizations.GetDictionary() }); + return Request.CreateResponse(HttpStatusCode.OK, res); + } + #endregion + + public struct TermML + { + public int TermID; + public string DefaultName; + public Dictionary LocNames; + } + + } +} \ No newline at end of file diff --git a/Server/Core/Integration/BlogModuleController_Portable.cs b/Server/Core/Integration/BlogModuleController_Portable.cs new file mode 100644 index 00000000..a51105ba --- /dev/null +++ b/Server/Core/Integration/BlogModuleController_Portable.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Web.UI.WebControls; +using System.Xml; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Entities.Modules; +using DotNetNuke.Modules.Blog.Common; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Modules.Blog.Entities.Terms; +using Microsoft.VisualBasic; + +namespace DotNetNuke.Modules.Blog.Integration +{ + public partial class BlogModuleController : IPortable + { + + private const string LogFilePattern = "{0}BlogImport_{1}.resources"; + + #region Post Import Logic + public static void CheckupOnImportedFiles(int moduleId) + { + string CacheKey = "Blog_CheckupOnImportedFiles" + moduleId.ToString(); + if (DotNetNuke.Common.Utilities.DataCache.GetCache(CacheKey) is null) + { + string logFile = string.Format(LogFilePattern, DotNetNuke.Common.Globals.HostMapPath, moduleId); + if (System.IO.File.Exists(logFile)) + { + using (var sr = new System.IO.StreamReader(logFile)) + { + string line; + int currentBlog = -1; + do + { + line = sr.ReadLine(); + if (!string.IsNullOrEmpty(line)) + { + string t = line.Substring(0, 1); + int oldId = int.Parse(line.Substring(1, line.IndexOf("-") - 1)); + int newId = int.Parse(line.Substring(line.IndexOf("-") + 1)); + if (t == "M") + { + Data.DataProvider.Instance().UpdateModuleWiring(DotNetNuke.Entities.Portals.PortalSettings.Current.PortalId, oldId, newId); + } + else if (t == "B") + { + var d = new System.IO.DirectoryInfo(string.Format(@"{0}Blog\Files\{1}\", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectoryMapPath, oldId)); + if (d.Exists) + { + d.MoveTo(string.Format(@"{0}Blog\Files\{1}\", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectoryMapPath, newId)); + } + currentBlog = newId; + } + else if (t == "P") + { + var d = new System.IO.DirectoryInfo(string.Format(@"{0}Blog\Files\{1}\{2}\", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectoryMapPath, currentBlog, oldId)); + if (d.Exists) + { + d.MoveTo(string.Format(@"{0}Blog\Files\{1}\{2}\", DotNetNuke.Entities.Portals.PortalSettings.Current.HomeDirectoryMapPath, currentBlog, newId)); + } + if (d.GetFiles("*.*").Count() == 0) + { + } + else + { + var post = PostsController.GetPost(newId, moduleId, ""); + if (post is not null) + { + string postPath = GetPostDirectoryPath(post); + foreach (System.IO.FileInfo f in d.GetFiles("*.*")) + { + string filename = f.Name; + string reg = @"\"([^\&]*)" + filename + @"\""; + string repl = """ + postPath + filename + """; + post.Content = Regex.Replace(post.Content, reg, repl); + foreach (string l in post.ContentLocalizations.Locales) + post.ContentLocalizations[l] = Regex.Replace(post.ContentLocalizations[l], reg, repl); + if (!string.IsNullOrEmpty(post.Summary)) + post.Summary = Regex.Replace(post.Summary, reg, repl); + foreach (string l in post.SummaryLocalizations.Locales) + post.SummaryLocalizations[l] = Regex.Replace(post.SummaryLocalizations[l], reg, repl); + } + PostsController.UpdatePost(post, -1); + } + } + } + } + } + while (!(line is null)); + sr.ReadLine(); + } + System.IO.File.Delete(logFile); + } + DotNetNuke.Common.Utilities.DataCache.SetCache(CacheKey, true); + } + } + #endregion + + #region IPortable Methods + public string ExportModule(int ModuleID) + { + + var strXml = new StringBuilder(); + using (var sw = new System.IO.StringWriter(strXml)) + { + using (var xml = new XmlTextWriter(sw)) + { + xml.WriteStartElement("dnnblog"); + xml.WriteElementString("ModuleId", ModuleID.ToString()); + var tabMods = new ModuleController().GetAllTabsModulesByModuleID(ModuleID); + if (tabMods.Count > 0) + { + var vs = ViewSettings.GetViewSettings(((ModuleInfo)tabMods[0]).TabModuleID); + vs.Serialize(xml); + if (vs.BlogModuleId == -1) + { + var ms = ModuleSettings.GetModuleSettings(ModuleID); + ms.Serialize(xml); + if (ms.VocabularyId > -1) + { + TermsController.WriteVocabulary(xml, "Categories", TermsController.GetTermsByVocabulary(ModuleID, ms.VocabularyId).Values.ToList()); + } + TermsController.WriteVocabulary(xml, "Tags", TermsController.GetTermsByModule(ModuleID, "").Where(t => t.VocabularyId == 1).ToList()); + } + } + foreach (BlogInfo b in BlogsController.GetBlogsByModule(ModuleID, "").Values) + b.WriteXml(xml); + xml.WriteEndElement(); // dnnblog + } + } + return strXml.ToString(); + + } + + public void ImportModule(int ModuleID, string Content, string Version, int UserID) + { + try + { + + var xContent = DotNetNuke.Common.Globals.GetContent(Content, "dnnblog"); + var importReport = new StringBuilder(); + int oldModuleId = -1; + Extensions.ReadValue(ref xContent, "ModuleId", ref oldModuleId); + importReport.AppendFormat("M{0}-{1}" + Constants.vbCrLf, oldModuleId, ModuleID); + + var tabMods = new ModuleController().GetAllTabsModulesByModuleID(ModuleID); + if (tabMods.Count > 0) + { + var vs = ViewSettings.GetViewSettings(((ModuleInfo)tabMods[0]).TabModuleID); + vs.FromXml(xContent.SelectSingleNode("ViewSettings")); + vs.UpdateSettings(); + if (vs.BlogModuleId == -1) + { + var settings = ModuleSettings.GetModuleSettings(ModuleID); + settings.FromXml(xContent.SelectSingleNode("Settings")); + var vocabulary = TermsController.FromXml(xContent.SelectSingleNode("Categories")); + var categories = new Dictionary(); + if (vocabulary.Count > 0) + { + settings.VocabularyId = Integration.CreateNewVocabulary(((ModuleInfo)tabMods[0]).PortalID).VocabularyId; + TermsController.AddVocabulary(settings.VocabularyId, vocabulary); + categories = TermsController.GetTermsByVocabulary(ModuleID, settings.VocabularyId, "", true); + } + settings.UpdateSettings(); + vocabulary = TermsController.FromXml(xContent.SelectSingleNode("Tags")); + if (vocabulary.Count > 0) + { + TermsController.AddTags(ModuleID, vocabulary); + } + var tags = TermsController.GetTermsByVocabulary(ModuleID, 1, ""); + foreach (XmlNode xBlog in xContent.SelectNodes("Blog")) + { + var blog = new BlogInfo(); + blog.FromXml(xBlog); + blog.ModuleID = ModuleID; + blog.OwnerUserId = UserID; + blog.BlogID = BlogsController.AddBlog(ref blog, UserID); + importReport.AppendFormat("B{0}-{1}" + Constants.vbCrLf, blog.ImportedBlogId, blog.BlogID); + foreach (PostInfo p in blog.ImportedPosts) + { + p.BlogID = blog.BlogID; + foreach (string tagName in p.ImportedTags) + { + if (tags.ContainsKey(tagName)) + { + p.Terms.Add(tags[tagName]); + } + } + foreach (string catName in p.ImportedCategories) + { + if (categories.ContainsKey(catName)) + { + p.Terms.Add(categories[catName]); + } + } + PostsController.AddPost(ref p, UserID); + importReport.AppendFormat("P{0}-{1}" + Constants.vbCrLf, p.ImportedPostId, p.ContentItemId); + } + } + } + } + + string importLogFile = string.Format(LogFilePattern, DotNetNuke.Common.Globals.HostMapPath, ModuleID); + WriteToFile(importLogFile, importReport.ToString()); + } + + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + } + #endregion + + #region Private Methods + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Integration/BlogModuleController_Searchable.cs b/Server/Core/Integration/BlogModuleController_Searchable.cs new file mode 100644 index 00000000..5b17fe88 --- /dev/null +++ b/Server/Core/Integration/BlogModuleController_Searchable.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Modules.Blog.Common; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Services.Search.Entities; + +namespace DotNetNuke.Modules.Blog.Integration +{ + public partial class BlogModuleController : ModuleSearchBase + { + + #region Search Implementation + public override IList GetModifiedSearchDocuments(ModuleInfo moduleInfo, DateTime beginDate) + { + + var res = new List(); + var settings = new ViewSettings(moduleInfo.TabModuleID, true); + if (settings.BlogModuleId != -1 & settings.BlogModuleId != moduleInfo.ModuleID) + return res; // bail out if it's a slave module + + // Blogs + foreach (BlogInfo b in BlogsController.GetBlogsByModule(moduleInfo.ModuleID, "").Values) + { + if (b.LastModifiedOnDate.ToUniversalTime() >= beginDate) + { + res.Add(new SearchDocument() + { + AuthorUserId = b.OwnerUserId, + Body = b.Title + " - " + b.Description, + Description = b.Description, + ModifiedTimeUtc = b.LastModifiedOnDate.ToUniversalTime(), + PortalId = moduleInfo.PortalID, + QueryString = "Blog=" + b.BlogID.ToString(), + Title = b.Title, + UniqueKey = "Blog" + b.BlogID.ToString() + }); + } + } + + // Posts + var addedPrimaryPosts = new List(); + foreach (PostInfo p in PostsController.GetChangedPosts(moduleInfo.ModuleID, beginDate)) + { + if (!addedPrimaryPosts.Contains(p.ContentItemId)) + { + res.Add(new SearchDocument() + { + AuthorUserId = p.CreatedByUserID, + Body = p.Summary + " " + HtmlUtils.Clean(p.Content, false), + Description = p.Summary, + ModifiedTimeUtc = p.LastModifiedOnDate.ToUniversalTime(), + PortalId = moduleInfo.PortalID, + QueryString = "Post=" + p.ContentItemId.ToString(), + Title = p.Title, + UniqueKey = "BlogPost" + p.ContentItemId.ToString() + }); + addedPrimaryPosts.Add(p.ContentItemId); + } + if (!string.IsNullOrEmpty(p.AltLocale)) + { + res.Add(new SearchDocument() + { + AuthorUserId = p.CreatedByUserID, + Body = p.AltSummary + " " + HtmlUtils.Clean(p.AltContent, false), + CultureCode = p.AltLocale, + Description = p.AltSummary, + ModifiedTimeUtc = p.LastModifiedOnDate.ToUniversalTime(), + PortalId = moduleInfo.PortalID, + QueryString = "Post=" + p.ContentItemId.ToString(), + Title = p.AltTitle, + UniqueKey = "BlogPost" + p.ContentItemId.ToString() + }); + } + } + return res; + + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Integration/BlogModuleController_Upgradeable.cs b/Server/Core/Integration/BlogModuleController_Upgradeable.cs new file mode 100644 index 00000000..0878d912 --- /dev/null +++ b/Server/Core/Integration/BlogModuleController_Upgradeable.cs @@ -0,0 +1,48 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Entities.Modules; + +namespace DotNetNuke.Modules.Blog.Integration +{ + public partial class BlogModuleController : IUpgradeable + { + + #region IUpgradeable Methods + public string UpgradeModule(string Version) + { + string message = ""; + + switch (Version ?? "") + { + case "05.00.00": + { + NotificationController.AddNotificationTypes(); + break; + } + } + return message; + + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Integration/FileController.cs b/Server/Core/Integration/FileController.cs new file mode 100644 index 00000000..73a58472 --- /dev/null +++ b/Server/Core/Integration/FileController.cs @@ -0,0 +1,90 @@ +using System.Collections; +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2015 +// by DotNetNuke Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +using System.IO; +using System.Web; +using DotNetNuke.Entities.Portals; +using DotNetNuke.Modules.Blog.Entities.Posts; + +namespace DotNetNuke.Modules.Blog.Integration +{ + + public class FileController + { + + #region Shared methods + + public static ArrayList getFileList(string pModulPath, PostInfo pPost) + { + + var myList = new ArrayList(); + if (Directory.Exists(getPostDir(pModulPath, pPost))) + { + string[] fileList = Directory.GetFiles(getPostDir(pModulPath, pPost)); + foreach (string s in fileList) + myList.Add(Path.GetFileName(s)); + } + return myList; + + } + + public static string getPostDir(string pModulPath, PostInfo pPost) + { + string getPostDirRet = default; + + PortalSettings _portalSettings = (PortalSettings)HttpContext.Current.Items["PortalSettings"]; + if (pPost is null) + { + getPostDirRet = HttpContext.Current.Request.MapPath(pModulPath) + @"Files\AnonymousBlogAttachments\"; + } + else + { + getPostDirRet = HttpContext.Current.Request.MapPath(pModulPath) + @"Files\" + pPost.BlogID.ToString() + @"\" + pPost.ContentItemId.ToString() + @"\"; + } + + return getPostDirRet; + + } + + public static string createFileDirectory(string filePath) + { + + string newFolderPath = filePath.Substring(0, filePath.LastIndexOf(@"\")); + if (!Directory.Exists(newFolderPath)) + Directory.CreateDirectory(newFolderPath); + return newFolderPath; + + } + + public static string getVirtualFileName(string pModulPath, string pFullPath) + { + string getVirtualFileNameRet = default; + string strReturn; + strReturn = pFullPath.Replace(HttpContext.Current.Request.MapPath(pModulPath), ""); + strReturn = strReturn.Replace(@"\", "/"); + strReturn = pModulPath + strReturn; + getVirtualFileNameRet = DotNetNuke.Common.Globals.ResolveUrl(strReturn); + return getVirtualFileNameRet; + } + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Integration/Integration.cs b/Server/Core/Integration/Integration.cs new file mode 100644 index 00000000..7c414b4d --- /dev/null +++ b/Server/Core/Integration/Integration.cs @@ -0,0 +1,62 @@ +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Linq; +using DotNetNuke.Entities.Content.Taxonomy; + +namespace DotNetNuke.Modules.Blog.Integration +{ + public class Integration + { + + public const string ContentTypeName = "DNN_Blog_Post"; + public const string JournalBlogTypeName = "blog"; + public const string JournalCommentTypeName = "comment"; + public const string NotificationPublishingTypeName = "DNN_Blog_Post_Publishing"; + public const string NotificationCommentApprovalTypeName = "DNN_Blog_Post_CommentApproval"; + public const string NotificationCommentReportedTypeName = "DNN_Blog_Post_CommentReported"; + public const string NotificationCommentAddedTypeName = "DNN_Blog_Post_CommentAdded"; + + public static Vocabulary CreateNewVocabulary(int portalId) + { + + string name = "Blog Categories"; + var cntScope = new ScopeTypeController(); + var cntVocabulary = new VocabularyController(); + int i = 1; + while (cntVocabulary.GetVocabularies().Where(v => v.Name == name).Count() > 0) + name = "Blog Categories " + i.ToString(); + var objScope = cntScope.GetScopeTypes().Where(s => s.ScopeType == "Portal").SingleOrDefault(); + var objVocab = new Vocabulary(); + objVocab.Name = name; + objVocab.IsSystem = false; + objVocab.Weight = 0; + objVocab.Description = "Automatically generated for blog module."; + objVocab.ScopeId = portalId; + objVocab.ScopeTypeId = objScope.ScopeTypeId; + objVocab.Type = VocabularyType.Hierarchy; + objVocab.VocabularyId = cntVocabulary.AddVocabulary(objVocab); + return objVocab; + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Integration/JournalController.cs b/Server/Core/Integration/JournalController.cs new file mode 100644 index 00000000..4e82e9c5 --- /dev/null +++ b/Server/Core/Integration/JournalController.cs @@ -0,0 +1,208 @@ +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2002-2011 +// by DotNetNuke Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Web; +using DotNetNuke.Entities.Modules; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Posts; +using static DotNetNuke.Modules.Blog.Integration.Integration; +using DotNetNuke.Services.Journal; + +namespace DotNetNuke.Modules.Blog.Integration +{ + + public class JournalController + { + + #region Public Methods + /// + /// Informs the core journal that the user has posted a blog Post. + /// + /// + /// + /// + /// + /// + /// + public static void AddBlogPostToJournal(PostInfo objPost, int portalId, int tabId, int journalUserId, string url) + { + if (journalUserId == -1) + return; + string objectKey = ContentTypeName + "_" + ContentTypeName + "_" + string.Format("{0}:{1}", objPost.BlogID, objPost.ContentItemId); + var ji = Framework.ServiceLocator.Instance.GetJournalItemByKey(portalId, objectKey); + + if (ji is not null) + { + Framework.ServiceLocator.Instance.DeleteJournalItemByKey(portalId, objectKey); + } + + ji = new JournalItem(); + + ji.PortalId = portalId; + ji.ProfileId = journalUserId; + ji.UserId = journalUserId; + ji.ContentItemId = objPost.ContentItemId; + ji.Title = objPost.Title; + ji.ItemData = new ItemData(); + ji.ItemData.Url = url; + ji.Summary = HttpUtility.HtmlDecode(objPost.Summary); + ji.Body = null; + ji.JournalTypeId = GetBlogJournalTypeID(portalId); + ji.ObjectKey = objectKey; + ji.SecuritySet = "E,"; + + var moduleInfo = Framework.ServiceLocator.Instance.GetModule(objPost.ModuleID, tabId, false); + Framework.ServiceLocator.Instance.SaveJournalItem(ji, moduleInfo); + } + + /// + /// Deletes a journal item associated with the specified blog Post. + /// + /// + /// + /// + /// + public static void RemoveBlogPostFromJournal(int blogId, int PostId, int portalId) + { + string objectKey = ContentTypeName + "_" + ContentTypeName + "_" + string.Format("{0}:{1}", blogId, PostId); + Framework.ServiceLocator.Instance.DeleteJournalItemByKey(portalId, objectKey); + } + + /// + /// Informs the core journal that the user has commented on a blog Post. + /// + /// + /// + /// + /// + /// + /// + public static void AddOrUpdateCommentInJournal(BlogInfo objBlog, PostInfo objPost, Entities.Comments.CommentInfo objComment, int portalId, int tabId, int journalUserId, string url) + { + if (journalUserId == -1) + return; + string objectKey = ContentTypeName + "_" + JournalCommentTypeName + "_" + string.Format("{0}:{1}", objPost.ContentItemId.ToString(), objComment.CommentID.ToString()); + var ji = Framework.ServiceLocator.Instance.GetJournalItemByKey(portalId, objectKey); + if (ji is not null) + { + Framework.ServiceLocator.Instance.DeleteJournalItemByKey(portalId, objectKey); + } + + ji = new JournalItem(); + + ji.PortalId = portalId; + ji.ProfileId = journalUserId; + ji.UserId = journalUserId; + ji.ContentItemId = objPost.ContentItemId; + ji.Title = objPost.Title; + ji.ItemData = new ItemData(); + ji.ItemData.Url = url; + ji.Summary = HttpUtility.HtmlDecode(objComment.Comment); + ji.Body = null; + ji.JournalTypeId = GetCommentJournalTypeID(portalId); + ji.ObjectKey = objectKey; + ji.SecuritySet = "E,"; + + var moduleInfo = Framework.ServiceLocator.Instance.GetModule(objPost.ModuleID, tabId, false); + Framework.ServiceLocator.Instance.SaveJournalItem(ji, moduleInfo); + + if (objBlog.OwnerUserId != journalUserId) + { + string title = DotNetNuke.Services.Localization.Localization.GetString("CommentAddedNotify", SharedResourceFileName); + string summary = "" + objPost.Title + ""; + NotificationController.CommentAdded(objComment, objPost, objBlog, portalId, summary, title); + } + + } + + /// + /// Deletes a journal item associated with the specific comment. + /// + /// + /// + /// + public static void RemoveCommentFromJournal(int PostId, int commentId, int portalId) + { + string objectKey = ContentTypeName + "_" + JournalCommentTypeName + "_" + string.Format("{0}:{1}", PostId, commentId); + Framework.ServiceLocator.Instance.DeleteJournalItemByKey(portalId, objectKey); + } + #endregion + + #region Private Methods + /// + /// Returns a journal type associated with blog Posts (using one of the core built in journal types) + /// + /// + /// + /// + private static int GetBlogJournalTypeID(int portalId) + { + IEnumerable colJournalTypes; + colJournalTypes = (from t in Framework.ServiceLocator.Instance.GetJournalTypes(portalId) + where t.JournalType == JournalBlogTypeName + select t); + int journalTypeId; + + if (colJournalTypes.Count() > 0) + { + var journalType = colJournalTypes.Single(); + journalTypeId = journalType.JournalTypeId; + } + else + { + journalTypeId = 7; + } + + return journalTypeId; + } + + /// + /// Returns a journal type associated with commenting (using one of the core built in journal types) + /// + /// + /// + private static int GetCommentJournalTypeID(int portalId) + { + IEnumerable colJournalTypes; + colJournalTypes = (from t in Framework.ServiceLocator.Instance.GetJournalTypes(portalId) + where t.JournalType == JournalCommentTypeName + select t); + int journalTypeId; + + if (colJournalTypes.Count() > 0) + { + var journalType = colJournalTypes.Single(); + journalTypeId = journalType.JournalTypeId; + } + else + { + journalTypeId = 18; + } + + return journalTypeId; + } + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Integration/NotificationController.cs b/Server/Core/Integration/NotificationController.cs new file mode 100644 index 00000000..9d774373 --- /dev/null +++ b/Server/Core/Integration/NotificationController.cs @@ -0,0 +1,344 @@ +using System.Collections.Generic; +using System.Linq; +using System.Web.UI.WebControls; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Entities.Users; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Comments; +using DotNetNuke.Modules.Blog.Entities.Posts; +using static DotNetNuke.Modules.Blog.Integration.Integration; +using DotNetNuke.Modules.Blog.Security.Permissions; +using static DotNetNuke.Modules.Blog.Security.Security; +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2002-2011 +// by DotNetNuke Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Services.Social.Notifications; + +namespace DotNetNuke.Modules.Blog.Integration +{ + + public class NotificationController + { + + #region Integration Methods + /// + /// This method will send a core notification to blog owners when a blog Post is pending publishing approval. + /// + /// + /// + /// + /// + /// + /// + public static void PostPendingApproval(BlogInfo objBlog, PostInfo objPost, int portalId, string summary, string title) + { + var notificationType = Framework.ServiceLocator.Instance.GetNotificationType(NotificationPublishingTypeName); + + var notificationKey = new NotificationKey(ContentTypeName, objBlog.ModuleID, objPost.BlogID, objPost.ContentItemId, -1); + var objNotification = new Notification(); + + objNotification.NotificationTypeID = notificationType.NotificationTypeId; + objNotification.Subject = title; + objNotification.Body = summary; + objNotification.IncludeDismissAction = false; + objNotification.SenderUserID = objPost.CreatedByUserID; + objNotification.Context = notificationKey.ToString(); + + var objOwner = UserController.GetUserById(portalId, objBlog.OwnerUserId); + var colUsers = BlogPermissionsController.GetUsersByBlogPermission(portalId, objBlog.BlogID, (int)BlogPermissionTypes.APPROVE).Values.ToList(); + if (!colUsers.Contains(objOwner)) + colUsers.Add(objOwner); + + Framework.ServiceLocator.Instance.SendNotification(objNotification, portalId, null, colUsers); + + } + + /// + /// Removes any notifications associated w/ a specific blog Post pending approval. + /// + /// + /// + /// + public static void RemovePostPendingNotification(int moduleId, int blogId, int PostId) + { + var notificationType = Framework.ServiceLocator.Instance.GetNotificationType(NotificationPublishingTypeName); + var notificationKey = new NotificationKey(ContentTypeName, moduleId, blogId, PostId, -1); + var objNotify = Framework.ServiceLocator.Instance.GetNotificationByContext(notificationType.NotificationTypeId, notificationKey.ToString()).SingleOrDefault(); + if (objNotify is not null) + { + Framework.ServiceLocator.Instance.DeleteAllNotificationRecipients(objNotify.NotificationID); + } + } + + /// + /// This method will send a core notification to blog owners when a comment is pending approval. + /// + /// + /// + /// + /// + /// + /// + /// + public static void CommentPendingApproval(CommentInfo objComment, BlogInfo objBlog, PostInfo objPost, int portalId, string summary, string subject) + { + var notificationType = Framework.ServiceLocator.Instance.GetNotificationType(NotificationCommentApprovalTypeName); + + var notificationKey = new NotificationKey(ContentTypeName + NotificationCommentApprovalTypeName, objBlog.ModuleID, objBlog.BlogID, objPost.ContentItemId, objComment.CommentID); + var objNotification = new Notification(); + + int recipientId; + if (objBlog.PublishAsOwner) + { + recipientId = objBlog.OwnerUserId; + } + else + { + recipientId = objPost.CreatedByUserID; + } + + objNotification.NotificationTypeID = notificationType.NotificationTypeId; + objNotification.Subject = subject; + objNotification.Body = summary; + objNotification.IncludeDismissAction = true; + objNotification.SenderUserID = objComment.CreatedByUserID; + objNotification.Context = notificationKey.ToString(); + + var objOwner = UserController.GetUserById(portalId, recipientId); + var colUsers = BlogPermissionsController.GetUsersByBlogPermission(portalId, objBlog.BlogID, (int)BlogPermissionTypes.APPROVECOMMENT); + if (!colUsers.ContainsKey(objOwner.Username)) + colUsers.Add(objOwner.Username, objOwner); + AddNotifications(portalId, colUsers.Values.ToList(), objNotification); + + } + + public static void ReportComment(CommentInfo objComment, BlogInfo objBlog, PostInfo objPost, int portalId, string summary, string subject) + { + var notificationType = Framework.ServiceLocator.Instance.GetNotificationType(NotificationCommentReportedTypeName); + + var notificationKey = new NotificationKey(ContentTypeName + NotificationCommentReportedTypeName, objBlog.ModuleID, objBlog.BlogID, objPost.ContentItemId, objComment.CommentID); + var objNotification = new Notification(); + + int recipientId; + if (objBlog.PublishAsOwner) + { + recipientId = objBlog.OwnerUserId; + } + else + { + recipientId = objPost.CreatedByUserID; + } + + objNotification.NotificationTypeID = notificationType.NotificationTypeId; + objNotification.Subject = subject; + objNotification.Body = summary; + objNotification.IncludeDismissAction = true; + objNotification.SenderUserID = objComment.CreatedByUserID; + objNotification.Context = notificationKey.ToString(); + + var objOwner = UserController.GetUserById(portalId, recipientId); + var colUsers = BlogPermissionsController.GetUsersByBlogPermission(portalId, objBlog.BlogID, (int)BlogPermissionTypes.APPROVECOMMENT); + if (!colUsers.ContainsKey(objOwner.Username)) + colUsers.Add(objOwner.Username, objOwner); + AddNotifications(portalId, colUsers.Values.ToList(), objNotification); + + } + /// + /// Removes any notifications associated w/ a specific blog comment pending approval. + /// + /// + /// + /// + public static void RemoveCommentPendingNotification(int moduleId, int blogId, int PostId, int commentId) + { + var notificationType = Framework.ServiceLocator.Instance.GetNotificationType(NotificationCommentApprovalTypeName); + var notificationKey = new NotificationKey(ContentTypeName + NotificationCommentApprovalTypeName, moduleId, blogId, PostId, commentId); + var objNotify = Framework.ServiceLocator.Instance.GetNotificationByContext(notificationType.NotificationTypeId, notificationKey.ToString()).SingleOrDefault(); + if (objNotify is not null) + { + Framework.ServiceLocator.Instance.DeleteAllNotificationRecipients(objNotify.NotificationID); + } + } + + /// + /// This method will send a core notification to blog owners when a comment is added (they can only dismiss this notification) + /// + /// + /// + /// + /// + /// + /// + /// + public static void CommentAdded(CommentInfo objComment, PostInfo objPost, BlogInfo objBlog, int portalId, string summary, string subject) + { + var notificationType = Framework.ServiceLocator.Instance.GetNotificationType(NotificationCommentAddedTypeName); + + var notificationKey = new NotificationKey(ContentTypeName + NotificationCommentAddedTypeName, objBlog.ModuleID, objBlog.BlogID, objPost.ContentItemId, objComment.CommentID); + var objNotification = new Notification(); + + int recipientId; + if (objBlog.PublishAsOwner) + { + recipientId = objBlog.OwnerUserId; + } + else + { + recipientId = objPost.CreatedByUserID; + } + + objNotification.NotificationTypeID = notificationType.NotificationTypeId; + objNotification.Subject = subject; + objNotification.Body = summary; + objNotification.IncludeDismissAction = true; + objNotification.SenderUserID = objComment.CreatedByUserID; + objNotification.Context = notificationKey.ToString(); + objNotification.SendToast = true; + + var objOwner = UserController.GetUserById(portalId, recipientId); + var colUsers = new List(); + + colUsers.Add(objOwner); + + AddNotifications(portalId, colUsers, objNotification); + + } + #endregion + + #region Private Methods + private static void AddNotifications(int portalId, List colUsers, Notification objNotification) + { + if (colUsers.Count > Framework.ServiceLocator.Instance.RecipientLimit(portalId)) + { + foreach (UserInfo u in colUsers) + { + var list = new List(); + list.Add(u); + Framework.ServiceLocator.Instance.SendNotification(objNotification, portalId, null, list); + } + } + else + { + Framework.ServiceLocator.Instance.SendNotification(objNotification, portalId, null, colUsers); + } + } + #endregion + + #region Install Methods + /// + /// This will create a notification type associated w/ the module and also handle the actions that must be associated with it. + /// + /// This should only ever run once, during 5.0.0 install (via IUpgradeable) + internal static void AddNotificationTypes() + { + var actions = new List(); + int deskModuleId = DesktopModuleController.GetDesktopModuleByFriendlyName("Blog").DesktopModuleID; + + var objNotificationType = new NotificationType(); + objNotificationType.Name = NotificationPublishingTypeName; + objNotificationType.Description = "Blog module post approval."; + objNotificationType.DesktopModuleId = deskModuleId; + + if (Framework.ServiceLocator.Instance.GetNotificationType(objNotificationType.Name) is null) + { + var objAction = new NotificationTypeAction(); + objAction.NameResourceKey = "ApprovePost"; + objAction.DescriptionResourceKey = "ApprovePost_Desc"; + objAction.APICall = "DesktopModules/Blog/API/NotificationService/ApprovePost"; + objAction.Order = 1; + actions.Add(objAction); + + objAction = new NotificationTypeAction(); + objAction.NameResourceKey = "DeletePost"; + objAction.DescriptionResourceKey = "DeletePost_Desc"; + objAction.APICall = "DesktopModules/Blog/API/NotificationService/DeletePost"; + objAction.ConfirmResourceKey = "DeleteItem"; + objAction.Order = 3; + actions.Add(objAction); + + Framework.ServiceLocator.Instance.CreateNotificationType(objNotificationType); + Framework.ServiceLocator.Instance.SetNotificationTypeActions(actions, objNotificationType.NotificationTypeId); + } + + objNotificationType = new NotificationType(); + objNotificationType.Name = NotificationCommentApprovalTypeName; + objNotificationType.Description = "Blog module comment approval."; + objNotificationType.DesktopModuleId = deskModuleId; + + if (Framework.ServiceLocator.Instance.GetNotificationType(objNotificationType.Name) is null) + { + actions.Clear(); + + var objAction = new NotificationTypeAction(); + objAction.NameResourceKey = "ApproveComment"; + objAction.DescriptionResourceKey = "ApproveComment_Desc"; + objAction.APICall = "DesktopModules/Blog/API/NotificationService/ApproveComment"; + objAction.Order = 1; + actions.Add(objAction); + + objAction = new NotificationTypeAction(); + objAction.NameResourceKey = "DeleteComment"; + objAction.DescriptionResourceKey = "DeleteComment_Desc"; + objAction.APICall = "DesktopModules/Blog/API/NotificationService/DeleteComment"; + objAction.ConfirmResourceKey = "DeleteItem"; + objAction.Order = 3; + actions.Add(objAction); + + Framework.ServiceLocator.Instance.CreateNotificationType(objNotificationType); + Framework.ServiceLocator.Instance.SetNotificationTypeActions(actions, objNotificationType.NotificationTypeId); + } + + objNotificationType = new NotificationType(); + objNotificationType.Name = NotificationCommentReportedTypeName; + objNotificationType.Description = "Blog module comment reported."; + objNotificationType.DesktopModuleId = deskModuleId; + + if (Framework.ServiceLocator.Instance.GetNotificationType(objNotificationType.Name) is null) + { + actions.Clear(); + + var objAction = new NotificationTypeAction(); + objAction.NameResourceKey = "DeleteComment"; + objAction.DescriptionResourceKey = "DeleteComment_Desc"; + objAction.APICall = "DesktopModules/Blog/API/Comments/Delete"; + objAction.ConfirmResourceKey = "DeleteItem"; + objAction.Order = 1; + actions.Add(objAction); + + Framework.ServiceLocator.Instance.CreateNotificationType(objNotificationType); + Framework.ServiceLocator.Instance.SetNotificationTypeActions(actions, objNotificationType.NotificationTypeId); + } + + objNotificationType = new NotificationType(); + objNotificationType.Name = NotificationCommentAddedTypeName; + objNotificationType.Description = "Blog module and comments being added."; + objNotificationType.DesktopModuleId = deskModuleId; + + if (Framework.ServiceLocator.Instance.GetNotificationType(objNotificationType.Name) is null) + { + Framework.ServiceLocator.Instance.CreateNotificationType(objNotificationType); + } + } + + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Integration/NotificationKey.cs b/Server/Core/Integration/NotificationKey.cs new file mode 100644 index 00000000..a9eef7d6 --- /dev/null +++ b/Server/Core/Integration/NotificationKey.cs @@ -0,0 +1,60 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +namespace DotNetNuke.Modules.Blog.Integration +{ + public class NotificationKey + { + + public string ID = ""; + public int ModuleId = -1; + public int BlogId = -1; + public int ContentItemId = -1; + public int CommentId = -1; + + public NotificationKey(string key) + { + string[] keyParts = key.Split(':'); + if (keyParts.Length < 5) + return; + ID = keyParts[0]; + ModuleId = int.Parse(keyParts[1]); + BlogId = int.Parse(keyParts[2]); + ContentItemId = int.Parse(keyParts[3]); + CommentId = int.Parse(keyParts[4]); + } + + public NotificationKey(string id, int moduleId, int blogId, int contentItemId, int commentId) + { + ID = id; + ModuleId = moduleId; + BlogId = blogId; + ContentItemId = contentItemId; + CommentId = commentId; + } + + public new string ToString() + { + return string.Format("{0}:{1}:{2}:{3}:{4}", ID, ModuleId, BlogId, ContentItemId, CommentId); + } + + } +} \ No newline at end of file diff --git a/Server/Core/Integration/Services/NotificationServiceController.cs b/Server/Core/Integration/Services/NotificationServiceController.cs new file mode 100644 index 00000000..247ae82d --- /dev/null +++ b/Server/Core/Integration/Services/NotificationServiceController.cs @@ -0,0 +1,146 @@ +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2002-2011 +// by DotNetNuke Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +using System.Net; +using System.Net.Http; +using System.Web.Http; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Comments; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Modules.Blog.Services; +using DotNetNuke.Services.Social.Notifications; +using DotNetNuke.Web.Api; + +namespace DotNetNuke.Modules.Blog.Integration.Services +{ + + public class NotificationServiceController : DnnApiController + { + + public class NotificationDTO + { + public int NotificationId { get; set; } + } + + #region Private Members + + private int BlogModuleId { get; set; } = -1; + private int BlogId { get; set; } = -1; + private BlogInfo Blog { get; set; } = null; + private int ContentItemId { get; set; } = -1; + private PostInfo Post { get; set; } = null; + private int CommentId { get; set; } = -1; + private CommentInfo Comment { get; set; } = null; + + #endregion + + #region Service Methods + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.ApprovePost)] + [ValidateAntiForgeryToken()] + public HttpResponseMessage ApprovePost(NotificationDTO postData) + { + var notify = Framework.ServiceLocator.Instance.GetNotification(postData.NotificationId); + ParsePublishKey(notify.Context); + if (Blog is null | Post is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + Post.Published = true; + PostsController.UpdatePost(Post, UserInfo.UserID); + Framework.ServiceLocator.Instance.DeleteNotification(postData.NotificationId); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.EditPost)] + [ValidateAntiForgeryToken()] + public HttpResponseMessage DeletePost(NotificationDTO postData) + { + var notify = Framework.ServiceLocator.Instance.GetNotification(postData.NotificationId); + ParsePublishKey(notify.Context); + if (Blog is null | Post is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + PostsController.DeletePost(ContentItemId); + Framework.ServiceLocator.Instance.DeleteNotification(postData.NotificationId); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.ApproveComment)] + [ValidateAntiForgeryToken()] + public HttpResponseMessage ApproveComment(NotificationDTO postData) + { + var notify = Framework.ServiceLocator.Instance.GetNotification(postData.NotificationId); + ParseCommentKey(notify.Context); + if (Blog is null | Post is null | Comment is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + CommentsController.ApproveComment(BlogModuleId, BlogId, Comment); + Framework.ServiceLocator.Instance.DeleteNotification(postData.NotificationId); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + + [HttpPost()] + [BlogAuthorize(SecurityAccessLevel.ApproveComment)] + [ValidateAntiForgeryToken()] + public HttpResponseMessage DeleteComment(NotificationDTO postData) + { + var notify = Framework.ServiceLocator.Instance.GetNotification(postData.NotificationId); + ParseCommentKey(notify.Context); + if (Blog is null | Post is null | Comment is null) + { + return Request.CreateResponse(HttpStatusCode.BadRequest, new { Result = "error" }); + } + CommentsController.DeleteComment(BlogModuleId, BlogId, Comment); + Framework.ServiceLocator.Instance.DeleteNotification(postData.NotificationId); + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + } + #endregion + + #region Private Methods + private void ParsePublishKey(string key) + { + var nKey = new NotificationKey(key); + BlogModuleId = nKey.ModuleId; + BlogId = nKey.BlogId; + ContentItemId = nKey.ContentItemId; + Blog = BlogsController.GetBlog(BlogId, UserInfo.UserID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + Post = PostsController.GetPost(ContentItemId, BlogModuleId, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + } + + private void ParseCommentKey(string key) + { + var nKey = new NotificationKey(key); + BlogModuleId = nKey.ModuleId; + BlogId = nKey.BlogId; + ContentItemId = nKey.ContentItemId; + CommentId = nKey.CommentId; + Blog = BlogsController.GetBlog(BlogId, UserInfo.UserID, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + Post = PostsController.GetPost(ContentItemId, BlogModuleId, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + Comment = CommentsController.GetComment(CommentId, UserInfo.UserID); + } + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Integration/SiteMapProvider.cs b/Server/Core/Integration/SiteMapProvider.cs new file mode 100644 index 00000000..e0f6acbd --- /dev/null +++ b/Server/Core/Integration/SiteMapProvider.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Security.Permissions; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Services.Sitemap; + +namespace DotNetNuke.Modules.Blog.Integration +{ + public class BlogSiteMapProvider : SitemapProvider + { + + public override List GetUrls(int portalId, DotNetNuke.Entities.Portals.PortalSettings ps, string version) + { + + var SitemapUrls = new List(); + var moduleTabs = new Dictionary>(); + foreach (BlogInfo blog in BlogsController.GetBlogsByPortal(portalId, -1, "").Values) + { + if (!moduleTabs.ContainsKey(blog.ModuleID)) + { + var tabs = new List(); + foreach (DotNetNuke.Entities.Tabs.TabInfo t in new DotNetNuke.Entities.Tabs.TabController().GetTabsByModuleID(blog.ModuleID).Values) + { + foreach (TabPermissionInfo tp in t.TabPermissions) + { + if ((tp.RoleName ?? "") == DotNetNuke.Common.Globals.glbRoleAllUsersName) + { + tabs.Add(t); + break; + } + } + } + moduleTabs.Add(blog.ModuleID, tabs); + } + int totalRecs = 0; + foreach (PostInfo p in PostsController.GetPostsByBlog(blog.ModuleID, blog.BlogID, System.Threading.Thread.CurrentThread.CurrentCulture.Name, -1, -1, 0, null, ref totalRecs).Values) + { + if (p.Published) + { + foreach (DotNetNuke.Entities.Tabs.TabInfo t in moduleTabs[blog.ModuleID]) + { + var smu = new SitemapUrl() { ChangeFrequency = SitemapChangeFrequency.Daily, LastModified = p.LastModifiedOnDate, Priority = 0.5f, Url = p.PermaLink(t) }; + SitemapUrls.Add(smu); + } + } + } + } + return SitemapUrls; + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Rss/BlogRssFeed.cs b/Server/Core/Rss/BlogRssFeed.cs new file mode 100644 index 00000000..2c3f0e00 --- /dev/null +++ b/Server/Core/Rss/BlogRssFeed.cs @@ -0,0 +1,455 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Xml; +using static DotNetNuke.Common.Globals; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Modules.Blog.Common; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Modules.Blog.Entities.Terms; + +namespace DotNetNuke.Modules.Blog.Rss +{ + public class BlogRssFeed + { + + #region Constants + private const string nsBlogPre = "blog"; + private const string nsBlogFull = "http://dnn-connect.org/blog/"; + private const string nsSlashPre = "slash"; + private const string nsSlashFull = "http://purl.org/rss/1.0/modules/slash/"; + private const string nsAtomPre = "atom"; + private const string nsAtomFull = "http://www.w3.org/2005/Atom"; + private const string nsMediaPre = "media"; + private const string nsMediaFull = "http://search.yahoo.com/mrss/"; + private const string nsDublinPre = "dc"; + private const string nsDublinFull = "http://purl.org/dc/elements/1.1/"; + private const string nsContentPre = "content"; + private const string nsContentFull = "http://purl.org/rss/1.0/modules/content/"; + private const string nsOpenSearchPre = "os"; + private const string nsOpenSearchFull = "http://opensearch.a9.com/spec/opensearchrss/1.0/"; + #endregion + + #region Properties + public ModuleSettings Settings { get; set; } = null; + public DotNetNuke.Entities.Portals.PortalSettings PortalSettings { get; set; } = null; + public IEnumerable Posts { get; set; } = null; + public string CacheFile { get; set; } = ""; + public bool IsCached { get; set; } = false; + public string ImageHandlerUrl { get; set; } = ""; + public int TotalRecords { get; set; } = -1; + + // Requested Properties + public int TermId { get; set; } = -1; + public int BlogId { get; set; } = -1; + public int RecordsToSend { get; set; } = 20; + public string Search { get; set; } = ""; + public bool SearchTitle { get; set; } = true; + public bool SearchContents { get; set; } = false; + public int ImageWidth { get; set; } = 144; + public int ImageHeight { get; set; } = 96; + public bool IncludeContents { get; set; } = false; + + // Feed Properties + public bool IsSearchFeed { get; set; } = false; + public BlogInfo Blog { get; set; } = null; + public TermInfo Term { get; set; } = null; + public string Title { get; set; } = ""; + public string Description { get; set; } = ""; + public string Link { get; set; } = ""; + public string FeedEmail { get; set; } = ""; + public string Language { get; set; } = ""; + public string Locale { get; set; } = System.Threading.Thread.CurrentThread.CurrentCulture.Name; + public string Copyright { get; set; } = ""; + public string URL { get; set; } = ""; + #endregion + + #region Constructors + public BlogRssFeed(int moduleId, NameValueCollection reqParams) + { + + // Initialize Settings + Settings = ModuleSettings.GetModuleSettings(moduleId); + PortalSettings = DotNetNuke.Entities.Portals.PortalSettings.Current; + RecordsToSend = Settings.RssDefaultNrItems; + ImageWidth = Settings.RssImageWidth; + ImageHeight = Settings.RssImageHeight; + string port = string.Empty; + if (HttpContext.Current.Request.Url.Port != 80) + { + port = ":" + HttpContext.Current.Request.Url.Port.ToString(); + } + ImageHandlerUrl = string.Format("{0}://{1}{2}{3}", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Host, port, VirtualPathUtility.ToAbsolute(glbImageHandlerPath)); + + // Read Request Values + int argVariable = BlogId; + Extensions.ReadValue(ref reqParams, "blog", ref argVariable); + BlogId = argVariable; + int argVariable1 = BlogId; + Extensions.ReadValue(ref reqParams, "blogid", ref argVariable1); + BlogId = argVariable1; + int argVariable2 = TermId; + Extensions.ReadValue(ref reqParams, "term", ref argVariable2); + TermId = argVariable2; + int argVariable3 = TermId; + Extensions.ReadValue(ref reqParams, "termid", ref argVariable3); + TermId = argVariable3; + if (Settings.RssMaxNrItems > 0) + { + int argVariable4 = RecordsToSend; + Extensions.ReadValue(ref reqParams, "recs", ref argVariable4); + RecordsToSend = argVariable4; + if (RecordsToSend > Settings.RssMaxNrItems) + RecordsToSend = Settings.RssMaxNrItems; + } + if (Settings.RssImageSizeAllowOverride) + { + int argVariable5 = ImageWidth; + Extensions.ReadValue(ref reqParams, "w", ref argVariable5); + ImageWidth = argVariable5; + int argVariable6 = ImageHeight; + Extensions.ReadValue(ref reqParams, "h", ref argVariable6); + ImageHeight = argVariable6; + } + if (Settings.RssAllowContentInFeed) + { + bool argVariable7 = IncludeContents; + Extensions.ReadValue(ref reqParams, "body", ref argVariable7); + IncludeContents = argVariable7; + } + string argVariable8 = Search; + Extensions.ReadValue(ref reqParams, "search", ref argVariable8); + Search = argVariable8; + bool argVariable9 = SearchTitle; + Extensions.ReadValue(ref reqParams, "t", ref argVariable9); + SearchTitle = argVariable9; + bool argVariable10 = SearchContents; + Extensions.ReadValue(ref reqParams, "c", ref argVariable10); + SearchContents = argVariable10; + string argVariable11 = Language; + Extensions.ReadValue(ref reqParams, "language", ref argVariable11); + Language = argVariable11; + if (!string.IsNullOrEmpty(Language)) + Locale = Language; + + // Start Filling In Feed Properties + if (!string.IsNullOrEmpty(Search)) + IsSearchFeed = true; + if (BlogId > -1) + Blog = BlogsController.GetBlog(BlogId, -1, System.Threading.Thread.CurrentThread.CurrentCulture.Name); + if (TermId > -1) + Term = TermsController.GetTerm(TermId, moduleId, Locale); + if (Blog is null) + { + var m = new ModuleController().GetModule(moduleId); + if (m is not null) + { + Title = m.ModuleTitle; + } + FeedEmail = Settings.RssEmail; + Copyright = Settings.RssDefaultCopyright; + } + else + { + Title = Blog.Title; + Description = Blog.Description; + FeedEmail = Blog.Email; + Copyright = Regex.Replace(Blog.Copyright, @"(?i)\[year\](?-i)", DateTime.Now.ToString("yyyy")); + } + if (Term is not null) + { + Title += " - " + Term.LocalizedName; + } + if (IsSearchFeed) + { + Title = "DNN Blog Search " + Title; + Description += string.Format(" - Searching '{0}'", Search); + } + Link = ApplicationURL(); + if (Blog is not null) + Link += string.Format("&blog={0}", BlogId); + if (Term is not null) + Link += string.Format("&term={0}", TermId); + if (RecordsToSend != Settings.RssDefaultNrItems) + Link += string.Format("&recs={0}", RecordsToSend); + if (ImageWidth != Settings.RssImageWidth) + Link += string.Format("&w={0}", ImageWidth); + if (ImageHeight != Settings.RssImageHeight) + Link += string.Format("&h={0}", ImageHeight); + if (IncludeContents) + Link += "&body=true"; + if (!string.IsNullOrEmpty(Language)) + Link += string.Format("&language={0}", Language); + if (!string.IsNullOrEmpty(Locale)) + Link += string.Format("&locale={0}", Locale); + if (IsSearchFeed) + Link += string.Format("&search={0}&t={1}&c={2}", HttpUtility.UrlEncode(Search), SearchTitle, SearchContents); + CacheFile = Link.Substring(Link.IndexOf('?') + 1).Replace("&", "+").Replace("=", "-"); + CacheFile = string.Format(@"{0}\Blog\RssCache\{1}.resources", PortalSettings.HomeDirectoryMapPath.TrimEnd('\\'), CacheFile); + URL = HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority; + if (DotNetNuke.Entities.Host.Host.UseFriendlyUrls) + { + Link = FriendlyUrl(PortalSettings.ActiveTab, Link, GetSafePageName(Title)); + } + else + { + Link = URL + ResolveUrl(Link); + } + + // Check Cache + if (System.IO.File.Exists(CacheFile)) + { + var f = new System.IO.FileInfo(CacheFile); + if (f.LastWriteTime.AddMinutes(Settings.RssTtl) > DateTime.Now) + IsCached = true; + } + else + { + string pth = System.IO.Path.GetDirectoryName(CacheFile); + if (!System.IO.Directory.Exists(pth)) + System.IO.Directory.CreateDirectory(pth); + } + + if (!IsCached) + { + // Load Posts + if (IsSearchFeed) + { + if (Term is not null) + { + Dictionary localSearchPostsByTerm() { int argtotalRecords = TotalRecords; var ret = PostsController.SearchPostsByTerm(moduleId, BlogId, Locale, TermId, Search, SearchTitle, SearchContents, 1, Language, DateTime.Now.ToUniversalTime(), -1, 0, RecordsToSend, "PUBLISHEDONDATE DESC", ref argtotalRecords, -1, false); TotalRecords = argtotalRecords; return ret; } + + Posts = localSearchPostsByTerm().Values; + } + else + { + Dictionary localSearchPosts() { int argtotalRecords1 = TotalRecords; var ret = PostsController.SearchPosts(moduleId, BlogId, Locale, Search, SearchTitle, SearchContents, 1, Language, DateTime.Now.ToUniversalTime(), -1, 0, RecordsToSend, "PUBLISHEDONDATE DESC", ref argtotalRecords1, -1, false); TotalRecords = argtotalRecords1; return ret; } + + Posts = localSearchPosts().Values; + } + } + else if (Term is not null) + { + Dictionary localGetPostsByTerm() { int argtotalRecords2 = TotalRecords; var ret = PostsController.GetPostsByTerm(moduleId, BlogId, Locale, TermId, 1, Language, DateTime.Now.ToUniversalTime(), -1, 0, RecordsToSend, "PUBLISHEDONDATE DESC", ref argtotalRecords2, -1, false); TotalRecords = argtotalRecords2; return ret; } + + Posts = localGetPostsByTerm().Values; + } + else + { + Dictionary localGetPosts() { int argtotalRecords3 = TotalRecords; var ret = PostsController.GetPosts(moduleId, BlogId, Locale, 1, Language, DateTime.Now.ToUniversalTime(), -1, false, 0, RecordsToSend, "PUBLISHEDONDATE DESC", ref argtotalRecords3, -1, false); TotalRecords = argtotalRecords3; return ret; } + + Posts = localGetPosts().Values; + } + WriteRss(CacheFile); + } + } + #endregion + + #region Public Methods + public string WriteRssToString() + { + var sb = new StringBuilder(); + WriteRss(ref sb); + return sb.ToString(); + } + + public void WriteRss(ref System.IO.Stream output) + { + using (var xtw = new XmlTextWriter(output, Encoding.UTF8)) + { + var argoutput = xtw; + WriteRss(ref argoutput); + xtw.Flush(); + } + } + + public void WriteRss(string fileName) + { + using (var fs = new System.IO.FileStream(fileName, System.IO.FileMode.Create, System.IO.FileAccess.Write)) + { + using (var xtw = new XmlTextWriter(fs, Encoding.UTF8)) + { + var argoutput = xtw; + WriteRss(ref argoutput); + xtw.Flush(); + } + } + } + + public void WriteRss(ref StringBuilder output) + { + using (var sw = new StringWriterWithEncoding(output, Encoding.UTF8)) + { + using (var xtw = new XmlTextWriter(sw)) + { + var argoutput = xtw; + WriteRss(ref argoutput); + xtw.Flush(); + } + sw.Flush(); + } + } + + public void WriteRss(ref XmlTextWriter output) + { + + output.Formatting = Formatting.Indented; + output.WriteStartDocument(); + output.WriteStartElement("rss"); + output.WriteAttributeString("version", "2.0"); + output.WriteAttributeString("xmlns", nsBlogPre, null, nsBlogFull); + // output.WriteAttributeString("xmlns", nsSlashPre, Nothing, nsSlashFull) + output.WriteAttributeString("xmlns", nsAtomPre, null, nsAtomFull); + output.WriteAttributeString("xmlns", nsMediaPre, null, nsMediaFull); + if (IsSearchFeed) + output.WriteAttributeString("xmlns", nsOpenSearchPre, null, nsOpenSearchFull); + if (IncludeContents) + output.WriteAttributeString("xmlns", nsContentPre, null, nsContentFull); + output.WriteStartElement("channel"); + + // Write the channel header block + output.WriteElementString("title", Title); + output.WriteElementString("link", Link); + output.WriteElementString("description", Description); + // optional elements + if (!string.IsNullOrEmpty(Language)) + output.WriteElementString("language", Language); + if (!string.IsNullOrEmpty(Copyright)) + output.WriteElementString("copyright", Copyright); + if (!string.IsNullOrEmpty(FeedEmail)) + output.WriteElementString("managingEditor", FeedEmail); + output.WriteElementString("pubDate", DateTime.Now.ToString("r")); + output.WriteElementString("lastBuildDate", DateTime.Now.ToString("r")); + if (Term is not null) + { + output.WriteElementString("category", Term.LocalizedName); + } + output.WriteElementString("generator", "DotNetNuke Blog RSS Generator Version " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()); + output.WriteElementString("ttl", Settings.RssTtl.ToString()); + if (Blog is not null && Blog.IncludeImagesInFeed & !string.IsNullOrEmpty(Blog.Image)) + { + output.WriteStartElement("image"); + output.WriteElementString("url", ImageHandlerUrl + string.Format("?TabId={0}&ModuleId={1}&Blog={2}&w={4}&h={5}&c=1&key={3}", PortalSettings.ActiveTab.TabID, Settings.ModuleId, BlogId, Blog.Image, ImageWidth, ImageHeight)); + output.WriteElementString("title", Title); + output.WriteElementString("link", Link); + output.WriteElementString("width", ImageWidth.ToString()); // default 88 max 144 + output.WriteElementString("height", ImageHeight.ToString()); // default 31 max 400 + output.WriteEndElement(); // image + } + // extended elements + output.WriteStartElement(nsAtomPre, "link", nsAtomFull); + output.WriteAttributeString("href", HttpContext.Current.Request.Url.AbsoluteUri); + output.WriteAttributeString("rel", "self"); + output.WriteAttributeString("type", "application/rss+xml"); + output.WriteEndElement(); // atom:link + if (IsSearchFeed) + { + output.WriteElementString(nsOpenSearchPre, "totalResults", nsOpenSearchFull, TotalRecords.ToString()); + output.WriteElementString(nsOpenSearchPre, "startIndex", nsOpenSearchFull, "0"); + output.WriteElementString(nsOpenSearchPre, "itemsPerPage", nsOpenSearchFull, RecordsToSend.ToString()); + } + + foreach (PostInfo e in Posts) + WriteItem(ref output, e); + + output.WriteEndElement(); // channel + output.WriteEndElement(); // rss + output.Flush(); + + } + #endregion + + #region Private Methods + private void WriteItem(ref XmlTextWriter writer, PostInfo item) + { + + writer.WriteStartElement("item"); + + // core data + writer.WriteElementString("title", item.LocalizedTitle); + + if (DotNetNuke.Entities.Host.Host.UseFriendlyUrls) + { + writer.WriteElementString("link", item.PermaLink()); + } + else + { + writer.WriteElementString("link", URL + item.PermaLink()); + } + + writer.WriteElementString("description", HttpUtility.HtmlDecode(item.LocalizedSummary)); + // optional elements + if (item.Blog.IncludeAuthorInFeed) + { + writer.WriteElementString("author", string.Format("{0} ({1})", item.Email, item.DisplayName)); + writer.WriteElementString(nsBlogPre, "author", nsBlogFull, item.DisplayName); + } + foreach (TermInfo t in TermsController.GetTermsByPost(item.ContentItemId, Settings.ModuleId, Locale)) + writer.WriteElementString("category", t.LocalizedName); + + // guid needs to have the isPermaLink=false attribute for some rss readers + writer.WriteStartElement("guid"); + writer.WriteAttributeString("isPermaLink", "true"); + + if (DotNetNuke.Entities.Host.Host.UseFriendlyUrls) + { + writer.WriteRaw(string.Format("{0}", item.PermaLink())); + } + else + { + writer.WriteRaw(string.Format("{0}", URL + HttpUtility.HtmlEncode(item.PermaLink()))); + } + + writer.WriteEndElement(); + + writer.WriteElementString("pubDate", item.PublishedOnDate.ToString("r")); + // extensions + if (item.Blog.IncludeImagesInFeed & !string.IsNullOrEmpty(item.Image)) + { + writer.WriteStartElement(nsMediaPre, "thumbnail", nsMediaFull); + writer.WriteAttributeString("width", ImageWidth.ToString()); + writer.WriteAttributeString("height", ImageHeight.ToString()); + writer.WriteAttributeString("url", ImageHandlerUrl + string.Format("?TabId={0}&ModuleId={1}&Blog={2}&Post={3}&w={5}&h={6}&c=1&key={4}", PortalSettings.ActiveTab.TabID, Settings.ModuleId, item.BlogID, item.ContentItemId, item.Image, ImageWidth, ImageHeight)); + writer.WriteEndElement(); // thumbnail + } + if (IncludeContents) + { + writer.WriteStartElement(nsContentPre, "encoded", nsContentFull); + writer.WriteCData(HttpUtility.HtmlDecode(item.Content)); + writer.WriteEndElement(); // content:encoded + } + // Blog Extensions + writer.WriteElementString(nsBlogPre, "publishedon", nsBlogFull, item.PublishedOnDate.ToString("u")); + + writer.WriteEndElement(); // item + + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Rss/StringWriterWithEncoding.cs b/Server/Core/Rss/StringWriterWithEncoding.cs new file mode 100644 index 00000000..86607528 --- /dev/null +++ b/Server/Core/Rss/StringWriterWithEncoding.cs @@ -0,0 +1,52 @@ +using System.Text; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +namespace DotNetNuke.Modules.Blog.Rss +{ + + /// + /// Support class to allow encoded writing + /// + /// + /// + /// [pdonker] 12/14/2009 created + /// + public class StringWriterWithEncoding : System.IO.StringWriter + { + + private Encoding _encoding; + + public StringWriterWithEncoding(StringBuilder builder, Encoding encoding) : base(builder) + { + _encoding = encoding; + } + + public override Encoding Encoding + { + get + { + return _encoding; + } + } + + } + +} \ No newline at end of file diff --git a/Server/Core/Security/BlogUser.cs b/Server/Core/Security/BlogUser.cs new file mode 100644 index 00000000..a5b37813 --- /dev/null +++ b/Server/Core/Security/BlogUser.cs @@ -0,0 +1,171 @@ +using System; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Entities.Users; + +namespace DotNetNuke.Modules.Blog.Security +{ + + /// + /// This class makes the UserInfo more robust and adds the much missed IsAdministrator to this + /// object so we don't have to keep on looking this up. + /// + /// + [Serializable()] + public class BlogUser : UserInfo + { + + #region Private Members + #endregion + + #region Constructors + public BlogUser() + { + LoadUser(null); + } + + public BlogUser(ref UserInfo user) + { + LoadUser(user); + } + + private void LoadUser(UserInfo user) + { + if (user is null) + { + user = Framework.ServiceLocator.Instance.GetCurrentUserInfo(); + } + + AffiliateID = user.AffiliateID; + DisplayName = Common.Globals.GetAString(user.DisplayName); + Email = Common.Globals.GetAString(user.Email); + FirstName = Common.Globals.GetAString(user.FirstName); + IsSuperUser = user.IsSuperUser; + LastName = Common.Globals.GetAString(user.LastName); + Membership = user.Membership; + PortalID = user.PortalID; + Profile = user.Profile; + Roles = user.Roles; + UserID = user.UserID; + UserID = user.UserID; + Username = Common.Globals.GetAString(user.Username); + + if (IsSuperUser) + { + IsAdministrator = true; + } + else if (UserID > -1) + { + var objPortals = new DotNetNuke.Entities.Portals.PortalController(); + var objPortal = objPortals.GetPortal(PortalID); + if (IsInRole(objPortal.AdministratorRoleName)) + { + IsAdministrator = true; + } + } + + if (UserID == -1) + { + try + { + PortalID = Framework.ServiceLocator.Instance.GetCurrentPortalSettings().PortalId; + } + catch (Exception ex) + { + return; + } + } + + } + #endregion + + #region Public Properties + public bool IsAdministrator { get; set; } = false; + #endregion + + #region Public Shared Methods + public static BlogUser GetCurrentUser() + { + var dnnUser = Framework.ServiceLocator.Instance.GetCurrentUserInfo(); + string cacheKey = string.Format("BlogUser{0}-{1}", dnnUser.PortalID, dnnUser.UserID); + BlogUser du = null; + try + { + du = (BlogUser)DotNetNuke.Common.Utilities.DataCache.GetCache(cacheKey); + } + catch + { + } + if (du is null) + { + du = new BlogUser(ref dnnUser); + DotNetNuke.Common.Utilities.DataCache.SetCache(cacheKey, du); + } + return du; + } + + public static BlogUser GetUser(int portalId, int userId) + { + string cacheKey = string.Format("BlogUser{0}-{1}", portalId, userId); + BlogUser du = null; + try + { + du = (BlogUser)DotNetNuke.Common.Utilities.DataCache.GetCache(cacheKey); + } + catch + { + } + if (du is null) + { + var dnnUser = UserController.GetUserById(portalId, userId); + if (dnnUser is null) + { + dnnUser = new UserInfo(); + dnnUser.PortalID = portalId; + } + du = new BlogUser(ref dnnUser); + DotNetNuke.Common.Utilities.DataCache.SetCache(cacheKey, du); + } + return du; + } + + public static BlogUser GetUser(UserInfo user) + { + string cacheKey = string.Format("BlogUser{0}-{1}", user.PortalID, user.UserID); + BlogUser du = null; + try + { + du = (BlogUser)DotNetNuke.Common.Utilities.DataCache.GetCache(cacheKey); + } + catch + { + } + if (du is null) + { + du = new BlogUser(ref user); + DotNetNuke.Common.Utilities.DataCache.SetCache(cacheKey, du); + } + return du; + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Security/ContextSecurity.cs b/Server/Core/Security/ContextSecurity.cs new file mode 100644 index 00000000..1e8fce22 --- /dev/null +++ b/Server/Core/Security/ContextSecurity.cs @@ -0,0 +1,356 @@ +using DotNetNuke.Entities.Users; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using static DotNetNuke.Modules.Blog.Security.Security; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Security.Permissions; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Security +{ + + public class ContextSecurity : IPropertyAccess + { + + #region Private Members + private bool _canAdd = false; + private bool _canEdit = false; + private bool _canApprove = false; + private bool _canAddComment = false; + private bool _canApproveComment = false; + private bool _canAutoApproveComment = false; + private bool _canViewComment = false; + private bool _userIsAdmin = false; + private bool _isBlogger = false; + private bool _isEditor = false; + private int _userId = -1; + #endregion + + #region Constructor + public ContextSecurity(int moduleId, int tabId, BlogInfo blog, UserInfo user) + { + _userId = user.UserID; + if (blog is not null) + { + IsOwner = blog.CreatedByUserID == user.UserID; + _canAdd = blog.CanAdd; + _canEdit = blog.CanEdit; + _canApprove = blog.CanApprove; + _canViewComment = blog.Permissions.CurrentUserHasPermission("VIEWCOMMENT"); + _canApproveComment = blog.Permissions.CurrentUserHasPermission("APPROVECOMMENT"); + _canAutoApproveComment = blog.Permissions.CurrentUserHasPermission("AUTOAPPROVECOMMENT"); + _canAddComment = blog.Permissions.CurrentUserHasPermission("ADDCOMMENT"); + } + else + { + using (var ir = Data.DataProvider.Instance().GetUserPermissionsByModule(moduleId, user.UserID)) + { + while (ir.Read()) + { + int permissionId = Conversions.ToInteger(ir["PermissionId"]); + int hasPermission = Conversions.ToInteger(ir["HasPermission"]); + if (hasPermission > 0) + { + switch (permissionId) + { + case (int)BlogPermissionTypes.ADD: + { + _canAdd = true; + break; + } + case (int)BlogPermissionTypes.EDIT: + { + _canEdit = true; + break; + } + case (int)BlogPermissionTypes.APPROVE: + { + _canApprove = true; + break; + } + } + } + } + } + } + LoggedIn = user.UserID > -1; + _userIsAdmin = DotNetNuke.Security.PortalSecurity.IsInRole(DotNetNuke.Entities.Portals.PortalSettings.Current.AdministratorRoleName); + var mc = new DotNetNuke.Entities.Modules.ModuleController(); + var objMod = new DotNetNuke.Entities.Modules.ModuleInfo(); + objMod = mc.GetModule(moduleId, tabId, false); + if (objMod is not null) + { + _isBlogger = ModulePermissionController.HasModulePermission(objMod.ModulePermissions, BloggerPermission); + _isEditor = ModulePermissionController.HasModulePermission(objMod.ModulePermissions, "EDIT"); + } + } + #endregion + + #region Public Properties + public bool IsOwner { get; set; } = false; + public bool LoggedIn { get; set; } = false; + + public bool CanEditPost + { + get + { + return _canEdit | IsOwner | UserIsAdmin; + } + } + public bool CanEditThisPost(Entities.Posts.PostInfo post) + { + if (CanEditPost) + return true; + if (post is null) + return false; + if (post.Blog.MustApproveGhostPosts && !CanApprovePost) + { + if (post.CreatedByUserID == _userId & !post.Published) + return true; + } + else if (post.CreatedByUserID == _userId) + return true; + return false; + } + + public bool CanAddPost + { + get + { + return _canAdd | IsOwner | UserIsAdmin; + } + } + + public bool CanAddComment + { + get + { + return _canAddComment | IsOwner | UserIsAdmin; + } + } + + public bool CanViewComments + { + get + { + return _canViewComment | IsOwner | UserIsAdmin; + } + } + + public bool CanApprovePost + { + get + { + return _canApprove | IsOwner | UserIsAdmin; + } + } + + public bool CanApproveComment + { + get + { + return _canApproveComment | IsOwner | UserIsAdmin; + } + } + + public bool CanAutoApproveComment + { + get + { + return _canAutoApproveComment | IsOwner | UserIsAdmin; + } + } + + public bool CanDoSomethingWithPosts + { + get + { + return _canEdit | _canAdd | _canApprove | _isBlogger | UserIsAdmin; + } + } + + public bool UserIsAdmin + { + get + { + return _userIsAdmin; + } + } + + public bool IsBlogger + { + get + { + return _isBlogger; + } + } + + public bool IsEditor + { + get + { + return _isEditor; + } + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "isowner": + { + return IsOwner.ToString(); + } + case "isowneryesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(IsOwner, formatProvider); + } + case "caneditpost": + { + return CanEditPost.ToString(); + } + case "caneditpostyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(CanEditPost, formatProvider); + } + case "canaddpost": + { + return CanAddPost.ToString(); + } + case "canaddpostyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(CanAddPost, formatProvider); + } + case "canaddcomment": + { + return CanAddComment.ToString(); + } + case "canaddcommentyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(CanAddComment, formatProvider); + } + case "canviewcomments": + { + return CanViewComments.ToString(); + } + case "canviewcommentsyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(CanViewComments, formatProvider); + } + case "canapprovepost": + { + return CanApprovePost.ToString(); + } + case "canapprovepostyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(CanApprovePost, formatProvider); + } + case "canapprovecomment": + { + return CanApproveComment.ToString(); + } + case "canapprovecommentyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(CanApproveComment, formatProvider); + } + case "canautoapprovecomment": + { + return CanAutoApproveComment.ToString(); + } + case "canautoapprovecommentyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(CanAutoApproveComment, formatProvider); + } + case "candosomethingwithposts": + { + return CanDoSomethingWithPosts.ToString(); + } + case "candosomethingwithpostsyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(CanDoSomethingWithPosts, formatProvider); + } + case "userisadmin": + { + return UserIsAdmin.ToString(); + } + case "userisadminyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(UserIsAdmin, formatProvider); + } + case "isblogger": + { + return IsBlogger.ToString(); + } + case "isbloggeryesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(IsBlogger, formatProvider); + } + case "iseditor": + { + return IsEditor.ToString(); + } + case "iseditoryesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(IsEditor, formatProvider); + } + case "loggedin": + { + return LoggedIn.ToString(); + } + case "loggedinyesno": + { + return PropertyAccess.Boolean2LocalizedYesNo(LoggedIn, formatProvider); + } + + default: + { + PropertyNotFound = true; + break; + } + } + return DotNetNuke.Common.Utilities.Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Security/Controls/BlogPermissionsGrid.cs b/Server/Core/Security/Controls/BlogPermissionsGrid.cs new file mode 100644 index 00000000..04605803 --- /dev/null +++ b/Server/Core/Security/Controls/BlogPermissionsGrid.cs @@ -0,0 +1,690 @@ +using System; +using System.Collections; +using System.Text; +using System.Web.UI; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Users; +using DotNetNuke.Modules.Blog.Security.Permissions; +using static DotNetNuke.Modules.Blog.Security.Security; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Security.Controls +{ + + public class BlogPermissionsGrid : PermissionsGrid + { + + #region Private Members + + private bool _InheritViewPermissionsFromParent = false; + private int _BlogID = -1; + private int _TabId = -1; + private BlogPermissionCollection _BlogPermissions; + private int _ViewColumnIndex; + private string _BlogType; + private int _currentUserId = -1; + private bool _userIsAdmin = false; + + #endregion + + #region Public Properties + public bool UserIsAdmin + { + get + { + return _userIsAdmin; + } + set + { + _userIsAdmin = value; + } + } + + public int CurrentUserId + { + get + { + return _currentUserId; + } + set + { + _currentUserId = value; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets and Sets the Id of the Blog + /// + /// + /// [cnurse] 01/09/2006 Documented + /// + /// ----------------------------------------------------------------------------- + public int BlogID + { + get + { + return _BlogID; + } + set + { + _BlogID = value; + if (!Page.IsPostBack) + { + GetBlogPermissions(); + } + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets and Sets the Id of the Tab associated with this Blog + /// + /// + /// [cnurse] 24/11/2006 Created + /// + /// ----------------------------------------------------------------------------- + public int TabId + { + get + { + return _TabId; + } + set + { + _TabId = value; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the BlogPermission Collection + /// + /// + /// [cnurse] 01/09/2006 Documented + /// + /// ----------------------------------------------------------------------------- + public BlogPermissionCollection Permissions + { + get + { + // First Update Permissions in case they have been changed + UpdatePermissions(); + + // Return the BlogPermissions + return _BlogPermissions; + + } + set + { + _BlogPermissions = value; + } + } + #endregion + + #region Private Methods + + /// ----------------------------------------------------------------------------- + /// + /// Gets the BlogPermissions from the Data Store + /// + /// + /// + /// ----------------------------------------------------------------------------- + private void GetBlogPermissions() + { + + _BlogPermissions = BlogPermissionsController.GetBlogPermissionsCollection(BlogID); + + } + + /// ----------------------------------------------------------------------------- + /// + /// Parse the Permission Keys used to persist the Permissions in the ViewState + /// + /// A string array of settings + /// An Arraylist to add the Permission object to + /// + /// + /// ----------------------------------------------------------------------------- + private void ParsePermissionKeys(string[] Settings, ArrayList arrPermisions) + { + + var objBlogPermission = new BlogPermissionInfo(); + var permission = PermissionsController.GetPermission(Convert.ToInt32(Settings[1])); + objBlogPermission.PermissionId = permission.PermissionId; + objBlogPermission.PermissionKey = permission.PermissionKey; + objBlogPermission.RoleId = Convert.ToInt32(Settings[4]); + + objBlogPermission.RoleName = Settings[3]; + objBlogPermission.AllowAccess = Conversions.ToBoolean(Settings[0]); + objBlogPermission.UserId = Convert.ToInt32(Settings[5]); + objBlogPermission.DisplayName = Settings[6]; + + objBlogPermission.BlogId = BlogID; + arrPermisions.Add(objBlogPermission); + + } + + /// ----------------------------------------------------------------------------- + /// + /// Check if the Role has the permission specified + /// + /// The Id of the Permission to check + /// The role id to check + /// + /// [cnurse] 01/09/2006 Documented + /// + /// ----------------------------------------------------------------------------- + private BlogPermissionInfo BlogHasRolePermission(int permissionID, int roleid) + { + int i; + var loopTo = _BlogPermissions.Count - 1; + for (i = 0; i <= loopTo; i++) + { + var objBlogPermission = _BlogPermissions[i]; + if (permissionID == objBlogPermission.PermissionId & objBlogPermission.RoleId == roleid) + { + return objBlogPermission; + } + } + return null; + } + + /// ----------------------------------------------------------------------------- + /// + /// Check if the Role has the permission specified + /// + /// The Id of the Permission to check + /// The user id to check + /// + /// [cnurse] 01/09/2006 Documented + /// + /// ----------------------------------------------------------------------------- + private BlogPermissionInfo BlogHasUserPermission(int permissionID, int userid) + { + int i; + var loopTo = _BlogPermissions.Count - 1; + for (i = 0; i <= loopTo; i++) + { + var objBlogPermission = _BlogPermissions[i]; + if (permissionID == objBlogPermission.PermissionId & objBlogPermission.UserId == userid) + { + return objBlogPermission; + } + } + return null; + } + + #endregion + + #region Protected Methods + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Enabled status of the permission + /// + /// The permission being loaded + /// The role + /// The column of the Grid + /// + /// [cnurse] 01/13/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override bool GetEnabled(PermissionInfo objPerm, DotNetNuke.Security.Roles.RoleInfo role, int column) + { + + if (role.RoleID == AdministratorRoleId) + { + return false; + } + else if (role.RoleID == -1) // all users + { + if (objPerm.PermissionId == (int)BlogPermissionTypes.ADD | objPerm.PermissionId == (int)BlogPermissionTypes.APPROVE | objPerm.PermissionId == (int)BlogPermissionTypes.EDIT) + { + return false; + } + else + { + return true; + } + } + else + { + return true; + } + + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Enabled status of the permission + /// + /// The permission being loaded + /// The user + /// The column of the Grid + /// + /// [cnurse] 01/13/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override bool GetEnabled(PermissionInfo objPerm, UserInfo user, int column) + { + + return true; + + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Value of the permission + /// + /// The permission being loaded + /// The role + /// The column of the Grid + /// A Boolean (True or False) + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override bool GetPermission(PermissionInfo objPerm, DotNetNuke.Security.Roles.RoleInfo role, int column) + { + + bool permission; + + var objBlogPermission = BlogHasRolePermission(objPerm.PermissionId, role.RoleID); + if (objBlogPermission is not null) + { + permission = objBlogPermission.AllowAccess; + } + else + { + permission = false; + } + + return permission; + + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Value of the permission + /// + /// The permission being loaded + /// The role + /// The column of the Grid + /// A Boolean (True or False) + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override bool GetPermission(PermissionInfo objPerm, UserInfo user, int column) + { + + bool permission; + + var objBlogPermission = BlogHasUserPermission(objPerm.PermissionId, user.UserID); + if (objBlogPermission is not null) + { + permission = objBlogPermission.AllowAccess; + } + else + { + permission = false; + } + + return permission; + + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Permissions from the Data Store + /// + /// + /// [cnurse] 01/09/2006 Documented + /// + /// ----------------------------------------------------------------------------- + protected override PermissionCollection GetPermissions() + { + + _ViewColumnIndex = 0; + return PermissionsController.GetPermissions(); + + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the users from the Database + /// + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override ArrayList GetUsers() + { + + var arrUsers = new ArrayList(); + UserInfo objUser; + bool blnExists; + + foreach (var objBlogPermission in _BlogPermissions) + { + if (!(objBlogPermission.UserId == glbUserNothing)) + { + blnExists = false; + foreach (UserInfo currentObjUser in arrUsers) + { + objUser = currentObjUser; + if (objBlogPermission.UserId == objUser.UserID) + { + blnExists = true; + } + } + if (!blnExists) + { + objUser = new UserInfo(); + objUser.UserID = objBlogPermission.UserId; + objUser.Username = objBlogPermission.Username; + objUser.DisplayName = objBlogPermission.DisplayName; + arrUsers.Add(objUser); + } + } + } + return arrUsers; + + } + + /// ----------------------------------------------------------------------------- + /// + /// Load the ViewState + /// + /// The saved state + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override void LoadViewState(object savedState) + { + + if (savedState is not null) + { + // Load State from the array of objects that was saved with SaveViewState. + + object[] myState = (object[])savedState; + + // Load Base Controls ViewState + if (myState[0] is not null) + { + base.LoadViewState(myState[0]); + } + + // Load BlogID + if (myState[1] is not null) + { + BlogID = Conversions.ToInteger(myState[1]); + } + + if (myState[2] is not null) + { + CurrentUserId = Conversions.ToInteger(myState[2]); + } + + // Load BlogPermissions + if (myState[3] is not null) + { + var arrPermissions = new ArrayList(); + string state = Conversions.ToString(myState[3]); + if (!string.IsNullOrEmpty(state)) + { + // First Break the String into individual Keys + string[] permissionKeys = Strings.Split(state, "##"); + foreach (string key in permissionKeys) + { + string[] Settings = Strings.Split(key, "|"); + ParsePermissionKeys(Settings, arrPermissions); + } + } + _BlogPermissions = new BlogPermissionCollection(arrPermissions); + } + } + + } + + /// ----------------------------------------------------------------------------- + /// + /// Saves the ViewState + /// + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override object SaveViewState() + { + + UpdatePermissions(); + + var allStates = new object[4]; + + allStates[0] = base.SaveViewState(); + allStates[1] = BlogID; + allStates[2] = CurrentUserId; + + // Persist the BlogPermissions + var sb = new StringBuilder(); + bool addDelimiter = false; + foreach (BlogPermissionInfo objBlogPermission in _BlogPermissions) + { + if (addDelimiter) + { + sb.Append("##"); + } + else + { + addDelimiter = true; + } + sb.Append(BuildKey(objBlogPermission.AllowAccess, objBlogPermission.PermissionId, -1, objBlogPermission.RoleId, objBlogPermission.RoleName, objBlogPermission.UserId, objBlogPermission.DisplayName)); + } + allStates[3] = sb.ToString(); + + return allStates; + + } + + /// ----------------------------------------------------------------------------- + /// + /// Updates a Permission + /// + /// The permission being updated + /// The name of the role + /// The id of the role + /// The value of the permission + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override void UpdatePermission(PermissionInfo permission, int roleId, string roleName, bool allowAccess) + { + + bool isMatch = false; + BlogPermissionInfo objPermission; + int permissionId = permission.PermissionId; + + // Search BlogPermission Collection for the permission to Update + foreach (var currentObjPermission in _BlogPermissions) + { + objPermission = currentObjPermission; + if (objPermission.PermissionId == permissionId & objPermission.RoleId == roleId) + { + // BlogPermission is in collection + objPermission.AllowAccess = allowAccess; + isMatch = true; + break; + } + } + + // BlogPermission not found so add new + if (!isMatch & allowAccess) + { + objPermission = new BlogPermissionInfo(); + objPermission.PermissionId = permission.PermissionId; + objPermission.PermissionKey = permission.PermissionKey; + objPermission.BlogId = BlogID; + objPermission.RoleId = roleId; + objPermission.RoleName = roleName; + objPermission.AllowAccess = allowAccess; + objPermission.UserId = glbUserNothing; + objPermission.DisplayName = Null.NullString; + _BlogPermissions.Add(objPermission); + } + + } + + /// ----------------------------------------------------------------------------- + /// + /// Updates a Permission + /// + /// The permission being updated + /// The user's displayname + /// The user's id + /// The value of the permission + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override void UpdatePermission(PermissionInfo permission, string displayName, int userId, bool allowAccess) + { + + bool isMatch = false; + BlogPermissionInfo objPermission; + int permissionId = permission.PermissionId; + + // Search BlogPermission Collection for the permission to Update + foreach (var currentObjPermission in _BlogPermissions) + { + objPermission = currentObjPermission; + if (objPermission.PermissionId == permissionId & objPermission.UserId == userId) + { + objPermission.AllowAccess = allowAccess; + isMatch = true; + break; + } + } + + // BlogPermission not found so add new + if (!isMatch & allowAccess) + { + objPermission = new BlogPermissionInfo(); + objPermission.PermissionId = permission.PermissionId; + objPermission.PermissionKey = permission.PermissionKey; + objPermission.BlogId = BlogID; + objPermission.RoleId = glbRoleNothing; + objPermission.RoleName = Null.NullString; + objPermission.AllowAccess = allowAccess; + objPermission.UserId = userId; + objPermission.DisplayName = displayName; + _BlogPermissions.Add(objPermission); + } + + } + + /// ----------------------------------------------------------------------------- + /// + /// Updates a Permission + /// + /// The permissions collection + /// The user to add + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override void AddPermission(PermissionCollection permissions, UserInfo user) + { + + BlogPermissionInfo objBlogPermission; + + // Search TabPermission Collection for the user + bool isMatch = false; + foreach (var currentObjBlogPermission in _BlogPermissions) + { + objBlogPermission = currentObjBlogPermission; + if (objBlogPermission.UserId == user.UserID) + { + isMatch = true; + break; + } + } + + // user not found so add new + if (!isMatch) + { + foreach (var objPermission in permissions.Values) + { + objBlogPermission = new BlogPermissionInfo(); + objBlogPermission.PermissionId = objPermission.PermissionId; + objBlogPermission.PermissionKey = objPermission.PermissionKey; + objBlogPermission.BlogId = BlogID; + objBlogPermission.RoleId = glbRoleNothing; + objBlogPermission.RoleName = Null.NullString; + if (objPermission.PermissionId == (int)BlogPermissionTypes.ADD) + { + objBlogPermission.AllowAccess = true; + } + else + { + objBlogPermission.AllowAccess = false; + } + objBlogPermission.UserId = user.UserID; + objBlogPermission.DisplayName = user.DisplayName; + _BlogPermissions.Add(objBlogPermission); + } + } + + } + + protected override void CreateChildControls() + { + base.CreateChildControls(); + } + #endregion + + #region Public Methods + + /// ----------------------------------------------------------------------------- + /// + /// Overrides the Base method to Generate the Data Grid + /// + /// + /// [cnurse] 01/09/2006 Documented + /// + /// ----------------------------------------------------------------------------- + public override void GenerateDataGrid() + { + + } + + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Security/Controls/PermissionsGrid.cs b/Server/Core/Security/Controls/PermissionsGrid.cs new file mode 100644 index 00000000..78b326cd --- /dev/null +++ b/Server/Core/Security/Controls/PermissionsGrid.cs @@ -0,0 +1,1150 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Linq; +using System.Runtime.CompilerServices; +using System.Web.UI; +using System.Web.UI.WebControls; +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Portals; +using DotNetNuke.Entities.Users; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Security.Permissions; +using DotNetNuke.Security.Roles; +using DotNetNuke.Services.Localization; +using DotNetNuke.UI.WebControls; +using Microsoft.VisualBasic; + +namespace DotNetNuke.Modules.Blog.Security.Controls +{ + + public abstract class PermissionsGrid : Control, INamingContainer + { + + private Panel pnlPermissions; + private Label lblGroups; + private DropDownList _cboRoleGroups; + + private DropDownList cboRoleGroups + { + [MethodImpl(MethodImplOptions.Synchronized)] + get + { + return _cboRoleGroups; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + set + { + if (_cboRoleGroups != null) + { + _cboRoleGroups.SelectedIndexChanged -= RoleGroupsSelectedIndexChanged; + } + + _cboRoleGroups = value; + if (_cboRoleGroups != null) + { + _cboRoleGroups.SelectedIndexChanged += RoleGroupsSelectedIndexChanged; + } + } + } + private DataGrid dgRolePermissions; + private Label lblUser; + private TextBox txtUser; + private LinkButton _cmdUser; + + private LinkButton cmdUser + { + [MethodImpl(MethodImplOptions.Synchronized)] + get + { + return _cmdUser; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + set + { + if (_cmdUser != null) + { + _cmdUser.Click -= AddUser; + } + + _cmdUser = value; + if (_cmdUser != null) + { + _cmdUser.Click += AddUser; + } + } + } + private DataGrid dgUserPermissions; + + #region Private Members + + private DataTable _dtRolePermissions = new DataTable(); + private DataTable _dtUserPermissions = new DataTable(); + private List _roles; + private ArrayList _users; + private PermissionCollection _permissions; + private string _resourceFile; + + #endregion + + #region Public Properties + + #region DataGrid Properties + + public TableItemStyle AlternatingItemStyle + { + get + { + return dgRolePermissions.AlternatingItemStyle; + } + } + + public bool AutoGenerateColumns + { + get + { + return dgRolePermissions.AutoGenerateColumns; + } + set + { + dgRolePermissions.AutoGenerateColumns = value; + dgUserPermissions.AutoGenerateColumns = value; + } + } + + public int CellSpacing + { + get + { + return dgRolePermissions.CellSpacing; + } + set + { + dgRolePermissions.CellSpacing = value; + dgUserPermissions.CellSpacing = value; + } + } + + public DataGridColumnCollection Columns + { + get + { + return dgRolePermissions.Columns; + } + } + + public TableItemStyle FooterStyle + { + get + { + return dgRolePermissions.FooterStyle; + } + } + + public GridLines GridLines + { + get + { + return dgRolePermissions.GridLines; + } + set + { + dgRolePermissions.GridLines = value; + dgUserPermissions.GridLines = value; + } + } + + public TableItemStyle HeaderStyle + { + get + { + return dgRolePermissions.HeaderStyle; + } + } + + public TableItemStyle ItemStyle + { + get + { + return dgRolePermissions.ItemStyle; + } + } + + public DataGridItemCollection Items + { + get + { + return dgRolePermissions.Items; + } + } + + public TableItemStyle SelectedItemStyle + { + get + { + return dgRolePermissions.SelectedItemStyle; + } + } + + public bool IncludeAdministratorRole { get; set; } = true; + #endregion + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Id of the Administrator Role + /// + /// + /// [cnurse] 01/16/2006 Created + /// + /// ----------------------------------------------------------------------------- + public int AdministratorRoleId + { + get + { + return Framework.ServiceLocator.Instance.GetCurrentPortalSettings().AdministratorRoleId; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Id of the Registered Users Role + /// + /// + /// [cnurse] 01/16/2006 Created + /// + /// ----------------------------------------------------------------------------- + public int RegisteredUsersRoleId + { + get + { + return Framework.ServiceLocator.Instance.GetCurrentPortalSettings().RegisteredRoleId; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets and Sets whether a Dynamic Column has been added + /// + /// + /// [cnurse] 01/09/2006 Documented + /// + /// ----------------------------------------------------------------------------- + public bool DynamicColumnAdded + { + get + { + if (ViewState["ColumnAdded"] is null) + { + return false; + } + else + { + return true; + } + } + set + { + ViewState["ColumnAdded"] = value; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the underlying Permissions Data Table + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + public DataTable dtRolePermissions + { + get + { + return _dtRolePermissions; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the underlying Permissions Data Table + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + public DataTable dtUserPermissions + { + get + { + return _dtUserPermissions; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Id of the Portal + /// + /// + /// [cnurse] 01/16/2006 Created + /// + /// ----------------------------------------------------------------------------- + public int PortalId + { + get + { + // Obtain PortalSettings from Current Context + var _portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + int intPortalID; + + if (_portalSettings.ActiveTab.ParentId == _portalSettings.SuperTabId) // if we are in host filemanager then we need to pass a null portal id + { + intPortalID = Null.NullInteger; + } + else + { + intPortalID = _portalSettings.PortalId; + } + + return intPortalID; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets and Sets the collection of Roles to display + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + public List Roles + { + get + { + return _roles; + } + set + { + _roles = value; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets and Sets the ResourceFile to localize permissions + /// + /// + /// [vmasanas] 02/24/2006 Created + /// + /// ----------------------------------------------------------------------------- + public string ResourceFile + { + get + { + return _resourceFile; + } + set + { + _resourceFile = value; + } + } + #endregion + + #region Abstract Methods + + /// ----------------------------------------------------------------------------- + /// + /// Generate the Data Grid + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + public abstract void GenerateDataGrid(); + + #endregion + + #region Private Methods + + /// ----------------------------------------------------------------------------- + /// + /// Bind the data to the controls + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + private void BindData() + { + + EnsureChildControls(); + + BindRolesGrid(); + BindUsersGrid(); + + } + + /// ----------------------------------------------------------------------------- + /// + /// Bind the Roles data to the Grid + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + private void BindRolesGrid() + { + + dtRolePermissions.Columns.Clear(); + dtRolePermissions.Rows.Clear(); + + DataColumn col; + + // Add Roles Column + col = new DataColumn("RoleId"); + dtRolePermissions.Columns.Add(col); + + // Add Roles Column + col = new DataColumn("RoleName"); + dtRolePermissions.Columns.Add(col); + + foreach (PermissionInfo pi in _permissions.Values) + { + // Add Enabled Column + col = new DataColumn(pi.PermissionKey + "_Enabled"); + dtRolePermissions.Columns.Add(col); + // Add Permission Column + col = new DataColumn(pi.PermissionKey); + dtRolePermissions.Columns.Add(col); + } + int i; + + GetRoles(); + + UpdateRolePermissions(); + DataRow row; + var loopTo = Roles.Count - 1; + for (i = 0; i <= loopTo; i++) + { + var role = Roles[i]; + row = dtRolePermissions.NewRow(); + row["RoleId"] = role.RoleID; + row["RoleName"] = Localization.LocalizeRole(role.RoleName); + + int j = 0; + foreach (PermissionInfo pi in _permissions.Values) + { + row[pi.PermissionKey + "_Enabled"] = GetEnabled(pi, role, j + 1); + row[pi.PermissionKey] = GetPermission(pi, role, j + 1); + j += 1; + } + dtRolePermissions.Rows.Add(row); + } + + dgRolePermissions.DataSource = dtRolePermissions; + dgRolePermissions.DataBind(); + + } + + /// ----------------------------------------------------------------------------- + /// + /// Bind the Roles data to the Grid + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + private void BindUsersGrid() + { + + dtUserPermissions.Columns.Clear(); + dtUserPermissions.Rows.Clear(); + + DataColumn col; + + // Add Roles Column + col = new DataColumn("UserId"); + dtUserPermissions.Columns.Add(col); + + // Add Roles Column + col = new DataColumn("DisplayName"); + dtUserPermissions.Columns.Add(col); + + int i; + foreach (PermissionInfo pi in _permissions.Values) + { + // Add Enabled Column + col = new DataColumn(pi.PermissionKey + "_Enabled"); + dtUserPermissions.Columns.Add(col); + // Add Permission Column + col = new DataColumn(pi.PermissionKey); + dtUserPermissions.Columns.Add(col); + } + + if (dgUserPermissions is not null) + { + + _users = GetUsers(); + + if (_users.Count != 0) + { + dgUserPermissions.Visible = true; + + UpdateUserPermissions(); + + DataRow row; + var loopTo = _users.Count - 1; + for (i = 0; i <= loopTo; i++) + { + UserInfo user = (UserInfo)_users[i]; + row = dtUserPermissions.NewRow(); + row["UserId"] = user.UserID; + row["DisplayName"] = user.DisplayName; + + int j = 0; + foreach (PermissionInfo pi in _permissions.Values) + { + row[pi.PermissionKey + "_Enabled"] = GetEnabled(pi, user, j + 1); + row[pi.PermissionKey] = GetPermission(pi, user, j + 1); + j += 1; + } + dtUserPermissions.Rows.Add(row); + } + + dgUserPermissions.DataSource = dtUserPermissions; + dgUserPermissions.DataBind(); + } + else + { + dgUserPermissions.Visible = false; + } + } + + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the roles from the Database and loads them into the Roles property + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + private void GetRoles() + { + var objRoleController = new RoleController(); + int RoleGroupId = -2; + if (cboRoleGroups is not null && cboRoleGroups.SelectedValue is not null) + { + RoleGroupId = int.Parse(cboRoleGroups.SelectedValue); + } + + if (RoleGroupId > -2) + { + _roles = GetRolesByGroup(Framework.ServiceLocator.Instance.GetCurrentPortalSettings().PortalId, RoleGroupId); + } + else + { + _roles = GetRolesByPortal(Framework.ServiceLocator.Instance.GetCurrentPortalSettings().PortalId); + } + if (!IncludeAdministratorRole) + { + var newList = new List(); + foreach (RoleInfo r in _roles) + { + if (r.RoleID != AdministratorRoleId) + { + newList.Add(r); + } + } + _roles = newList; + } + + if (RoleGroupId < 0) + { + var r = new RoleInfo(); + r.RoleID = -1; // all users + r.RoleName = DotNetNuke.Common.Globals.glbRoleAllUsersName; + _roles.Add(r); + } + _roles.Reverse(); + _roles = _roles.OrderBy(r => r.RoleName.ToLower()).ToList(); + } + + /// ----------------------------------------------------------------------------- + /// + /// Sets up the columns for the Grid + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + private void SetUpRolesGrid() + { + + dgRolePermissions.Columns.Clear(); + + var textCol = new BoundColumn(); + textCol.HeaderText = " "; + textCol.DataField = "RoleName"; + textCol.ItemStyle.Width = Unit.Parse("100px"); + dgRolePermissions.Columns.Add(textCol); + + var idCol = new BoundColumn(); + idCol.HeaderText = ""; + idCol.DataField = "roleid"; + idCol.Visible = false; + dgRolePermissions.Columns.Add(idCol); + + TemplateColumn checkCol; + + // Dim objPermission As PermissionInfo + foreach (PermissionInfo objPermission in _permissions.Values) + { + checkCol = new TemplateColumn(); + var columnTemplate = new CheckBoxColumnTemplate(); + columnTemplate.DataField = objPermission.PermissionKey; + columnTemplate.EnabledField = objPermission.PermissionKey + "_Enabled"; + checkCol.ItemTemplate = columnTemplate; + string locName = ""; + locName = Localization.GetString(objPermission.PermissionKey + ".Permission", SharedResourceFileName); + if (locName is null) + { + locName = objPermission.PermissionKey; + } + checkCol.HeaderText = Interaction.IIf(!string.IsNullOrEmpty(locName), locName, objPermission.PermissionKey).ToString(); + checkCol.ItemStyle.HorizontalAlign = HorizontalAlign.Center; + checkCol.HeaderStyle.Wrap = true; + dgRolePermissions.Columns.Add(checkCol); + } + + } + + private void SetUpUsersGrid() + { + + if (dgUserPermissions is not null) + { + dgUserPermissions.Columns.Clear(); + + var textCol = new BoundColumn(); + textCol.HeaderText = " "; + textCol.DataField = "DisplayName"; + textCol.ItemStyle.Width = Unit.Parse("100px"); + dgUserPermissions.Columns.Add(textCol); + + var idCol = new BoundColumn(); + idCol.HeaderText = ""; + idCol.DataField = "userid"; + idCol.Visible = false; + dgUserPermissions.Columns.Add(idCol); + + TemplateColumn checkCol; + + foreach (PermissionInfo objPermission in _permissions.Values) + { + checkCol = new TemplateColumn(); + var columnTemplate = new CheckBoxColumnTemplate(); + columnTemplate.DataField = objPermission.PermissionKey; + columnTemplate.EnabledField = objPermission.PermissionKey + "_Enabled"; + checkCol.ItemTemplate = columnTemplate; + string locName = ""; + locName = Localization.GetString(objPermission.PermissionKey + ".Permission", SharedResourceFileName); + if (locName is null) + { + locName = objPermission.PermissionKey; + } + checkCol.HeaderText = Interaction.IIf(!string.IsNullOrEmpty(locName), locName, objPermission.PermissionKey).ToString(); + checkCol.ItemStyle.HorizontalAlign = HorizontalAlign.Center; + checkCol.HeaderStyle.Wrap = true; + dgUserPermissions.Columns.Add(checkCol); + } + } + + } + + + #endregion + + #region Protected Methods + + /// ----------------------------------------------------------------------------- + /// + /// Builds the key used to store the "permission" information in the ViewState + /// + /// Is the checkbox checked + /// The Id of the permission + /// The Id of the object permission + /// The role id + /// The role name + /// + /// + /// ----------------------------------------------------------------------------- + protected string BuildKey(bool @checked, int permissionId, int objectPermissionId, int roleId, string roleName) + { + return BuildKey(@checked, permissionId, objectPermissionId, roleId, roleName, Null.NullInteger, Null.NullString); + } + + /// ----------------------------------------------------------------------------- + /// + /// Builds the key used to store the "permission" information in the ViewState + /// + /// Is the checkbox checked + /// The Id of the permission + /// The Id of the object permission + /// The role id + /// The role name + /// The user id + /// The user display name + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected string BuildKey(bool @checked, int permissionId, int objectPermissionId, int roleId, string roleName, int userID, string displayName) + { + + string key; + + if (@checked) + { + key = "True"; + } + else + { + key = "False"; + } + + key += "|" + Convert.ToString(permissionId); + + // Add objectPermissionId + key += "|"; + if (objectPermissionId > -1) + { + key += Convert.ToString(objectPermissionId); + } + + key += "|" + roleName; + key += "|" + roleId.ToString(); + key += "|" + userID.ToString(); + key += "|" + displayName.ToString(); + + return key; + + } + + /// ----------------------------------------------------------------------------- + /// + /// Creates the Child Controls + /// + /// + /// [cnurse] 02/23/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected override void CreateChildControls() + { + + // get data + _permissions = GetPermissions(); + + pnlPermissions = new Panel(); + pnlPermissions.CssClass = "DataGrid_Container"; + + // Optionally Add Role Group Filter + var _portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + var arrGroups = RoleController.GetRoleGroups(_portalSettings.PortalId); + if (arrGroups.Count > 0) + { + lblGroups = new Label(); + lblGroups.Text = Localization.GetString("RoleGroupFilter"); + lblGroups.CssClass = "SubHead"; + pnlPermissions.Controls.Add(lblGroups); + + pnlPermissions.Controls.Add(new LiteralControl("  ")); + + cboRoleGroups = new DropDownList(); + cboRoleGroups.AutoPostBack = true; + + cboRoleGroups.Items.Add(new ListItem(Localization.GetString("AllRoles"), "-2")); + var liItem = new ListItem(Localization.GetString("GlobalRoles"), "-1"); + liItem.Selected = true; + cboRoleGroups.Items.Add(liItem); + foreach (RoleGroupInfo roleGroup in arrGroups) + cboRoleGroups.Items.Add(new ListItem(roleGroup.RoleGroupName, roleGroup.RoleGroupID.ToString())); + pnlPermissions.Controls.Add(cboRoleGroups); + + pnlPermissions.Controls.Add(new LiteralControl("

")); + } + + dgRolePermissions = new DataGrid(); + dgRolePermissions.AutoGenerateColumns = false; + dgRolePermissions.CellSpacing = 0; + dgRolePermissions.GridLines = GridLines.None; + dgRolePermissions.CssClass = "PermissionsGrid"; + dgRolePermissions.FooterStyle.CssClass = "DataGrid_Footer"; + dgRolePermissions.HeaderStyle.CssClass = "DataGrid_Header"; + dgRolePermissions.ItemStyle.CssClass = "DataGrid_Item"; + dgRolePermissions.AlternatingItemStyle.CssClass = "DataGrid_AlternatingItem"; + SetUpRolesGrid(); + pnlPermissions.Controls.Add(dgRolePermissions); + + _users = GetUsers(); + + if (_users is not null) + { + dgUserPermissions = new DataGrid(); + dgUserPermissions.AutoGenerateColumns = false; + dgUserPermissions.CellSpacing = 0; + dgUserPermissions.GridLines = GridLines.None; + dgUserPermissions.FooterStyle.CssClass = "DataGrid_Footer"; + dgUserPermissions.HeaderStyle.CssClass = "DataGrid_Header"; + dgUserPermissions.ItemStyle.CssClass = "DataGrid_Item"; + dgUserPermissions.AlternatingItemStyle.CssClass = "DataGrid_AlternatingItem"; + SetUpUsersGrid(); + pnlPermissions.Controls.Add(dgUserPermissions); + + pnlPermissions.Controls.Add(new LiteralControl("
")); + + lblUser = new Label(); + lblUser.Text = Localization.GetString("User"); + lblUser.CssClass = "SubHead"; + pnlPermissions.Controls.Add(lblUser); + + pnlPermissions.Controls.Add(new LiteralControl("  ")); + + txtUser = new TextBox(); + txtUser.CssClass = "NormalTextBox"; + pnlPermissions.Controls.Add(txtUser); + + pnlPermissions.Controls.Add(new LiteralControl("  ")); + + cmdUser = new LinkButton(); + cmdUser.Text = Localization.GetString("Add"); + cmdUser.CssClass = "dnnSecondaryAction"; + pnlPermissions.Controls.Add(cmdUser); + } + + Controls.Add(pnlPermissions); + + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Enabled status of the permission + /// + /// The permission being loaded + /// The role + /// The column of the Grid + /// + /// [cnurse] 01/13/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected virtual bool GetEnabled(PermissionInfo objPerm, RoleInfo role, int column) + { + return false; + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Enabled status of the permission + /// + /// The permission being loaded + /// The user + /// The column of the Grid + /// + /// [cnurse] 01/13/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected virtual bool GetEnabled(PermissionInfo objPerm, UserInfo user, int column) + { + return false; + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Value of the permission + /// + /// The permission being loaded + /// The role + /// The column of the Grid + /// + /// [cnurse] 01/13/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected virtual bool GetPermission(PermissionInfo objPerm, RoleInfo role, int column) + { + return false; + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the Value of the permission + /// + /// The permission being loaded + /// The user + /// The column of the Grid + /// + /// [cnurse] 01/13/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected virtual bool GetPermission(PermissionInfo objPerm, UserInfo user, int column) + { + return false; + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the permissions from the Database + /// + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected virtual PermissionCollection GetPermissions() + { + + return null; + + } + + /// ----------------------------------------------------------------------------- + /// + /// Gets the users from the Database + /// + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected virtual ArrayList GetUsers() + { + + return null; + + } + + protected override void OnLoad(EventArgs e) + { + + } + + /// ----------------------------------------------------------------------------- + /// + /// Overrides the base OnPreRender method to Bind the Grid to the Permissions + /// + /// + /// [cnurse] 01/09/2006 Documented + /// + /// ----------------------------------------------------------------------------- + protected override void OnPreRender(EventArgs e) + { + BindData(); + } + + /// ----------------------------------------------------------------------------- + /// + /// Updates a Permission + /// + /// The permission being updated + /// The name of the role + /// The value of the permission + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected virtual void UpdatePermission(PermissionInfo permission, int roleId, string roleName, bool allowAccess) + { + + } + + /// ----------------------------------------------------------------------------- + /// + /// Updates a Permission + /// + /// The permission being updated + /// The user's displayname + /// The user's id + /// The value of the permission + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected virtual void UpdatePermission(PermissionInfo permission, string displayName, int userId, bool allowAccess) + { + + } + + /// ----------------------------------------------------------------------------- + /// + /// Updates a Permission + /// + /// The permissions collection + /// The user to add + /// + /// [cnurse] 01/12/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected virtual void AddPermission(PermissionCollection permissions, UserInfo user) + { + + } + + /// ----------------------------------------------------------------------------- + /// + /// Updates the permissions + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected void UpdatePermissions() + { + + EnsureChildControls(); + + UpdateRolePermissions(); + UpdateUserPermissions(); + + } + + /// ----------------------------------------------------------------------------- + /// + /// Updates the permissions + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected void UpdateRolePermissions() + { + + if (dgRolePermissions is not null) + { + foreach (DataGridItem dgi in dgRolePermissions.Items) + { + int i; + var loopTo = dgi.Cells.Count - 1; + for (i = 2; i <= loopTo; i++) + { + // all except first two cells which is role names and role ids + if (dgi.Cells[i].Controls.Count > 0) + { + CheckBox cb = (CheckBox)dgi.Cells[i].Controls[0]; + UpdatePermission(_permissions[i - 2], int.Parse(dgi.Cells[1].Text), dgi.Cells[0].Text, cb.Checked); + } + } + } + } + + } + + /// ----------------------------------------------------------------------------- + /// + /// Updates the permissions + /// + /// + /// [cnurse] 01/09/2006 Created + /// + /// ----------------------------------------------------------------------------- + protected void UpdateUserPermissions() + { + + if (dgUserPermissions is not null) + { + foreach (DataGridItem dgi in dgUserPermissions.Items) + { + int i; + var loopTo = dgi.Cells.Count - 1; + for (i = 2; i <= loopTo; i++) + { + // all except first two cells which is displayname and userid + if (dgi.Cells[i].Controls.Count > 0) + { + CheckBox cb = (CheckBox)dgi.Cells[i].Controls[0]; + UpdatePermission(_permissions[i - 2], dgi.Cells[0].Text, int.Parse(dgi.Cells[1].Text), cb.Checked); + } + } + } + } + + } + + #endregion + + #region Event Handlers + + /// ----------------------------------------------------------------------------- + /// + /// RoleGroupsSelectedIndexChanged runs when the Role Group is changed + /// + /// + /// [cnurse] 01/06/2006 Documented + /// + /// ----------------------------------------------------------------------------- + private void RoleGroupsSelectedIndexChanged(object sender, EventArgs e) + { + + UpdatePermissions(); + + } + + /// ----------------------------------------------------------------------------- + /// + /// AddUser runs when the Add user linkbutton is clicked + /// + /// + /// + /// ----------------------------------------------------------------------------- + private void AddUser(object sender, EventArgs e) + { + + UpdatePermissions(); + + if (!string.IsNullOrEmpty(txtUser.Text)) + { + // verify username + var objUser = UserController.GetUserByName(PortalId, txtUser.Text); + if (objUser is not null) + { + AddPermission(_permissions, objUser); + BindData(); + } + else + { + // user does not exist + lblUser = new Label(); + lblUser.Text = "
" + Localization.GetString("InvalidUserName"); + lblUser.CssClass = "NormalRed"; + pnlPermissions.Controls.Add(lblUser); + } + } + + } + + #endregion + + } + + +} \ No newline at end of file diff --git a/Server/Core/Security/Permissions/BlogPermissionCollection.cs b/Server/Core/Security/Permissions/BlogPermissionCollection.cs new file mode 100644 index 00000000..fed2abeb --- /dev/null +++ b/Server/Core/Security/Permissions/BlogPermissionCollection.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections; +using System.Collections.Generic; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using DotNetNuke.Entities.Users; + +namespace DotNetNuke.Modules.Blog.Security.Permissions +{ + [Serializable()] + public class BlogPermissionCollection : List, IXmlSerializable + { + + public BlogPermissionCollection(ArrayList BlogPermissions) : base() + { + int i; + var loopTo = BlogPermissions.Count - 1; + for (i = 0; i <= loopTo; i++) + { + BlogPermissionInfo objBlogPermission = (BlogPermissionInfo)BlogPermissions[i]; + Add(objBlogPermission); + } + } + + public BlogPermissionCollection() : base() + { + } + + public new BlogPermissionInfo this[int index] + { + get + { + return base[index]; + } + set + { + base[index] = value; + } + } + + public new string ToString(string PermissionKey) + { + string res = ""; + foreach (BlogPermissionInfo epi in this) + { + if ((epi.PermissionKey ?? "") == (PermissionKey ?? "")) + { + if (epi.RoleId == -1) + { + res += ";" + DotNetNuke.Common.Globals.glbRoleAllUsersName; + } + else if (epi.RoleId > -1) + { + res += ";" + epi.RoleName; + } + else if (epi.UserId > -1) + { + res += ";" + epi.UserId.ToString(); + } + } + } + return res + ";"; + } + + public bool CurrentUserHasPermission(string PermissionKey) + { + var u = Framework.ServiceLocator.Instance.GetCurrentUserInfo(); + if (u is not null) + { + foreach (BlogPermissionInfo epi in this) + { + if (epi.PermissionKey is null) + { + var objP = PermissionsController.GetPermission(epi.PermissionId); + epi.PermissionKey = objP.PermissionKey; + } + if (epi.AllowAccess && (epi.PermissionKey ?? "") == (PermissionKey ?? "")) + { + if (epi.RoleId == -1) + return true; + if (epi.UserId == u.UserID) + return true; + foreach (string role in u.Roles) + { + if ((epi.RoleName ?? "") == (role ?? "")) + { + return true; + break; + } + } + } + } + } + return false; + } + + public bool ContainsPermissionKey(string permissionKey) + { + foreach (BlogPermissionInfo epi in this) + { + if (epi.PermissionKey is null) + { + var objP = PermissionsController.GetPermission(epi.PermissionId); + epi.PermissionKey = objP.PermissionKey; + } + if (epi.AllowAccess && (epi.PermissionKey ?? "") == (permissionKey ?? "")) + { + return true; + break; + } + } + return false; + } + + public bool ContainsPermission(string permissionKey, int RoleId, int UserId) + { + foreach (BlogPermissionInfo epi in this) + { + if (epi.PermissionKey is null) + { + var objP = PermissionsController.GetPermission(epi.PermissionId); + epi.PermissionKey = objP.PermissionKey; + } + if ((epi.PermissionKey ?? "") == (permissionKey ?? "") & epi.RoleId == RoleId & epi.UserId == UserId) + { + return true; + break; + } + } + return false; + } + + public void AddPermission(int PortalId, int BlogId, string PermissionKey, int RoleId, int UserId) + { + var objP = PermissionsController.GetPermissions()[PermissionKey]; + var pi = new BlogPermissionInfo(objP); + pi.BlogId = BlogId; + pi.RoleId = RoleId; + pi.UserId = UserId; + Add(pi); + } + + #region IXmlSerializable Implementation + /// ----------------------------------------------------------------------------- + /// + /// GetSchema returns the XmlSchema for this class + /// + /// GetSchema is implemented as a stub method as it is not required + /// + /// [pdonker] 05/21/2008 Created + /// + /// ----------------------------------------------------------------------------- + public XmlSchema GetSchema() + { + return null; + } + + private string readElement(XmlReader reader, string ElementName) + { + if (!(reader.NodeType == XmlNodeType.Element) || (reader.Name ?? "") != (ElementName ?? "")) + { + reader.ReadToFollowing(ElementName); + } + if (reader.NodeType == XmlNodeType.Element) + { + return reader.ReadElementContentAsString(); + } + else + { + return ""; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// ReadXml fills the object (de-serializes it) from the XmlReader passed + /// + /// + /// The XmlReader that contains the xml for the object + /// + /// [pdonker] 05/21/2008 Created + /// + /// ----------------------------------------------------------------------------- + public void ReadXml(XmlReader reader) + { + try + { + reader.ReadStartElement("Permissions"); + do + { + reader.ReadStartElement("Permission"); + var epi = new BlogPermissionInfo(); + epi.ReadXml(reader); + Add(epi); + } + while (reader.ReadToNextSibling("Permission")); + } + catch (Exception ex) + { + // log exception as DNN import routine does not do that + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + // re-raise exception to make sure import routine displays a visible error to the user + throw new Exception("An error occured during import of an Category", ex); + } + + } + + public void ReadXml(XmlNode xN) + { + + foreach (XmlNode xPermission in xN.ChildNodes) + { + var epi = new BlogPermissionInfo(); + epi.ReadXml(xPermission); + if (!string.IsNullOrEmpty(epi.RoleName)) // we don't import user permissions + { + Add(epi); + } + } + + } + + /// ----------------------------------------------------------------------------- + /// + /// WriteXml converts the object to Xml (serializes it) and writes it using the XmlWriter passed + /// + /// + /// The XmlWriter that contains the xml for the object + /// + /// [pdonker] 05/21/2008 Created + /// + /// ----------------------------------------------------------------------------- + public void WriteXml(XmlWriter writer) + { + writer.WriteStartElement("Permissions"); + foreach (BlogPermissionInfo epi in this) + { + if (epi.PermissionKey is null) + { + var pi = PermissionsController.GetPermission(epi.PermissionId); + epi.PermissionKey = pi.PermissionKey; + } + epi.WriteXml(writer); + } + writer.WriteEndElement(); + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Security/Permissions/BlogPermissionInfo.cs b/Server/Core/Security/Permissions/BlogPermissionInfo.cs new file mode 100644 index 00000000..51c31e87 --- /dev/null +++ b/Server/Core/Security/Permissions/BlogPermissionInfo.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; +using System.Xml; + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Modules.Blog.Common; + +using static DotNetNuke.Modules.Blog.Security.Security; + +namespace DotNetNuke.Modules.Blog.Security.Permissions +{ + public partial class BlogPermissionInfo + { + + #region Constructors + public BlogPermissionInfo() + { + BlogId = Null.NullInteger; + RoleId = glbRoleNothing; + AllowAccess = false; + _RoleName = Null.NullString; + UserId = glbUserNothing; + Username = Null.NullString; + DisplayName = Null.NullString; + } // New + + public BlogPermissionInfo(PermissionInfo pi) + { + BlogId = Null.NullInteger; + RoleId = glbRoleNothing; + AllowAccess = false; + _RoleName = Null.NullString; + UserId = glbUserNothing; + Username = Null.NullString; + DisplayName = Null.NullString; + PermissionId = pi.PermissionId; + PermissionKey = pi.PermissionKey; + } // New + #endregion + + + #region Public Properties + private string _RoleName; + [DataMember()] + public string RoleName + { + get + { + if (string.IsNullOrEmpty(_RoleName)) + { + if (RoleId == -1) + { + _RoleName = DotNetNuke.Common.Globals.glbRoleAllUsersName; + } + } + return _RoleName; + } + set + { + _RoleName = value; + } + } + + public string PermissionKey { get; set; } + #endregion + + #region Public Methods + public override bool Equals(object obj) + { + if (obj is null | !ReferenceEquals(GetType(), obj.GetType())) + { + return false; + } + BlogPermissionInfo perm = (BlogPermissionInfo)obj; + return AllowAccess == perm.AllowAccess & Expires > DateTime.Now & BlogId == perm.BlogId & RoleId == perm.RoleId & UserId == perm.UserId & PermissionId == perm.PermissionId; + } + + public BlogPermissionInfo Clone() + { + var res = new BlogPermissionInfo(); + res.AllowAccess = AllowAccess; + res.DisplayName = DisplayName; + res.BlogId = BlogId; + res.Expires = Expires; + res.PermissionId = PermissionId; + res.PermissionKey = PermissionKey; + res.RoleId = RoleId; + res.RoleName = RoleName; + res.UserId = UserId; + res.Username = Username; + return res; + } + + public void ReadXml(XmlNode xN) + { + + var ht = new Hashtable(); + foreach (XmlNode n in xN.ChildNodes) + ht.Add(n.Name, n.InnerText); + int argVariable = PermissionId; + Extensions.ReadValue(ref ht, "PermissionId", ref argVariable); + PermissionId = argVariable; + bool argVariable1 = AllowAccess; + Extensions.ReadValue(ref ht, "AllowAccess", ref argVariable1); + AllowAccess = argVariable1; + string argVariable2 = PermissionKey; + Extensions.ReadValue(ref ht, "PermissionKey", ref argVariable2); + PermissionKey = argVariable2; + int argVariable3 = RoleId; + Extensions.ReadValue(ref ht, "RoleID", ref argVariable3); + RoleId = argVariable3; + int argVariable4 = UserId; + Extensions.ReadValue(ref ht, "UserID", ref argVariable4); + UserId = argVariable4; + string argVariable5 = RoleName; + Extensions.ReadValue(ref ht, "RoleName", ref argVariable5); + RoleName = argVariable5; + string argVariable6 = Username; + Extensions.ReadValue(ref ht, "UserName", ref argVariable6); + Username = argVariable6; + + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Security/Permissions/BlogPermissionInfo_Interfaces.cs b/Server/Core/Security/Permissions/BlogPermissionInfo_Interfaces.cs new file mode 100644 index 00000000..10826fe2 --- /dev/null +++ b/Server/Core/Security/Permissions/BlogPermissionInfo_Interfaces.cs @@ -0,0 +1,328 @@ +using System; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Security.Permissions +{ + + [Serializable()] + [XmlRoot("BlogPermission")] + [DataContract()] + public partial class BlogPermissionInfo : IHydratable, IPropertyAccess, IXmlSerializable + { + + #region IHydratable Implementation + /// ----------------------------------------------------------------------------- + /// + /// Fill hydrates the object from a Datareader + /// + /// The Fill method is used by the CBO method to hydrtae the object + /// rather than using the more expensive Refection methods. + /// + /// [pdonker] 02/08/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void Fill(IDataReader dr) + { + + AllowAccess = Convert.ToBoolean(Null.SetNull(dr["AllowAccess"], AllowAccess)); + BlogId = Convert.ToInt32(Null.SetNull(dr["BlogId"], BlogId)); + Expires = Conversions.ToDate(Null.SetNull(dr["Expires"], Expires)); + PermissionId = Convert.ToInt32(Null.SetNull(dr["PermissionId"], PermissionId)); + RoleId = Convert.ToInt32(Null.SetNull(dr["RoleId"], RoleId)); + UserId = Convert.ToInt32(Null.SetNull(dr["UserId"], UserId)); + Username = Convert.ToString(Null.SetNull(dr["Username"], Username)); + DisplayName = Convert.ToString(Null.SetNull(dr["DisplayName"], DisplayName)); + RoleName = Convert.ToString(Null.SetNull(dr["RoleName"], RoleName)); + + } + /// ----------------------------------------------------------------------------- + /// + /// Gets and sets the Key ID + /// + /// The KeyID property is part of the IHydratble interface. It is used + /// as the key property when creating a Dictionary + /// + /// [pdonker] 02/08/2013 Created + /// + /// ----------------------------------------------------------------------------- + public int KeyID + { + get + { + return default; + } + set + { + } + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + switch (strPropertyName.ToLower() ?? "") + { + case "allowaccess": + { + return PropertyAccess.Boolean2LocalizedYesNo(AllowAccess, formatProvider); + } + case "blogid": + { + return BlogId.ToString(OutputFormat, formatProvider); + } + case "expires": + { + return Expires.ToString(OutputFormat, formatProvider); + } + case "permissionid": + { + return PermissionId.ToString(OutputFormat, formatProvider); + } + case "roleid": + { + return RoleId.ToString(OutputFormat, formatProvider); + } + case "userid": + { + return UserId.ToString(OutputFormat, formatProvider); + } + case "username": + { + return PropertyAccess.FormatString(Username, strFormat); + } + case "displayname": + { + return PropertyAccess.FormatString(DisplayName, strFormat); + } + case "rolename": + { + return PropertyAccess.FormatString(RoleName, strFormat); + } + + default: + { + PropertyNotFound = true; + break; + } + } + + return Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + #region IXmlSerializable Implementation + /// ----------------------------------------------------------------------------- + /// + /// GetSchema returns the XmlSchema for this class + /// + /// GetSchema is implemented as a stub method as it is not required + /// + /// [pdonker] 02/08/2013 Created + /// + /// ----------------------------------------------------------------------------- + public XmlSchema GetSchema() + { + return null; + } + + private string readElement(XmlReader reader, string ElementName) + { + if (!(reader.NodeType == XmlNodeType.Element) || (reader.Name ?? "") != (ElementName ?? "")) + { + reader.ReadToFollowing(ElementName); + } + if (reader.NodeType == XmlNodeType.Element) + { + return reader.ReadElementContentAsString(); + } + else + { + return ""; + } + } + + /// ----------------------------------------------------------------------------- + /// + /// ReadXml fills the object (de-serializes it) from the XmlReader passed + /// + /// + /// The XmlReader that contains the xml for the object + /// + /// [pdonker] 02/08/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void ReadXml(XmlReader reader) + { + try + { + + bool argresult = AllowAccess; + bool.TryParse(readElement(reader, "AllowAccess"), out argresult); + AllowAccess = argresult; + bool localTryParse() { int argresult = BlogId; var ret = int.TryParse(readElement(reader, "BlogId"), out argresult); BlogId = argresult; return ret; } + + if (!localTryParse()) + { + BlogId = Null.NullInteger; + } + var argresult1 = Expires; + DateTime.TryParse(readElement(reader, "Expires"), out argresult1); + Expires = argresult1; + bool localTryParse1() { int argresult1 = PermissionId; var ret = int.TryParse(readElement(reader, "PermissionId"), out argresult1); PermissionId = argresult1; return ret; } + + if (!localTryParse1()) + { + PermissionId = Null.NullInteger; + } + bool localTryParse2() { int argresult2 = RoleId; var ret = int.TryParse(readElement(reader, "RoleId"), out argresult2); RoleId = argresult2; return ret; } + + if (!localTryParse2()) + { + RoleId = Null.NullInteger; + } + bool localTryParse3() { int argresult3 = UserId; var ret = int.TryParse(readElement(reader, "UserId"), out argresult3); UserId = argresult3; return ret; } + + if (!localTryParse3()) + { + UserId = Null.NullInteger; + } + Username = readElement(reader, "Username"); + DisplayName = readElement(reader, "DisplayName"); + RoleName = readElement(reader, "RoleName"); + } + catch (Exception ex) + { + // log exception as DNN import routine does not do that + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + // re-raise exception to make sure import routine displays a visible error to the user + throw new Exception("An error occured during import of an BlogPermission", ex); + } + + } + + /// ----------------------------------------------------------------------------- + /// + /// WriteXml converts the object to Xml (serializes it) and writes it using the XmlWriter passed + /// + /// + /// The XmlWriter that contains the xml for the object + /// + /// [pdonker] 02/08/2013 Created + /// + /// ----------------------------------------------------------------------------- + public void WriteXml(XmlWriter writer) + { + writer.WriteStartElement("BlogPermission"); + writer.WriteElementString("AllowAccess", AllowAccess.ToString()); + writer.WriteElementString("BlogId", BlogId.ToString()); + writer.WriteElementString("Expires", Expires.ToString()); + writer.WriteElementString("PermissionId", PermissionId.ToString()); + writer.WriteElementString("RoleId", RoleId.ToString()); + writer.WriteElementString("UserId", UserId.ToString()); + writer.WriteElementString("Username", Username); + writer.WriteElementString("DisplayName", DisplayName); + writer.WriteElementString("RoleName", RoleName); + writer.WriteEndElement(); + } + #endregion + + #region ToXml Methods + public string ToXml() + { + return ToXml("BlogPermission"); + } + + public string ToXml(string elementName) + { + var xml = new StringBuilder(); + xml.Append("<"); + xml.Append(elementName); + AddAttribute(ref xml, "AllowAccess", AllowAccess.ToString()); + AddAttribute(ref xml, "BlogId", BlogId.ToString()); + AddAttribute(ref xml, "Expires", Expires.ToString()); + AddAttribute(ref xml, "PermissionId", PermissionId.ToString()); + AddAttribute(ref xml, "RoleId", RoleId.ToString()); + AddAttribute(ref xml, "UserId", UserId.ToString()); + AddAttribute(ref xml, "Username", Username); + AddAttribute(ref xml, "DisplayName", DisplayName); + AddAttribute(ref xml, "RoleName", RoleName); + AddAttribute(ref xml, "AllowAccess", AllowAccess.ToString()); + AddAttribute(ref xml, "BlogId", BlogId.ToString()); + AddAttribute(ref xml, "Expires", Expires.ToUniversalTime().ToString("u")); + AddAttribute(ref xml, "PermissionId", PermissionId.ToString()); + AddAttribute(ref xml, "RoleId", RoleId.ToString()); + AddAttribute(ref xml, "UserId", UserId.ToString()); + AddAttribute(ref xml, "Username", Username); + AddAttribute(ref xml, "DisplayName", DisplayName); + AddAttribute(ref xml, "RoleName", RoleName); + xml.Append(" />"); + return xml.ToString(); + } + + private void AddAttribute(ref StringBuilder xml, string attributeName, string attributeValue) + { + xml.Append(" " + attributeName); + xml.Append("=\"" + attributeValue + "\""); + } + #endregion + + #region JSON Serialization + public void WriteJSON(ref Stream s) + { + var ser = new DataContractJsonSerializer(typeof(BlogPermissionInfo)); + ser.WriteObject(s, this); + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Security/Permissions/BlogPermissionInfo_Properties.cs b/Server/Core/Security/Permissions/BlogPermissionInfo_Properties.cs new file mode 100644 index 00000000..142a7409 --- /dev/null +++ b/Server/Core/Security/Permissions/BlogPermissionInfo_Properties.cs @@ -0,0 +1,54 @@ +using System; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; + +namespace DotNetNuke.Modules.Blog.Security.Permissions +{ + public partial class BlogPermissionInfo + { + + #region Private Members + #endregion + + #region Public Properties + [DataMember()] + public bool AllowAccess { get; set; } + [DataMember()] + public int BlogId { get; set; } + [DataMember()] + public DateTime Expires { get; set; } + [DataMember()] + public int PermissionId { get; set; } + [DataMember()] + public int RoleId { get; set; } + [DataMember()] + public int UserId { get; set; } + [DataMember()] + public string Username { get; set; } + [DataMember()] + public string DisplayName { get; set; } + // + // Public Property RoleName() As String + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Security/Permissions/BlogPermissionsController.cs b/Server/Core/Security/Permissions/BlogPermissionsController.cs new file mode 100644 index 00000000..6f084e70 --- /dev/null +++ b/Server/Core/Security/Permissions/BlogPermissionsController.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.Data; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Users; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using static DotNetNuke.Modules.Blog.Security.Security; + +namespace DotNetNuke.Modules.Blog.Security.Permissions +{ + public partial class BlogPermissionsController + { + + #region Public Methods + public static bool HasBlogPermission(BlogPermissionCollection objBlogPermissions, int PermissionId) + { + if (BlogUser.GetCurrentUser().IsAdministrator) + return true; + var m = objBlogPermissions; + int i; + var loopTo = m.Count - 1; + for (i = 0; i <= loopTo; i++) + { + BlogPermissionInfo mp; + mp = m[i]; + if (mp.PermissionId == PermissionId && DotNetNuke.Security.PortalSecurity.IsInRoles(mp.RoleName) | (Framework.ServiceLocator.Instance.GetCurrentUserInfo().Username ?? "") == (mp.Username ?? "") & mp.UserId != glbUserNothing && mp.Expires > DateTime.Now | mp.Expires == DateTime.MinValue) + { + return true; + } + } + return false; + } + + public static bool HasBlogPermission(BlogPermissionCollection objBlogPermissions, string PermissionKey) + { + if (BlogUser.GetCurrentUser().IsAdministrator) + return true; + var m = objBlogPermissions; + int i; + var loopTo = m.Count - 1; + for (i = 0; i <= loopTo; i++) + { + BlogPermissionInfo mp; + mp = m[i]; + if ((mp.PermissionKey ?? "") == (PermissionKey ?? "") && DotNetNuke.Security.PortalSecurity.IsInRoles(mp.RoleName) | (Framework.ServiceLocator.Instance.GetCurrentUserInfo().Username ?? "") == (mp.Username ?? "") & mp.UserId != glbUserNothing && mp.Expires > DateTime.Now | mp.Expires == DateTime.MinValue) + { + return true; + } + } + return false; + } + + public static bool HasBlogPermission(BlogPermissionCollection objBlogPermissions, string PermissionKey, UserInfo User) + { + if (BlogUser.GetUser(User).IsAdministrator) + return true; + var m = objBlogPermissions; + int i; + var loopTo = m.Count - 1; + for (i = 0; i <= loopTo; i++) + { + BlogPermissionInfo mp; + mp = m[i]; + if ((mp.PermissionKey ?? "") == (PermissionKey ?? "") && User.IsInRole(mp.RoleName) | (User.Username ?? "") == (mp.Username ?? "") & mp.UserId != glbUserNothing && mp.Expires > DateTime.Now | mp.Expires == DateTime.MinValue) + { + return true; + } + } + return false; + } + + public static BlogPermissionCollection GetBlogPermissionsCollection(int BlogId) + { + + var epc = new BlogPermissionCollection(); + if (BlogId > 0) + { + using (var ir = Data.DataProvider.Instance().GetBlogPermissionsByBlog(BlogId)) + { + while (ir.Read()) + epc.Add(FillBlogPermissionInfo(ir, false, false)); + } + } + return epc; + + } + + public static void DeleteBlogPermissionsByBlogId(int BlogId) + { + + Data.DataProvider.Instance().DeleteBlogPermissions(BlogId); + + } + + public static void UpdateBlogPermissions(BlogInfo Blog) + { + DeleteBlogPermissionsByBlogId(Blog.BlogID); + foreach (BlogPermissionInfo objBlogPermission in Blog.Permissions) + { + objBlogPermission.BlogId = Blog.BlogID; + if (objBlogPermission.AllowAccess) + { + try + { + AddBlogPermission(objBlogPermission); + } + catch + { + } + } + } + } + + public static Dictionary GetUsersByBlogPermission(int portalId, int blogId, int permissionId) + { + return CBO.FillDictionary("username", Data.DataProvider.Instance().GetUsersByBlogPermission(portalId, blogId, permissionId)); + } + public static Dictionary GetUsersByBlogPermission(int portalId, int blogId, string permission) + { + return CBO.FillDictionary("username", Data.DataProvider.Instance().GetUsersByBlogPermission(portalId, blogId, GetPermissionId(permission))); + } + + public static int GetPermissionId(string permission) + { + switch (permission.ToUpper() ?? "") + { + case "ADD": + { + return (int)BlogPermissionTypes.ADD; + } + case "ADDCOMMENT": + { + return (int)BlogPermissionTypes.ADDCOMMENT; + } + case "APPROVE": + { + return (int)BlogPermissionTypes.APPROVE; + } + case "APPROVECOMMENT": + { + return (int)BlogPermissionTypes.APPROVECOMMENT; + } + case "AUTOAPPROVECOMMENT": + { + return (int)BlogPermissionTypes.AUTOAPPROVECOMMENT; + } + case "EDIT": + { + return (int)BlogPermissionTypes.EDIT; + } + + default: + { + return -1; + } + } + } + #endregion + + #region Fill Methods + private static BlogPermissionInfo FillBlogPermissionInfo(IDataReader dr) + { + return FillBlogPermissionInfo(dr, true, true); + } + + private static BlogPermissionInfo FillBlogPermissionInfo(IDataReader dr, bool CheckForOpenDataReader, bool CloseReader) + { + + var objBlogPermission = new BlogPermissionInfo(); + bool canContinue = true; + if (CheckForOpenDataReader) + { + canContinue = false; + if (dr.Read()) + { + canContinue = true; + } + } + if (canContinue) + { + { + ref var withBlock = ref objBlogPermission; + withBlock.AllowAccess = Convert.ToBoolean(Null.SetNull(dr["AllowAccess"], objBlogPermission.AllowAccess)); + withBlock.DisplayName = Convert.ToString(Null.SetNull(dr["DisplayName"], objBlogPermission.DisplayName)); + withBlock.BlogId = Convert.ToInt32(Null.SetNull(dr["BlogId"], objBlogPermission.BlogId)); + withBlock.Expires = Convert.ToDateTime(Null.SetNull(dr["Expires"], objBlogPermission.Expires)); + withBlock.PermissionId = Convert.ToInt32(Null.SetNull(dr["PermissionId"], objBlogPermission.PermissionId)); + switch (withBlock.PermissionId) + { + case (int)BlogPermissionTypes.ADD: + { + withBlock.PermissionKey = "ADD"; + break; + } + case (int)BlogPermissionTypes.EDIT: + { + withBlock.PermissionKey = "EDIT"; + break; + } + case (int)BlogPermissionTypes.APPROVE: + { + withBlock.PermissionKey = "APPROVE"; + break; + } + case (int)BlogPermissionTypes.ADDCOMMENT: + { + withBlock.PermissionKey = "ADDCOMMENT"; + break; + } + case (int)BlogPermissionTypes.APPROVECOMMENT: + { + withBlock.PermissionKey = "APPROVECOMMENT"; + break; + } + case (int)BlogPermissionTypes.AUTOAPPROVECOMMENT: + { + withBlock.PermissionKey = "AUTOAPPROVECOMMENT"; + break; + } + } + withBlock.RoleId = Convert.ToInt32(Null.SetNull(dr["RoleID"], objBlogPermission.RoleId)); + if (withBlock.RoleId > -1) + { + string rn = Convert.ToString(Null.SetNull(dr["RoleName"], "")); + withBlock.RoleName = rn; + } + withBlock.UserId = Convert.ToInt32(Null.SetNull(dr["UserID"], objBlogPermission.UserId)); + withBlock.Username = Convert.ToString(Null.SetNull(dr["UserName"], objBlogPermission.Username)); + } + } + else + { + objBlogPermission = null; + } + + if (CloseReader) + { + dr.Close(); + } + + return objBlogPermission; + + } + + #endregion + + } + + + +} \ No newline at end of file diff --git a/Server/Core/Security/Permissions/BlogPermissionsController_CRUD.cs b/Server/Core/Security/Permissions/BlogPermissionsController_CRUD.cs new file mode 100644 index 00000000..b730ea64 --- /dev/null +++ b/Server/Core/Security/Permissions/BlogPermissionsController_CRUD.cs @@ -0,0 +1,40 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + + +using DotNetNuke.Modules.Blog.Data; + +namespace DotNetNuke.Modules.Blog.Security.Permissions +{ + + public partial class BlogPermissionsController + { + + public static void AddBlogPermission(BlogPermissionInfo objBlogPermission) + { + + DataProvider.Instance().AddBlogPermission(objBlogPermission.AllowAccess, objBlogPermission.BlogId, objBlogPermission.Expires, objBlogPermission.PermissionId, objBlogPermission.RoleId, objBlogPermission.UserId); + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Security/Permissions/PermissionCollection.cs b/Server/Core/Security/Permissions/PermissionCollection.cs new file mode 100644 index 00000000..cb737bb7 --- /dev/null +++ b/Server/Core/Security/Permissions/PermissionCollection.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections; +using System.Collections.Generic; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using static DotNetNuke.Modules.Blog.Security.Security; + +namespace DotNetNuke.Modules.Blog.Security.Permissions +{ + + [Serializable()] + public class PermissionCollection : IDictionary + { + + private Dictionary _permissions = new Dictionary(); + private SortedDictionary _keys = new SortedDictionary(); + + public PermissionCollection() + { + Add("ADD", new PermissionInfo() { PermissionId = (int)BlogPermissionTypes.ADD, PermissionKey = "ADD" }); + Add("EDIT", new PermissionInfo() { PermissionId = (int)BlogPermissionTypes.EDIT, PermissionKey = "EDIT" }); + Add("APPROVE", new PermissionInfo() { PermissionId = (int)BlogPermissionTypes.APPROVE, PermissionKey = "APPROVE" }); + Add("VIEWCOMMENT", new PermissionInfo() { PermissionId = (int)BlogPermissionTypes.VIEWCOMMENT, PermissionKey = "VIEWCOMMENT" }); + Add("ADDCOMMENT", new PermissionInfo() { PermissionId = (int)BlogPermissionTypes.ADDCOMMENT, PermissionKey = "ADDCOMMENT" }); + Add("APPROVECOMMENT", new PermissionInfo() { PermissionId = (int)BlogPermissionTypes.APPROVECOMMENT, PermissionKey = "APPROVECOMMENT" }); + Add("AUTOAPPROVECOMMENT", new PermissionInfo() { PermissionId = (int)BlogPermissionTypes.AUTOAPPROVECOMMENT, PermissionKey = "AUTOAPPROVECOMMENT" }); + } + + public PermissionInfo GetById(int id) + { + switch (id) + { + case (int)BlogPermissionTypes.ADD: + { + return this["ADD"]; + } + case (int)BlogPermissionTypes.EDIT: + { + return this["EDIT"]; + } + case (int)BlogPermissionTypes.APPROVE: + { + return this["APPROVE"]; + } + case (int)BlogPermissionTypes.ADDCOMMENT: + { + return this["ADDCOMMENT"]; + } + case (int)BlogPermissionTypes.APPROVECOMMENT: + { + return this["APPROVECOMMENT"]; + } + case (int)BlogPermissionTypes.AUTOAPPROVECOMMENT: + { + return this["AUTOAPPROVECOMMENT"]; + } + case (int)BlogPermissionTypes.VIEWCOMMENT: + { + return this["VIEWCOMMENT"]; + } + } + return null; + } + + public void Add(KeyValuePair item) + { + if (!ContainsKey(item.Key)) + { + _permissions.Add(item.Key, item.Value); + _keys.Add(_permissions.Count - 1, item.Key); + } + } + + public void Clear() + { + _permissions.Clear(); + _keys.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return _permissions.ContainsValue(item.Value); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + // todo + } + + public int Count + { + get + { + return _permissions.Count; + } + } + + public bool IsReadOnly + { + get + { + return false; + } + } + + public bool Remove(KeyValuePair item) + { + if (_permissions.ContainsKey(item.Key)) + { + _permissions.Remove(item.Key); + return true; + } + return false; + } + + public void Add(string key, PermissionInfo value) + { + if (!_permissions.ContainsKey(key)) + { + _permissions.Add(key, value); + _keys.Add(_permissions.Count - 1, key); + } + } + + public bool ContainsKey(string key) + { + return _permissions.ContainsKey(key); + } + + public PermissionInfo this[string key] + { + get + { + return _permissions[key]; + } + set + { + _permissions[key] = value; + } + } + + public PermissionInfo this[int index] + { + get + { + return this[_keys[index]]; + } + set + { + this[_keys[index]] = value; + } + } + + public ICollection Keys + { + get + { + return _keys.Values; + } + } + + public bool Remove(string key) + { + if (_permissions.ContainsKey(key)) + { + _permissions.Remove(key); + return true; + } + return false; + } + + public bool TryGetValue(string key, out PermissionInfo value) + { + return _permissions.TryGetValue(key, out value); + } + + public ICollection Values + { + get + { + return _permissions.Values; + } + } + + public IEnumerator> GetEnumerator() + { + return null; + } + + public IEnumerator GetEnumerator1() + { + return null; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator1(); + + } +} \ No newline at end of file diff --git a/Server/Core/Security/Permissions/PermissionInfo_Properties.cs b/Server/Core/Security/Permissions/PermissionInfo_Properties.cs new file mode 100644 index 00000000..2bbdaa89 --- /dev/null +++ b/Server/Core/Security/Permissions/PermissionInfo_Properties.cs @@ -0,0 +1,53 @@ +using System; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Runtime.Serialization; + +namespace DotNetNuke.Modules.Blog.Security.Permissions +{ + [Serializable()] + public partial class PermissionInfo + { + + #region Private Members + #endregion + + #region Constructors + public PermissionInfo() + { + } + + public PermissionInfo(int PermissionId, string PermissionKey) + { + this.PermissionId = PermissionId; + this.PermissionKey = PermissionKey; + } + #endregion + + #region Public Properties + [DataMember()] + public int PermissionId { get; set; } + [DataMember()] + public string PermissionKey { get; set; } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Security/Permissions/PermissionsController.cs b/Server/Core/Security/Permissions/PermissionsController.cs new file mode 100644 index 00000000..dd1ef802 --- /dev/null +++ b/Server/Core/Security/Permissions/PermissionsController.cs @@ -0,0 +1,47 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +namespace DotNetNuke.Modules.Blog.Security.Permissions +{ + public class PermissionsController + { + + public static PermissionCollection GetPermissions() + { + + string CacheKey = "BlogPermissions"; + PermissionCollection bp = (PermissionCollection)DotNetNuke.Common.Utilities.DataCache.GetCache(CacheKey); + if (bp is null) + { + bp = new PermissionCollection(); + DotNetNuke.Common.Utilities.DataCache.SetCache(CacheKey, bp); + } + return bp; + + } + + public static PermissionInfo GetPermission(int permissionId) + { + return GetPermissions().GetById(permissionId); + } + + } +} \ No newline at end of file diff --git a/Server/Core/Security/Security.cs b/Server/Core/Security/Security.cs new file mode 100644 index 00000000..05458922 --- /dev/null +++ b/Server/Core/Security/Security.cs @@ -0,0 +1,42 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +namespace DotNetNuke.Modules.Blog.Security +{ + public class Security + { + + public enum BlogPermissionTypes + { + EDIT = 0, + ADD = 1, + APPROVE = 2, + ADDCOMMENT = 3, + APPROVECOMMENT = 4, + VIEWCOMMENT = 5, + AUTOAPPROVECOMMENT = 6 + } + + public const int glbRoleNothing = -4; + public const int glbUserNothing = -10; + + } +} \ No newline at end of file diff --git a/Server/Core/Services/BlogAuthorizeAttribute.cs b/Server/Core/Services/BlogAuthorizeAttribute.cs new file mode 100644 index 00000000..3bb75b4f --- /dev/null +++ b/Server/Core/Services/BlogAuthorizeAttribute.cs @@ -0,0 +1,165 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Threading; +using System.Web; +using DotNetNuke.Common; +using DotNetNuke.Entities.Users; +using DotNetNuke.Modules.Blog.Common; +using DotNetNuke.Modules.Blog.Entities.Blogs; + +using DotNetNuke.Modules.Blog.Security; +using DotNetNuke.Services.Social.Notifications; + +using DotNetNuke.Web.Api; + +namespace DotNetNuke.Modules.Blog.Services +{ + + #region Security Access Levels + public enum SecurityAccessLevel : int + { + Anonymous = 0, + Admin = 1, + ViewModule = 2, + EditModule = 4, + AddPost = 8, + EditPost = 16, + ApprovePost = 32, + AddComment = 64, + ApproveComment = 128, + Blogger = 256, + Owner = 512 + } + #endregion + + public class BlogAuthorizeAttribute : AuthorizeAttributeBase, IOverrideDefaultAuthLevel + { + + #region Properties + public int BlogId { get; set; } = -1; + public int NotificationId { get; set; } = -1; + public SecurityAccessLevel AccessLevel { get; set; } + public UserInfo UserInfo { get; set; } + public ContextSecurity Security { get; set; } + #endregion + + #region Constructors + public BlogAuthorizeAttribute() + { + AccessLevel = SecurityAccessLevel.Admin; + } + + public BlogAuthorizeAttribute(SecurityAccessLevel accessLevel) + { + AccessLevel = accessLevel; + } + #endregion + + #region Public Methods + public override bool IsAuthorized(AuthFilterContext context) + { + + if (AccessLevel == SecurityAccessLevel.Anonymous) + return true; // save time by not going through the code below + + int argVariable = BlogId; + Extensions.ReadValue(ref HttpContext.Current.Request.Params, "blogId", ref argVariable); + BlogId = argVariable; + int argVariable1 = NotificationId; + Extensions.ReadValue(ref HttpContext.Current.Request.Params, "NotificationId", ref argVariable1); + NotificationId = argVariable1; + int moduleId = context.ActionContext.Request.FindModuleId(); + int tabId = context.ActionContext.Request.FindTabId(); + if (!HttpContextSource.Current.Request.IsAuthenticated) + { + UserInfo = new UserInfo(); + } + else + { + var portalSettings = Framework.ServiceLocator.Instance.GetCurrentPortalSettings(); + UserInfo = UserController.GetCachedUser(portalSettings.PortalId, HttpContextSource.Current.User.Identity.Name); + if (UserInfo is null) + UserInfo = new UserInfo(); + } + if (NotificationId > -1) + { + var notify = Framework.ServiceLocator.Instance.GetNotification(NotificationId); + var nKey = new Integration.NotificationKey(notify.Context); + BlogId = nKey.BlogId; + moduleId = nKey.ModuleId; + } + var blog = BlogsController.GetBlog(BlogId, UserInfo.UserID, Thread.CurrentThread.CurrentCulture.Name); + if (blog is null) + return false; + Security = new ContextSecurity(moduleId, tabId, blog, UserInfo); + + if ((AccessLevel & SecurityAccessLevel.Admin) == SecurityAccessLevel.Admin && Security.UserIsAdmin) + { + return true; + } + else if ((AccessLevel & SecurityAccessLevel.ViewModule) == SecurityAccessLevel.ViewModule && DotNetNuke.Security.Permissions.ModulePermissionController.CanViewModule(context.ActionContext.Request.FindModuleInfo())) + { + return true; + } + else if ((AccessLevel & SecurityAccessLevel.EditModule) == SecurityAccessLevel.EditModule && DotNetNuke.Security.Permissions.ModulePermissionController.HasModulePermission(context.ActionContext.Request.FindModuleInfo().ModulePermissions, "EDIT")) + { + return true; + } + else if ((AccessLevel & SecurityAccessLevel.AddPost) == SecurityAccessLevel.AddPost && Security.CanAddPost) + { + return true; + } + else if ((AccessLevel & SecurityAccessLevel.EditPost) == SecurityAccessLevel.EditPost && Security.CanEditPost) + { + return true; + } + else if ((AccessLevel & SecurityAccessLevel.ApprovePost) == SecurityAccessLevel.ApprovePost && Security.CanApprovePost) + { + return true; + } + else if ((AccessLevel & SecurityAccessLevel.AddComment) == SecurityAccessLevel.AddComment && Security.CanAddComment) + { + return true; + } + else if ((AccessLevel & SecurityAccessLevel.ApproveComment) == SecurityAccessLevel.ApproveComment && Security.CanApproveComment) + { + return true; + } + else if ((AccessLevel & SecurityAccessLevel.Blogger) == SecurityAccessLevel.Blogger && Security.IsBlogger) + { + return true; + } + else if ((AccessLevel & SecurityAccessLevel.Owner) == SecurityAccessLevel.Owner && Security.IsOwner) + { + return true; + } + + return false; + + } + #endregion + + #region Private Methods + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Services/BlogRouteMapper.cs b/Server/Core/Services/BlogRouteMapper.cs new file mode 100644 index 00000000..03a58ae9 --- /dev/null +++ b/Server/Core/Services/BlogRouteMapper.cs @@ -0,0 +1,80 @@ +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Web; +using DotNetNuke.Web.Api; + +namespace DotNetNuke.Modules.Blog.Services +{ + + public class BlogRouteMapper : IServiceRouteMapper + { + + public enum ServiceControllers + { + Blogs, + Comments, + Posts, + Terms + } + + public const string ServicePath = "~/DesktopModules/Blog/API/"; + + public void RegisterRoutes(IMapRoute mapRouteManager) + { + mapRouteManager.MapHttpRoute("Blog", "Blogs", "Blogs/{action}", new { Controller = "Blogs" }, new string[] { "DotNetNuke.Modules.Blog.Entities.Blogs" }); + mapRouteManager.MapHttpRoute("Blog", "Comments", "Comments/{action}", new { Controller = "Comments" }, new string[] { "DotNetNuke.Modules.Blog.Entities.Comments" }); + mapRouteManager.MapHttpRoute("Blog", "Posts", "Posts/{action}", new { Controller = "Posts" }, new string[] { "DotNetNuke.Modules.Blog.Entities.Posts" }); + mapRouteManager.MapHttpRoute("Blog", "Terms", "Terms/{action}", new { Controller = "Terms" }, new string[] { "DotNetNuke.Modules.Blog.Entities.Terms" }); + mapRouteManager.MapHttpRoute("Blog", "Other", "{controller}/{action}", new string[] { "DotNetNuke.Modules.Blog.Services", "DotNetNuke.Modules.Blog.Integration.Services" }); + } + + public static string GetRoute(ServiceControllers controller, string @method) + { + switch (controller) + { + case ServiceControllers.Blogs: + { + return GetRoute("Blogs", @method); + } + case ServiceControllers.Comments: + { + return GetRoute("Comments", @method); + } + case ServiceControllers.Posts: + { + return GetRoute("Posts", @method); + } + + default: + { + return GetRoute("Terms", @method); + } + } + } + + public static string GetRoute(string controller, string @method) + { + return HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Host + DotNetNuke.Common.Globals.ResolveUrl(ServicePath + controller + "/" + @method); + } + + } + +} \ No newline at end of file diff --git a/Server/Core/Services/ModulesController.cs b/Server/Core/Services/ModulesController.cs new file mode 100644 index 00000000..47d91401 --- /dev/null +++ b/Server/Core/Services/ModulesController.cs @@ -0,0 +1,174 @@ +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Net; +using System.Net.Http; +using System.Text; +using System.Web.Http; +using System.Xml; +using DotNetNuke.Entities.Modules; +using DotNetNuke.Modules.Blog.Common; +using DotNetNuke.Web.Api; + +namespace DotNetNuke.Modules.Blog.Services +{ + + public class ModulesController : DnnApiController + { + + public class AddModuleDTO + { + public string paneName { get; set; } + public int position { get; set; } + public string title { get; set; } + public string template { get; set; } + } + + #region Private Members + #endregion + + #region Service Methods + [HttpPost()] + [DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.Edit)] + [ValidateAntiForgeryToken()] + [ActionName("Add")] + public HttpResponseMessage AddModule(AddModuleDTO postData) + { + + var newSettings = new ViewSettings(ActiveModule.TabModuleID); + newSettings.BlogModuleId = ActiveModule.ModuleID; + newSettings.Template = postData.template; + + var objModule = new ModuleInfo(); + objModule.Initialize(PortalSettings.PortalId); + objModule.PortalID = PortalSettings.PortalId; + objModule.TabID = PortalSettings.ActiveTab.TabID; + objModule.ModuleOrder = postData.position; + if (string.IsNullOrEmpty(postData.title)) + { + objModule.ModuleTitle = "Blog"; + } + else + { + objModule.ModuleTitle = postData.title; + } + objModule.PaneName = postData.paneName; + objModule.ModuleDefID = ActiveModule.ModuleDefID; + objModule.InheritViewPermissions = true; + objModule.AllTabs = false; + objModule.Alignment = ""; + + var objModules = new ModuleController(); + objModule.ModuleID = objModules.AddModule(objModule); + newSettings.UpdateSettings(objModule.TabModuleID); + + return Request.CreateResponse(HttpStatusCode.OK, new { Result = "success" }); + + } + + [HttpGet()] + [AllowAnonymous()] + [ActionName("Manifest")] + public HttpResponseMessage GetManifest() + { + + var res = new HttpResponseMessage(HttpStatusCode.OK); + + using (var @out = new StringWriterWithEncoding(Encoding.UTF8)) + { + using (var output = new XmlTextWriter(out)) + { + var bs = ModuleSettings.GetModuleSettings(ActiveModule.ModuleID); + + output.Formatting = Formatting.Indented; + output.WriteStartDocument(); + output.WriteStartElement("manifest"); + output.WriteAttributeString("xmlns", "http://schemas.microsoft.com/wlw/manifest/weblog"); + output.WriteStartElement("options"); + + output.WriteElementString("clientType", "Metaweblog"); + output.WriteElementString("supportsMultipleCategories", bs.AllowMultipleCategories.ToYesNo()); + output.WriteElementString("supportsCategories", (bs.VocabularyId != -1).ToYesNo()); + output.WriteElementString("supportsCustomDate", "Yes"); + output.WriteElementString("supportsKeywords", "Yes"); + output.WriteElementString("supportsTrackbacks", "Yes"); + output.WriteElementString("supportsEmbeds", "No"); + output.WriteElementString("supportsAuthor", "No"); + output.WriteElementString("supportsExcerpt", (bs.SummaryModel == Common.Globals.SummaryType.PlainTextIndependent).ToYesNo()); + output.WriteElementString("supportsPassword", "No"); + output.WriteElementString("supportsPages", "No"); + output.WriteElementString("supportsPageParent", "No"); + output.WriteElementString("supportsPageOrder", "No"); + output.WriteElementString("supportsEmptyTitles", "No"); + output.WriteElementString("supportsExtendedEntries", (bs.SummaryModel == Common.Globals.SummaryType.HtmlPrecedesPost).ToYesNo()); + output.WriteElementString("supportsCommentPolicy", "No"); + output.WriteElementString("supportsPingPolicy", "No"); + output.WriteElementString("supportsPostAsDraft", "Yes"); + output.WriteElementString("supportsFileUpload", "Yes"); + output.WriteElementString("supportsSlug", "No"); + output.WriteElementString("supportsHierarchicalCategories", "Yes"); + output.WriteElementString("supportsCategoriesInline", "Yes"); + output.WriteElementString("supportsNewCategories", "No"); + output.WriteElementString("supportsNewCategoriesInline", "No"); + output.WriteElementString("requiresXHTML", "Yes"); + + output.WriteEndElement(); // options + output.WriteEndElement(); // manifest + output.Flush(); + + } + + res.Content = new StringContent(out.ToString(), Encoding.UTF8, "application/xml"); + + } + + return res; + + } + #endregion + + #region Private Methods + #endregion + + } + + #region Helper Class for Manifest Writing + public class StringWriterWithEncoding : System.IO.StringWriter + { + + private Encoding _Encoding { get; set; } + + public StringWriterWithEncoding(Encoding enc) : base() + { + _Encoding = enc; + } + + public override Encoding Encoding + { + get + { + return _Encoding; + } + } + + } + #endregion + +} \ No newline at end of file diff --git a/Server/Core/Services/RSSController.cs b/Server/Core/Services/RSSController.cs new file mode 100644 index 00000000..2753fd29 --- /dev/null +++ b/Server/Core/Services/RSSController.cs @@ -0,0 +1,58 @@ +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Net; +using System.Net.Http; +using System.Text; +using System.Web; +using System.Web.Http; +using static DotNetNuke.Modules.Blog.Common.Globals; +using DotNetNuke.Modules.Blog.Rss; +using DotNetNuke.Web.Api; + +namespace DotNetNuke.Modules.Blog.Services +{ + + public class RSSController : DnnApiController + { + + #region Private Members + #endregion + + #region Service Methods + [HttpGet()] + [DnnModuleAuthorize(AccessLevel = DotNetNuke.Security.SecurityAccessLevel.View)] + [ActionName("Get")] + public HttpResponseMessage GetRss() + { + var res = new HttpResponseMessage(HttpStatusCode.OK); + var queryString = HttpUtility.ParseQueryString(Request.RequestUri.Query); + var feed = new BlogRssFeed(ActiveModule.ModuleID, queryString); + res.Content = new StringContent(ReadFile(feed.CacheFile), Encoding.UTF8, "application/xml"); + return res; + } + #endregion + + #region Private Methods + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Services/TrackAndPingBackController.cs b/Server/Core/Services/TrackAndPingBackController.cs new file mode 100644 index 00000000..85e9f071 --- /dev/null +++ b/Server/Core/Services/TrackAndPingBackController.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Web; +using DotNetNuke.Modules.Blog.Common; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Modules.Blog.Entities.Posts; + +namespace DotNetNuke.Modules.Blog.Services +{ + public class TrackAndPingBackController + { + + #region Private Members + private static readonly Regex TrackbackLinkRegex = new Regex("trackback:ping=\"([^\"]+)\"", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private static readonly Regex UrlsRegex = new Regex(".*?)[\"'].*?>(?.*?)", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private PostInfo Post { get; set; } = null; + private DotNetNuke.Entities.Portals.PortalSettings PortalSettings { get; set; } = null; + #endregion + + #region TrackbackMessage + public struct TrackbackMessage + { + + #region Properties + public string BlogName { get; set; } + public string Excerpt { get; set; } + public Uri PostUrl { get; set; } + public string Title { get; set; } + public Uri UrlToNotifyTrackback { get; set; } + #endregion + + #region Constructors + public TrackbackMessage(PostInfo post, Uri urlToNotifyTrackback, DotNetNuke.Entities.Portals.PortalSettings portalSettings) + { + Title = post.Title; + PostUrl = new Uri(post.PermaLink(portalSettings)); + Excerpt = post.Summary; + BlogName = post.Blog.Title; + UrlToNotifyTrackback = urlToNotifyTrackback; + } + #endregion + + #region Public Methods + public override string ToString() + { + return string.Format(System.Globalization.CultureInfo.InvariantCulture, "title={0}&url={1}&excerpt={2}&blog_name={3}", Title, PostUrl, Excerpt, BlogName); + } + #endregion + + } + #endregion + + #region Constructors + public TrackAndPingBackController(PostInfo post) + { + Post = post; + PortalSettings = DotNetNuke.Entities.Portals.PortalSettings.Current; + } + #endregion + + #region Public Methods + public void SendTrackAndPingBacks() + { + + if (!Post.Blog.EnableTrackBackSend & !Post.Blog.EnablePingBackSend) + return; + + foreach (Uri url in GetUrlsFromContent(HttpUtility.HtmlDecode(Post.Content))) + { + + bool trackbackSent = false; + if (Post.Blog.EnableTrackBackSend) + { + var remoteFile = new WebPage(url); + string pageContent = remoteFile.GetFileAsString(); + var trackbackUrl = GetTrackBackUrlFromPage(pageContent); + if (trackbackUrl is not null) + { + var message = new TrackbackMessage(Post, trackbackUrl, PortalSettings); + trackbackSent = SendTrackback(message); + } + } + if (!trackbackSent && Post.Blog.EnablePingBackSend) + { + SendPingback(new Uri(Post.PermaLink(PortalSettings)), url); + } + + } + + } + #endregion + + #region Trackback + public bool SendTrackback(TrackbackMessage message) + { + + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(message.UrlToNotifyTrackback); + + request.Credentials = CredentialCache.DefaultNetworkCredentials; + request.Method = "POST"; + request.ContentLength = message.ToString().Length; + request.ContentType = "application/x-www-form-urlencoded"; + request.KeepAlive = false; + request.Timeout = 30000; + + using (var writer = new System.IO.StreamWriter(request.GetRequestStream())) + { + writer.Write(message.ToString()); + } + + bool result = false; + HttpWebResponse response; + try + { + response = (HttpWebResponse)request.GetResponse(); + string answer; + using (var sr = new System.IO.StreamReader(response.GetResponseStream())) + { + answer = sr.ReadToEnd(); + } + result = response.StatusCode == HttpStatusCode.OK && answer.Contains("0"); + } + catch (Exception ex) + { + } + + return result; + + } + #endregion + + #region Pingback + public void SendPingback(Uri sourceUrl, Uri targetUrl) + { + + try + { + + string pingUrl = null; + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(targetUrl); + request.Credentials = CredentialCache.DefaultNetworkCredentials; + using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) + { + foreach (string k in response.Headers.AllKeys) + { + if (k.Equals("x-pingback", StringComparison.OrdinalIgnoreCase) || k.Equals("pingback", StringComparison.OrdinalIgnoreCase)) + { + pingUrl = response.Headers[k]; + } + } + if (string.IsNullOrEmpty(pingUrl)) + { + using (var reader = new System.IO.StreamReader(response.GetResponseStream())) + { + string content = reader.ReadToEnd(); + var m = Regex.Match(content, "]*rel=\"pingback\"[^>]*>|]*rel='pingback'[^>]*>"); + if (m.Success) + { + string link = m.Value; + var m2 = Regex.Match(link, "href=\"(?[^\"]*)\"|href='(?[^']*)'"); + if (m2.Success) + { + pingUrl = m2.Groups["link"].Value.Replace("&", "&"); + } + } + } + } + } + + Uri url = null; + if (!string.IsNullOrEmpty(pingUrl) && Uri.TryCreate(pingUrl, UriKind.Absolute, out url)) + { + request = (HttpWebRequest)WebRequest.Create(url); + request.Method = "POST"; + request.Timeout = 30000; + request.ContentType = "text/xml"; + request.ProtocolVersion = HttpVersion.Version11; + request.Headers["Accept-Language"] = "en-us"; + AddXmlToRequest(sourceUrl, targetUrl, request); + using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) + { + } + } + } + + catch (Exception ex) + { + ex = new Exception(); + } + + } + #endregion + + #region Private Methods + private static Uri GetTrackBackUrlFromPage(string input) + { + string url = TrackbackLinkRegex.Match(input).Groups[1].ToString().Trim(); + Uri uri = null; + return Uri.TryCreate(url, UriKind.Absolute, out uri) ? uri : null; + } + + private static IEnumerable GetUrlsFromContent(string content) + { + var urlsList = new List(); + foreach (Match m in UrlsRegex.Matches(content)) + { + string url = m.Groups["url"].ToString().Trim(); + Uri uri = null; + if (Uri.TryCreate(url, UriKind.Absolute, out uri)) + { + urlsList.Add(uri); + } + } + return urlsList; + } + + private static void AddXmlToRequest(Uri sourceUrl, Uri targetUrl, HttpWebRequest webreqPing) + { + using (var stream = webreqPing.GetRequestStream()) + { + using (var writer = new System.Xml.XmlTextWriter(stream, Encoding.ASCII)) + { + writer.WriteStartDocument(true); + writer.WriteStartElement("methodCall"); + writer.WriteElementString("methodName", "pingback.ping"); + writer.WriteStartElement("params"); + + writer.WriteStartElement("param"); + writer.WriteStartElement("value"); + writer.WriteElementString("string", sourceUrl.ToString()); + writer.WriteEndElement(); + writer.WriteEndElement(); + + writer.WriteStartElement("param"); + writer.WriteStartElement("value"); + writer.WriteElementString("string", targetUrl.ToString()); + writer.WriteEndElement(); + writer.WriteEndElement(); + + writer.WriteEndElement(); + writer.WriteEndElement(); + } + } + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Services/WLW/BlogPostException.cs b/Server/Core/Services/WLW/BlogPostException.cs new file mode 100644 index 00000000..f86606b2 --- /dev/null +++ b/Server/Core/Services/WLW/BlogPostException.cs @@ -0,0 +1,46 @@ +using System; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +namespace DotNetNuke.Modules.Blog.Services.WLW +{ + public class BlogPostException : Exception + { + + private string _resourceKey; + public BlogPostException(string resourceKey, string defaultMessage) : base(defaultMessage) + { + _resourceKey = resourceKey; + } + + public string ResourceKey + { + get + { + return _resourceKey; + } + set + { + _resourceKey = value; + } + } + + } +} \ No newline at end of file diff --git a/Server/Core/Services/WLW/Blogger/IBlogger.cs b/Server/Core/Services/WLW/Blogger/IBlogger.cs new file mode 100644 index 00000000..da466600 --- /dev/null +++ b/Server/Core/Services/WLW/Blogger/IBlogger.cs @@ -0,0 +1,51 @@ + +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2015 +// by DotNetNuke Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using CookComputing.XmlRpc; + +namespace DotNetNuke.Modules.Blog.Services.WLW.Blogger +{ + + /// + /// Interface for Blogger Methods that WLW uses + /// + /// + /// + /// [pdonker] 12/14/2009 created + /// + public interface IBlogger + { + + [XmlRpcMethod("blogger.deletePost", Description = "Deletes a post.")] + bool deletePost(string appKey, string postid, string username, string password, [XmlRpcParameter(Description = "Where applicable, this specifies whether the blog " + "should be republished after the post has been deleted.")] bool publish); + + [XmlRpcMethod("blogger.getUsersBlogs", Description = "Returns information on all the blogs a given user " + "is a member.")] + BlogInfoStruct[] getUsersBlogs(string appKey, string username, string password); + + } + + public struct BlogInfoStruct + { + public string url; + public string blogName; + public string blogid; + } +} \ No newline at end of file diff --git a/Server/Core/Services/WLW/MetaWeblog/IMetaWeblog.cs b/Server/Core/Services/WLW/MetaWeblog/IMetaWeblog.cs new file mode 100644 index 00000000..d4378a1b --- /dev/null +++ b/Server/Core/Services/WLW/MetaWeblog/IMetaWeblog.cs @@ -0,0 +1,288 @@ +using System; +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2015 +// by DotNetNuke Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using CookComputing.XmlRpc; + +namespace DotNetNuke.Modules.Blog.Services.WLW.MetaWeblog +{ + + /// + /// Interface for MetaWeblog methods that WLW uses + /// + /// + /// + /// [pdonker] 12/14/2009 created + /// + public interface IMetaWeblog + { + + [XmlRpcMethod("metaWeblog.editPost", Description = "Updates and existing post to a designated blog using the metaWeblog API. Returns true if completed.")] + bool editPost(string postid, string username, string password, Post post, bool publish); + + [XmlRpcMethod("metaWeblog.getCategories", Description = "Retrieves a list of valid Categories for a post using the metaWeblog API. Returns the metaWeblog Categories struct collection.")] + MetaWebLogCategoryInfo[] getCategories(string blogid, string username, string password); + + [XmlRpcMethod("metaWeblog.getPost", Description = "Retrieves an existing post using the metaWeblog API. Returns the metaWeblog struct.")] + Post getPost(string postid, string username, string password); + + [XmlRpcMethod("metaWeblog.getRecentPosts", Description = "Retrieves a list of the most recent existing post using the metaWeblog API. Returns the metaWeblog struct collection.")] + Post[] getRecentPosts(string blogid, string username, string password, int numberOfPosts); + + [XmlRpcMethod("metaWeblog.newPost", Description = "Makes a new post to a designated blog using the metaWeblog API. Returns postid as a string.")] + string newPost(string blogid, string username, string password, Post post, bool publish); + + [XmlRpcMethod("metaWeblog.newMediaObject", Description = "Uploads an image, movie, song, or other media using the metaWeblog API. Returns the metaObject struct.")] + mediaObjectInfo newMediaObject(string blogid, string username, string password, mediaObject mediaobject); + + } + + [XmlRpcMissingMapping(MappingAction.Ignore)] + public struct Enclosure + { + public int length; + public string @type; + public string url; + } + + [XmlRpcMissingMapping(MappingAction.Ignore)] + public struct Source + { + public string name; + public string url; + } + + /// + /// Central structure to pass a post between WLW and the module + /// + /// + /// + /// [pdonker] 12/20/2009 added 'publish' + /// + [XmlRpcMissingMapping(MappingAction.Ignore)] + public struct Post + { + + /// + /// The date to publish the blog Post. + /// + /// + [XmlRpcMember("pubDate", Description = "The date to publish the blog Post.")] + public DateTime pubDate; + + /// + /// The GMT DateTime value when the blog Post was created. + /// + /// + [XmlRpcMember("date_created_gmt", Description = "The GMT DateTime value when the blog Post was created.")] + public DateTime date_created_gmt; + + /// + /// The DateTime value when the blog Post was created. + /// + /// + [XmlRpcMissingMapping(MappingAction.Error)] + public DateTime dateCreated; + + /// + /// Post Content + /// + /// + [XmlRpcMissingMapping(MappingAction.Error)] + public string description; + + /// + /// Post Title + /// + /// + [XmlRpcMissingMapping(MappingAction.Error)] + public string title; + + /// + /// List of categories for the post + /// + /// + [XmlRpcMember("categories", Description = "Contains Categories for the post.")] + public string[] categories; + + /// + /// + /// + /// + [XmlRpcMember("mt_keywords", Description = "List of Keywords for the post.")] + public string mt_keywords; + + /// + /// + /// + /// + [XmlRpcMember("mt_allow_comments", Description = "Determines if comments will be allowed for this post. (0 = none, 1 = open, 2=closed)")] + public int mt_allow_comments; + + /// + /// + /// + /// + [XmlRpcMember("mt_allow_pings", Description = "Determines if comments will be allowed for this post. (0 = closed, 1 = open) ")] + public int mt_allow_pings; + + /// + /// + /// + /// + public string link; + + /// + /// + /// + /// + public string permalink; + + /// + /// + /// + /// + [XmlRpcMember(Description = "Not required when posting. Depending on server may be either string or integer. Use Convert.ToInt32(postid) to treat as integer or Convert.ToString(postid) to treat as string")] + public string postid; + + /// + /// + /// + /// + [XmlRpcMember("publish", Description = "Determines if post will be published ")] + public bool publish; + + + /// + /// Used to track an SEO friendly description of the post, usually shorter than + /// the Title and formatted for SEO presentation (eg. Using-Trackbacks-1). + /// Only utilized if the supportsSlug entity is set to yes in the manifest file. + /// + /// + public string wp_slug; + + /// + /// Only utilized if the supportsPassword entity is set to yes in the manifest file. + /// + /// + public string wp_password; + + /// + /// Only utilized if the supportsPageParent entity is set to yes in the manifest file. + /// + /// + [XmlRpcMember("wp_page_parent_id", Description = "Id for the parent of the page.")] + public string wp_page_parent_id; + + /// + /// Only utilized if the supportsPageOrder entity is set to yes in the manifest file. + /// + /// + public string wp_page_order; + + /// + /// Only utilized if the supportsAuthor entity is set to yes in the manifest file. + /// + /// + public string wp_author_id; + + /// + /// Only utilized if the supportsExcerpt entity is set to yes in the manifest file. In plain HTML. + /// + /// + [XmlRpcMember("mt_excerpt", Description = "Summary of the post.")] + public string mt_excerpt; + + /// + /// Only utilized if the supportsExtendedPosts entity is set to yes in the manifest file. + /// + /// + public string mt_text_more; + + /// + /// Used to manage trackback URLs. Will only be populated if + /// supportsTrackbacks is set to yes in the manifest file. + /// + /// + + public string[] mt_tb_ping_urls; + + /// + /// Used to track the status of the page. This is a WordPress property. + /// + /// + public string page_status; + + } + + public struct Page + { + [XmlRpcMember("page_id", Description = "Id for the page.")] + public object page_id; + [XmlRpcMember("page_title", Description = "Title of the page.")] + public string page_title; + [XmlRpcMember("page_parent_id", Description = "Id for the parent of the page.")] + public string page_parent_id; + [XmlRpcMember("DateCreated", Description = "Creation date of the page.")] + public DateTime dateCreated; + } + + public struct CategoryInfo + { + public string categoryId; + public string parentId; + public string description; + public string categoryName; + public string htmlUrl; + public string rssUrl; + } + + /// + /// Metaweblog specific category structure + /// + /// + public struct MetaWebLogCategoryInfo + { + public string description; + public string htmlUrl; + public string rssUrl; + } + + public struct NewCategory + { + public string name; + public string slug; + public int parent_id; + public string description; + } + + public struct mediaObject + { + public string name; + public string @type; + public byte[] bits; + } + + public struct mediaObjectInfo + { + public string url; + } + +} \ No newline at end of file diff --git a/Server/Core/Services/WLW/MoveableType/IMoveableType.cs b/Server/Core/Services/WLW/MoveableType/IMoveableType.cs new file mode 100644 index 00000000..a304f210 --- /dev/null +++ b/Server/Core/Services/WLW/MoveableType/IMoveableType.cs @@ -0,0 +1,61 @@ + +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2015 +// by DotNetNuke Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using CookComputing.XmlRpc; + +namespace DotNetNuke.Modules.Blog.Services.WLW.MoveableType +{ + + /// + /// Interface for Moveable Type methods that WLW uses + /// + /// + /// + /// [pdonker] 12/14/2009 created + /// + public interface IMoveableType + { + + [XmlRpcMethod("mt.getPostCategories", Description = "Retrieves the categories for an existing post using the MoveableType " + "API. Returns the metaWeblog struct.")] + Category[] getPostCategories(string postid, string username, string password); + + [XmlRpcMethod("mt.setPostCategories", Description = "Sets the categories for an existing post using the MoveableType " + "API. Returns the metaWeblog struct.")] + bool setPostCategories(string postid, string username, string password, Category[] categories); + + } + + /// + /// MT specific category structure + /// + /// + /// + /// [pdonker] 12/14/2009 created + /// + public struct Category + { + public string categoryId; + [XmlRpcMissingMapping(MappingAction.Ignore)] + public string categoryName; + [XmlRpcMissingMapping(MappingAction.Ignore)] + public bool isPrimary; + } + +} \ No newline at end of file diff --git a/Server/Core/Services/WLW/WordPress/IWordPress.cs b/Server/Core/Services/WLW/WordPress/IWordPress.cs new file mode 100644 index 00000000..5a15efab --- /dev/null +++ b/Server/Core/Services/WLW/WordPress/IWordPress.cs @@ -0,0 +1,59 @@ + +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2015 +// by DotNetNuke Corporation +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using CookComputing.XmlRpc; + +namespace DotNetNuke.Modules.Blog.Services.WLW.WordPress +{ + + /// + /// Interface for Wordpress methods that WLW uses + /// + /// + /// + /// [pdonker] 12/14/2009 created + /// + public interface IWordPress + { + + [XmlRpcMethod("wp.getCategories", Description = "Retrieves the categories for a blog using the Wordpress API. Returns an array of category Infos.")] + CategoryInfo[] getCategories(string blogid, string username, string password); + + } + + /// + /// WP specific category structure + /// + /// + /// + /// [pdonker] 12/14/2009 created + /// + public struct CategoryInfo + { + public int categoryId; + public int parentId; + public string description; + public string categoryName; + public string htmlUrl; + public string rssUrl; + } + +} \ No newline at end of file diff --git a/Server/Core/Templating/BaseCustomTokenReplace.cs b/Server/Core/Templating/BaseCustomTokenReplace.cs new file mode 100644 index 00000000..bea587e5 --- /dev/null +++ b/Server/Core/Templating/BaseCustomTokenReplace.cs @@ -0,0 +1,216 @@ +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using static DotNetNuke.Services.Localization.Localization; +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2002-2010 by DotNetNuke Corp. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Services.Tokens; + +namespace DotNetNuke.Modules.Blog.Templating +{ + /// + /// BaseCustomTokenReplace allows to add multiple sources implementing IPropertyAccess + /// + /// + public abstract class BaseCustomTokenReplace : BaseTokenReplace + { + + #region Private Fields + private Scope _AccessLevel; + private DotNetNuke.Entities.Users.UserInfo _AccessingUser; + private bool _debugMessages; + #endregion + + #region Protected Properties + + /// + /// Gets/sets the current Access Level controlling access to critical user settings + /// + /// A TokenAccessLevel as defined above + protected Scope CurrentAccessLevel + { + get + { + return _AccessLevel; + } + set + { + + _AccessLevel = value; + } + } + + protected Dictionary PropertySource = new Dictionary(); + + + #endregion + + #region Public Properties + + /// + /// Gets/sets the user object representing the currently accessing user (permission) + /// + /// UserInfo oject + public DotNetNuke.Entities.Users.UserInfo AccessingUser + { + get + { + return _AccessingUser; + } + set + { + _AccessingUser = value; + } + } + + /// + /// If DebugMessages are enabled, unknown Tokens are replaced with Error Messages + /// + /// + /// + /// + public bool DebugMessages + { + get + { + return _debugMessages; + } + set + { + _debugMessages = value; + } + } + + #endregion + + #region Protected Methods + + protected override string replacedTokenValue(string strObjectName, string strPropertyName, string strFormat) + { + bool PropertyNotFound = false; + string result = string.Empty; + if (PropertySource.ContainsKey(strObjectName.ToLower())) + { + result = PropertySource[strObjectName.ToLower()].GetProperty(strPropertyName, strFormat, FormatProvider, AccessingUser, CurrentAccessLevel, ref PropertyNotFound); + } + else if (DebugMessages) + { + string message = GetString("TokenReplaceUnknownObject", SharedResourceFile, FormatProvider.ToString()); + if (string.IsNullOrEmpty(message)) + message = "Error accessing [{0}:{1}], {0} is an unknown datasource"; + result = string.Format(message, strObjectName, strPropertyName); + } + if (DebugMessages & PropertyNotFound) + { + string message; + if ((result ?? "") == (PropertyAccess.ContentLocked ?? "")) + { + message = GetString("TokenReplaceRestrictedProperty", GlobalResourceFile, FormatProvider.ToString()); + } + else + { + message = GetString("TokenReplaceUnknownProperty", GlobalResourceFile, FormatProvider.ToString()); + } + + if (string.IsNullOrEmpty(message)) + message = "Error accessing [{0}:{1}], {1} is unknown for datasource {0}"; + result = string.Format(message, strObjectName, strPropertyName); + } + return result; + } + + #endregion + + #region Public Methods + + /// + /// Checks for present [Object:Property] tokens + /// + /// String with [Object:Property] tokens + /// + /// + /// 08/10/2007 [sleupold] created + /// 10/19/2007 [sleupold] corrected to ignore unchanged text returned (issue DNN-6526) + /// + public bool ContainsTokens(string strSourceText) + { + if (!string.IsNullOrEmpty(strSourceText)) + { + foreach (Match currentMatch in TokenizerRegex.Matches(strSourceText)) + { + if (currentMatch.Result("${object}").Length > 0) + { + return true; + } + } + } + return false; + } + + /// + /// returns cacheability of the passed text regarding all contained tokens + /// + /// the text to parse for tokens to replace + /// cacheability level (not - safe - fully) + /// always check cacheability before caching a module! + /// + /// 10/19/2007 [sleupold] corrected to handle non-empty strings + /// + public CacheLevel Cacheability(string strSourcetext) + { + var IsSafe = CacheLevel.fullyCacheable; + if (strSourcetext is not null && !string.IsNullOrEmpty(strSourcetext)) + { + + // initialize PropertyAccess classes + string DummyResult = ReplaceTokens(strSourcetext); + + var Result = new StringBuilder(); + foreach (Match currentMatch in TokenizerRegex.Matches(strSourcetext)) + { + + string strObjectName = currentMatch.Result("${object}"); + if (strObjectName.Length > 0) + { + if (strObjectName == "[") + { + } + // nothing + else if (!PropertySource.ContainsKey(strObjectName.ToLower())) + { + } + // end if + else + { + var c = PropertySource[strObjectName.ToLower()].Cacheability; + if (c < IsSafe) + IsSafe = c; + } + } + } + } + return IsSafe; + } + + #endregion + + } + +} \ No newline at end of file diff --git a/Server/Core/Templating/BaseTokenReplace.cs b/Server/Core/Templating/BaseTokenReplace.cs new file mode 100644 index 00000000..8cb4c124 --- /dev/null +++ b/Server/Core/Templating/BaseTokenReplace.cs @@ -0,0 +1,186 @@ + +// +// DotNetNuke® - http://www.dotnetnuke.com +// Copyright (c) 2002-2010 by DotNetNuke Corp. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; +using DotNetNuke.UI.Utilities; + +namespace DotNetNuke.Modules.Blog.Templating +{ + + /// + /// The BaseTokenReplace class provides the tokenization of tokens formatted + /// [object:property] or [object:property|format|ifEmpty] or [custom:no] within a string + /// with the appropriate current property/custom values. + /// + /// + public abstract class BaseTokenReplace + { + + #region Regexp Tokenizer + + + // Private Const ExpressionDefault As String = "(?:\[(?:(?[^\]\[:]+):(?[^\]\[\|]+))(?:\|(?:(?[^\]\[]+)\|(?[^\]\[]+))|\|(?:(?[^\|\]\[]+)))?\])|(?\[[^\]\[]+\])|(?[^\]\[]+)" + private const string ExpressionDefault = @"\[(?[^\]\[:\r\n]+):(?[^\]\[\|\r\n]+)((\])|(\|(?[^\]\[\r\n]+)((\])|(\|(?[^\]\[\r\n]+)))))"; + + private const string ExpressionObjectLess = @"(?:\[(?:(?[^\]\[:]+):(?[^\]\[\|]+))(?:\|(?:(?[^\]\[]+)\|(?[^\]\[]+))|\|(?:(?[^\|\]\[]+)))?\])" + @"|(?:(?\[)(?[A-Z0-9._]+)(?:\|(?:(?[^\]\[]+)\|(?[^\]\[]+))|\|(?:(?[^\|\]\[]+)))?\])" + @"|(?\[[^\]\[]+\])" + @"|(?[^\]\[]+)"; + + + + private bool _UseObjectLessExpression = false; + + protected bool UseObjectLessExpression + { + get + { + return _UseObjectLessExpression; + } + set + { + _UseObjectLessExpression = value; + } + } + + private string TokenReplaceCacheKey + { + get + { + if (UseObjectLessExpression) + { + return "Blog_TokenReplaceRegEx_Objectless"; + } + else + { + return "Blog_TokenReplaceRegEx_Default"; + } + } + } + + private string RegExpression + { + get + { + if (UseObjectLessExpression) + { + return ExpressionObjectLess; + } + else + { + return ExpressionDefault; + } + } + } + + protected const string ObjectLessToken = "no_object"; + + /// + /// Gets the Regular expression for the token to be replaced + /// + /// A regular Expression + protected Regex TokenizerRegex + { + get + { + Regex tokenizer = (Regex)DataCache.GetCache(TokenReplaceCacheKey); + if (tokenizer is null) + { + tokenizer = new Regex(RegExpression, RegexOptions.Compiled); + DataCache.SetCache(TokenReplaceCacheKey, tokenizer); + } + return tokenizer; + } + } + #endregion + + #region Fields & Properties + private string _Language; + private CultureInfo _FormatProvider; + + /// + /// Gets/sets the language to be used, e.g. for date format + /// + /// A string, representing the locale + public string Language + { + get + { + return _Language; + } + set + { + _Language = value; + _FormatProvider = new CultureInfo(_Language); + } + } + + /// + /// Gets the Format provider as Culture info from stored language or current culture + /// + /// An CultureInfo + protected CultureInfo FormatProvider + { + get + { + if (_FormatProvider is null) + { + _FormatProvider = System.Threading.Thread.CurrentThread.CurrentUICulture; + } + return _FormatProvider; + } + } + #endregion + + protected virtual string ReplaceTokens(string strSourceText) + { + if (strSourceText is null) + return string.Empty; + var Result = new StringBuilder(); + return TokenizerRegex.Replace(strSourceText, ReplaceTokenMatch); + } + + private string ReplaceTokenMatch(Match m) + { + + string strObjectName = m.Result("${object}"); + if (strObjectName.Length > 0) + { + if (strObjectName == "[") + strObjectName = ObjectLessToken; + string strPropertyName = m.Result("${property}"); + string strFormat = m.Result("${format}"); + string strIfEmptyReplacment = m.Result("${ifEmpty}"); + string strConversion = replacedTokenValue(strObjectName, strPropertyName, strFormat); + if (strIfEmptyReplacment.Length > 0 && strConversion.Length == 0) + strConversion = strIfEmptyReplacment; + return strConversion; + } + else + { + return m.Value; + } + + } + + + protected abstract string replacedTokenValue(string strObjectName, string strPropertyName, string strFormat); + + } +} \ No newline at end of file diff --git a/Server/Core/Templating/BlogTokenReplace.cs b/Server/Core/Templating/BlogTokenReplace.cs new file mode 100644 index 00000000..78fa3f78 --- /dev/null +++ b/Server/Core/Templating/BlogTokenReplace.cs @@ -0,0 +1,301 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Entities.Portals; +using DotNetNuke.Modules.Blog.Common; +using DotNetNuke.Modules.Blog.Entities.Blogs; +using DotNetNuke.Modules.Blog.Entities.Comments; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Modules.Blog.Entities.Terms; +using DotNetNuke.Services.Tokens; + +namespace DotNetNuke.Modules.Blog.Templating +{ + public class BlogTokenReplace : GenericTokenReplace + { + + public BlogTokenReplace(int moduleId) + { + base.ctor(Scope.DefaultSettings); + + var actModule = new DotNetNuke.Entities.Modules.ModuleController().GetModule(moduleId); + ModuleInfo = actModule; + UseObjectLessExpression = false; + + } + + public BlogTokenReplace(DotNetNuke.Entities.Modules.ModuleInfo actModule, Security.ContextSecurity security, BlogInfo blog, PostInfo post, ModuleSettings settings, ViewSettings viewSettings) + { + base.ctor(Scope.DefaultSettings); + + ModuleInfo = actModule; + UseObjectLessExpression = false; + PropertySource["security"] = security; + PropertySource["settings"] = settings; + PropertySource["viewsettings"] = viewSettings; + if (blog is not null) + { + PropertySource["blog"] = blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, blog.OwnerUserId, blog.Username); + } + if (post is not null) + { + PropertySource["post"] = post; + } + + } + + public BlogTokenReplace(DotNetNuke.Entities.Modules.ModuleInfo actModule, Security.ContextSecurity security, BlogInfo blog, PostInfo Post, ModuleSettings settings, ViewSettings viewSettings, CommentInfo comment) + { + base.ctor(Scope.DefaultSettings); + + PrimaryObject = comment; + ModuleInfo = actModule; + UseObjectLessExpression = false; + PropertySource["security"] = security; + PropertySource["settings"] = settings; + PropertySource["viewsettings"] = viewSettings; + if (Post is not null) + { + PropertySource["post"] = Post; + PropertySource["author"] = new LazyLoadingUser(PortalSettings.PortalId, Post.CreatedByUserID, Post.Username); + PropertySource["blog"] = Post.Blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, Post.Blog.OwnerUserId, Post.Blog.Username); + } + else if (blog is not null) + { + PropertySource["blog"] = blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, blog.OwnerUserId, blog.Username); + } + PropertySource["comment"] = comment; + PropertySource["commenter"] = new LazyLoadingUser(PortalSettings.PortalId, comment.CreatedByUserID, comment.Username); + + } + + public BlogTokenReplace(BlogModuleBase blogModule) + { + base.ctor(Scope.DefaultSettings); + + ModuleInfo = blogModule.ModuleConfiguration; + UseObjectLessExpression = false; + PropertySource["query"] = blogModule.BlogContext; + PropertySource["security"] = blogModule.BlogContext.Security; + PropertySource["urls"] = blogModule.BlogContext.ModuleUrls; + PropertySource["settings"] = blogModule.Settings; + PropertySource["viewsettings"] = blogModule.ViewSettings; + if (blogModule.BlogContext.Blog is not null) + { + PropertySource["blog"] = blogModule.BlogContext.Blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, blogModule.BlogContext.Blog.OwnerUserId, blogModule.BlogContext.Blog.Username); + } + if (blogModule.BlogContext.Post is not null) + { + PropertySource["post"] = blogModule.BlogContext.Post; + PropertySource["author"] = new LazyLoadingUser(PortalSettings.PortalId, blogModule.BlogContext.Post.CreatedByUserID, blogModule.BlogContext.Post.Username); + } + if (blogModule.BlogContext.Term is not null) + { + PropertySource["selectedterm"] = blogModule.BlogContext.Term; + } + if (blogModule.BlogContext.Author is not null) + { + PropertySource["author"] = blogModule.BlogContext.Author; + } + + } + + public BlogTokenReplace(BlogModuleBase blogModule, BlogInfo blog) + { + base.ctor(Scope.DefaultSettings); + + PrimaryObject = blog; + ModuleInfo = blogModule.ModuleConfiguration; + UseObjectLessExpression = false; + PropertySource["query"] = blogModule.BlogContext; + PropertySource["security"] = blogModule.BlogContext.Security; + PropertySource["urls"] = blogModule.BlogContext.ModuleUrls; + PropertySource["settings"] = blogModule.Settings; + PropertySource["viewsettings"] = blogModule.ViewSettings; + PropertySource["blog"] = blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, blog.OwnerUserId, blog.Username); + if (blogModule.BlogContext.Post is not null) + { + PropertySource["post"] = blogModule.BlogContext.Post; + PropertySource["author"] = new LazyLoadingUser(PortalSettings.PortalId, blogModule.BlogContext.Post.CreatedByUserID, blogModule.BlogContext.Post.Username); + } + else if (blogModule.BlogContext.Author is not null) + { + PropertySource["author"] = blogModule.BlogContext.Author; + } + if (blogModule.BlogContext.Term is not null) + { + PropertySource["selectedterm"] = blogModule.BlogContext.Term; + } + + } + + public BlogTokenReplace(BlogModuleBase blogModule, BlogCalendarInfo objBlogCalendar) + { + base.ctor(Scope.DefaultSettings); + + PrimaryObject = objBlogCalendar; + ModuleInfo = blogModule.ModuleConfiguration; + UseObjectLessExpression = false; + PropertySource["query"] = blogModule.BlogContext; + PropertySource["security"] = blogModule.BlogContext.Security; + PropertySource["urls"] = blogModule.BlogContext.ModuleUrls; + PropertySource["settings"] = blogModule.Settings; + PropertySource["viewsettings"] = blogModule.ViewSettings; + if (blogModule.BlogContext.Blog is not null) + { + PropertySource["blog"] = blogModule.BlogContext.Blog; + } + PropertySource["calendar"] = objBlogCalendar; + if (blogModule.BlogContext.Post is not null) + { + PropertySource["post"] = blogModule.BlogContext.Post; + PropertySource["author"] = new LazyLoadingUser(PortalSettings.PortalId, blogModule.BlogContext.Post.CreatedByUserID, blogModule.BlogContext.Post.Username); + } + else if (blogModule.BlogContext.Author is not null) + { + PropertySource["author"] = blogModule.BlogContext.Author; + } + if (blogModule.BlogContext.Term is not null) + { + PropertySource["selectedterm"] = blogModule.BlogContext.Term; + } + + } + + public BlogTokenReplace(BlogModuleBase blogModule, LazyLoadingUser objAuthor) + { + base.ctor(Scope.DefaultSettings); + + PrimaryObject = objAuthor; + ModuleInfo = blogModule.ModuleConfiguration; + UseObjectLessExpression = false; + PropertySource["query"] = blogModule.BlogContext; + PropertySource["security"] = blogModule.BlogContext.Security; + PropertySource["urls"] = blogModule.BlogContext.ModuleUrls; + PropertySource["settings"] = blogModule.Settings; + PropertySource["viewsettings"] = blogModule.ViewSettings; + if (blogModule.BlogContext.Blog is not null) + { + PropertySource["blog"] = blogModule.BlogContext.Blog; + } + PropertySource["author"] = objAuthor; + if (blogModule.BlogContext.Post is not null) + { + PropertySource["post"] = blogModule.BlogContext.Post; + } + if (blogModule.BlogContext.Term is not null) + { + PropertySource["selectedterm"] = blogModule.BlogContext.Term; + } + + } + + public BlogTokenReplace(BlogModuleBase blogModule, PostInfo Post) + { + base.ctor(Scope.DefaultSettings); + + PrimaryObject = Post; + ModuleInfo = blogModule.ModuleConfiguration; + UseObjectLessExpression = false; + PropertySource["query"] = blogModule.BlogContext; + PropertySource["security"] = blogModule.BlogContext.Security; + PropertySource["urls"] = blogModule.BlogContext.ModuleUrls; + PropertySource["settings"] = blogModule.Settings; + PropertySource["viewsettings"] = blogModule.ViewSettings; + PropertySource["post"] = Post; + PropertySource["author"] = new LazyLoadingUser(PortalSettings.PortalId, Post.CreatedByUserID, Post.Username); + PropertySource["blog"] = Post.Blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, Post.Blog.OwnerUserId, Post.Blog.Username); + if (blogModule.BlogContext.Term is not null) + { + PropertySource["selectedterm"] = blogModule.BlogContext.Term; + } + + } + + public BlogTokenReplace(BlogModuleBase blogModule, PostInfo Post, TermInfo term) + { + base.ctor(Scope.DefaultSettings); + + PrimaryObject = term; + ModuleInfo = blogModule.ModuleConfiguration; + UseObjectLessExpression = false; + PropertySource["query"] = blogModule.BlogContext; + PropertySource["security"] = blogModule.BlogContext.Security; + PropertySource["urls"] = blogModule.BlogContext.ModuleUrls; + PropertySource["settings"] = blogModule.Settings; + PropertySource["viewsettings"] = blogModule.ViewSettings; + if (Post is not null) + { + PropertySource["post"] = Post; + PropertySource["author"] = new LazyLoadingUser(PortalSettings.PortalId, Post.CreatedByUserID, Post.Username); + PropertySource["blog"] = Post.Blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, Post.Blog.OwnerUserId, Post.Blog.Username); + } + else if (blogModule.BlogContext.Blog is not null) + { + PropertySource["blog"] = blogModule.BlogContext.Blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, blogModule.BlogContext.Blog.OwnerUserId, blogModule.BlogContext.Blog.Username); + } + PropertySource["term"] = term; + if (blogModule.BlogContext.Term is not null) + { + PropertySource["selectedterm"] = blogModule.BlogContext.Term; + } + + } + + public BlogTokenReplace(BlogModuleBase blogModule, PostInfo Post, CommentInfo comment) + { + base.ctor(Scope.DefaultSettings); + + PrimaryObject = comment; + ModuleInfo = blogModule.ModuleConfiguration; + UseObjectLessExpression = false; + PropertySource["query"] = blogModule.BlogContext; + PropertySource["security"] = blogModule.BlogContext.Security; + PropertySource["urls"] = blogModule.BlogContext.ModuleUrls; + PropertySource["settings"] = blogModule.Settings; + PropertySource["viewsettings"] = blogModule.ViewSettings; + if (Post is not null) + { + PropertySource["post"] = Post; + PropertySource["author"] = new LazyLoadingUser(PortalSettings.PortalId, Post.CreatedByUserID, Post.Username); + PropertySource["blog"] = Post.Blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, Post.Blog.OwnerUserId, Post.Blog.Username); + } + else if (blogModule.BlogContext.Blog is not null) + { + PropertySource["blog"] = blogModule.BlogContext.Blog; + PropertySource["owner"] = new LazyLoadingUser(PortalSettings.PortalId, blogModule.BlogContext.Blog.OwnerUserId, blogModule.BlogContext.Blog.Username); + } + PropertySource["comment"] = comment; + PropertySource["commenter"] = new LazyLoadingUser(PortalSettings.PortalId, comment.CreatedByUserID, comment.Username); + + } + + } +} \ No newline at end of file diff --git a/Server/Core/Templating/CustomParameters.cs b/Server/Core/Templating/CustomParameters.cs new file mode 100644 index 00000000..3c92c34d --- /dev/null +++ b/Server/Core/Templating/CustomParameters.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Specialized; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; + +namespace DotNetNuke.Modules.Blog.Templating +{ + public class CustomParameters : IPropertyAccess + { + + #region Private Members + private NameValueCollection @params { get; set; } + #endregion + + #region Constructors + public CustomParameters(params string[] customParameters) + { + @params = new NameValueCollection(); + foreach (string sParameter in customParameters) + @params.Add(Strings.Left(sParameter.ToLower(), sParameter.IndexOf('=')), Strings.Mid(sParameter, sParameter.IndexOf('=') + 2)); + } + #endregion + + #region IPropertyAccess + public CacheLevel Cacheability + { + get + { + return CacheLevel.notCacheable; + } + } + + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + if (@params[strPropertyName.ToLower()] is null) + return DotNetNuke.Common.Utilities.Null.NullString; + string value = @params[strPropertyName.ToLower()]; + try + { + if (Information.IsNumeric(value)) + { + return Conversions.ToDouble(value).ToString(OutputFormat, formatProvider); + } + if (Information.IsDate(value)) + { + return Conversions.ToDate(value).ToString(OutputFormat, formatProvider); + } + return Common.Globals.FormatBoolean(Conversions.ToBoolean(value), strFormat); + } + catch (Exception ex) + { + return value; + } + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Templating/GenericTokenReplace.cs b/Server/Core/Templating/GenericTokenReplace.cs new file mode 100644 index 00000000..722dde8f --- /dev/null +++ b/Server/Core/Templating/GenericTokenReplace.cs @@ -0,0 +1,76 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Services.Tokens; + +namespace DotNetNuke.Modules.Blog.Templating +{ + public abstract class GenericTokenReplace : TokenReplace + { + + public object PrimaryObject { get; set; } = null; + + public GenericTokenReplace(Scope accessLevel) : base(Scope.DefaultSettings) + { + } + + public GenericTokenReplace(Scope accessLevel, int moduleId) : base(Scope.DefaultSettings, moduleId) + { + } + + public new string ReplaceTokens(string strSourceText) + { + strSourceText = strSourceText.Replace(@"\[", "{{").Replace(@"\]", "}}"); + return base.ReplaceTokens(strSourceText).Replace("{{", "[").Replace("}}", "]"); + } + + public new string ReplaceTokens(string strSourceText, params string[] additionalParameters) + { + strSourceText = strSourceText.Replace(@"\[", "{{").Replace(@"\]", "}}"); + PropertySource["custom"] = new CustomParameters(additionalParameters); + return base.ReplaceTokens(strSourceText).Replace("{{", "[").Replace("}}", "]"); + } + + public void AddCustomParameters(params string[] additionalParameters) + { + PropertySource["custom"] = new CustomParameters(additionalParameters); + } + + public void AddResources(string TemplateRelPath) + { + PropertySource["resx"] = new Resources(TemplateRelPath); + } + + public void AddPropertySource(string key, IPropertyAccess resource) + { + PropertySource[key] = resource; + } + + public string GetTokenValue(string obj, string prop, string format) + { + if (!PropertySource.ContainsKey(obj)) + return ""; + bool bFound = false; + return PropertySource[obj].GetProperty(prop, format, System.Threading.Thread.CurrentThread.CurrentCulture, null, Scope.DefaultSettings, ref bFound); + } + + } +} \ No newline at end of file diff --git a/Server/Core/Templating/LazyLoadingUser.cs b/Server/Core/Templating/LazyLoadingUser.cs new file mode 100644 index 00000000..66025e81 --- /dev/null +++ b/Server/Core/Templating/LazyLoadingUser.cs @@ -0,0 +1,152 @@ +using System.Web; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Common.Utilities; +using DotNetNuke.Entities.Users; +using DotNetNuke.Modules.Blog.Entities.Posts; +using DotNetNuke.Services.Tokens; +using Microsoft.VisualBasic; + +namespace DotNetNuke.Modules.Blog.Templating +{ + public class LazyLoadingUser : IPropertyAccess + { + + #region Properties + public int PortalId { get; set; } = -1; + public int UserId { get; set; } = -1; + public string Username { get; set; } = ""; + + private UserInfo _user; + public UserInfo User + { + get + { + if (_user is null) + { + if (UserId > -1) + { + _user = UserController.GetUserById(PortalId, UserId); + } + else if (!string.IsNullOrEmpty(Username)) + { + _user = UserController.GetCachedUser(PortalId, Username); + } + else + { + _user = new UserInfo(); + } + } + return _user; + } + set + { + _user = value; + } + } + + private PostAuthor _postAuthor = null; + #endregion + + #region Constructors + public LazyLoadingUser(int portalId, int userId) + { + PortalId = portalId; + UserId = userId; + } + + public LazyLoadingUser(int portalId, int userId, string userName) + { + PortalId = portalId; + UserId = userId; + Username = userName; + } + + public LazyLoadingUser(UserInfo user) + { + User = user; + PortalId = user.PortalID; + UserId = user.UserID; + } + + public LazyLoadingUser(PostAuthor user) + { + User = user; + PortalId = user.PortalID; + UserId = user.UserID; + _postAuthor = user; + } + #endregion + + #region IPropertyAccess Implementation + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + switch (strPropertyName.ToLower() ?? "") + { + case "profilepic": + { + if (Information.IsNumeric(strFormat)) + { + return DotNetNuke.Common.Globals.ResolveUrl(string.Format("~/DnnImageHandler.ashx?mode=profilepic&userId={0}&w={1}&h={1}", UserId, strFormat)); + } + else + { + return DotNetNuke.Common.Globals.ResolveUrl(string.Format("~/DnnImageHandler.ashx?mode=profilepic&userId={0}&w={1}&h={1}", UserId, 50)); + } + } + case "profileurl": + { + return DotNetNuke.Common.Globals.UserProfileURL(UserId); + } + } + string res = ""; + if (_postAuthor is not null) + { + res = _postAuthor.GetProperty(strPropertyName, strFormat, formatProvider, AccessingUser, AccessLevel, ref PropertyNotFound); + } + else + { + res = User.GetProperty(strPropertyName, strFormat, formatProvider, AccessingUser, AccessLevel, ref PropertyNotFound); + } + if (PropertyNotFound) + { + res = HttpUtility.HtmlDecode(User.Profile.GetPropertyValue(strPropertyName)); + } + if (!string.IsNullOrEmpty(res)) + { + PropertyNotFound = false; + return res; + } + PropertyNotFound = true; + return Null.NullString; + } + + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Templating/Resources.cs b/Server/Core/Templating/Resources.cs new file mode 100644 index 00000000..5630e27a --- /dev/null +++ b/Server/Core/Templating/Resources.cs @@ -0,0 +1,91 @@ + +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +using DotNetNuke.Common.Utilities; +using static DotNetNuke.Services.Localization.Localization; +using DotNetNuke.Services.Tokens; + +namespace DotNetNuke.Modules.Blog.Templating +{ + public class Resources : IPropertyAccess + { + + private string ResourcesPath { get; set; } = ""; + private string PrimaryResourceFile { get; set; } = ""; + private string SecondaryResourceFile { get; set; } = ""; + + #region Constructors + public Resources(string TemplateRelPath) + { + PrimaryResourceFile = TemplateRelPath; + ResourcesPath = TemplateRelPath.Substring(0, TemplateRelPath.LastIndexOf("/")); + if (!PrimaryResourceFile.ToLower().EndsWith(".resx")) + { + PrimaryResourceFile = PrimaryResourceFile + ".resx"; + } + SecondaryResourceFile = ResourcesPath + "/SharedResources.ascx.resx"; + } + #endregion + + #region IPropertyAccess Implementation + public CacheLevel Cacheability + { + get + { + return CacheLevel.fullyCacheable; + } + } + + public string GetProperty(string strPropertyName, string strFormat, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo AccessingUser, Scope AccessLevel, ref bool PropertyNotFound) + { + string OutputFormat = string.Empty; + if (string.IsNullOrEmpty(strFormat)) + { + OutputFormat = "D"; + } + else + { + OutputFormat = strFormat; + } + string res = GetString(strPropertyName, PrimaryResourceFile); + if (string.IsNullOrEmpty(res)) + { + res = GetString(strPropertyName, SecondaryResourceFile); + } + if (res is not null) + { + switch (OutputFormat.ToLower() ?? "") + { + case "js": + case "jssafe": + { + res = UI.Utilities.ClientAPI.GetSafeJSString(res); + break; + } + } + return res; + } + return Null.NullString; + } + #endregion + + } +} \ No newline at end of file diff --git a/Server/Core/Templating/Template.cs b/Server/Core/Templating/Template.cs new file mode 100644 index 00000000..5b5c9347 --- /dev/null +++ b/Server/Core/Templating/Template.cs @@ -0,0 +1,334 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using Microsoft.VisualBasic; +using Microsoft.VisualBasic.CompilerServices; +// +// DNN Connect - http://dnn-connect.org +// Copyright (c) 2015 +// by DNN Connect +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +// documentation files (the "Software"), to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +// to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or substantial portions +// of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + +namespace DotNetNuke.Modules.Blog.Templating +{ + public class Template + { + + #region Private Members + public string FileName { get; set; } = "Template.html"; + public string Contents { get; set; } = ""; + public string ViewMapPath { get; set; } = ""; + public string ViewRelPath { get; set; } = ""; + public GenericTokenReplace Replacer { get; set; } = null; + #endregion + + #region Events + private void Template_GetData(string DataSource, Dictionary Parameters, ref List Replacers, ref List Arguments, object callingObject) + { + GetData?.Invoke(DataSource, Parameters, ref Replacers, ref Arguments, callingObject); + } + + public event GetDataEventHandler GetData; + + public delegate void GetDataEventHandler(string DataSource, Dictionary Parameters, ref List Replacers, ref List Arguments, object callingObject); + #endregion + + #region Constructors + public Template(string ViewMapPath, string ViewRelPath, string Filename, GenericTokenReplace Replacer, TemplateRepeaterItem item) + { + this.ViewMapPath = ViewMapPath; + this.ViewRelPath = ViewRelPath; + FileName = Filename; + this.Replacer = Replacer; + this.Replacer.AddResources(ViewRelPath + "App_LocalResources/" + Filename); + if (item is not null) + this.Replacer.AddPropertySource("item", item); + } + + public Template(string ViewMapPath, string ViewRelPath, string Filename, GenericTokenReplace Replacer, TemplateRepeaterItem item, string[] Arguments) + { + this.ViewMapPath = ViewMapPath; + this.ViewRelPath = ViewRelPath; + FileName = Filename; + this.Replacer = Replacer; + this.Replacer.AddCustomParameters(Arguments); + this.Replacer.AddResources(ViewRelPath + "App_LocalResources/" + Filename); + if (item is not null) + this.Replacer.AddPropertySource("item", item); + } + #endregion + + #region Public Methods + public string ReplaceContents() + { + + try + { + Contents = Templating.GetTemplateFile(ViewMapPath + FileName); + if (string.IsNullOrEmpty(Contents)) + return ""; + // Expand subtemplates + // Simple conditional template e.g. [subtemplate|Widget.html|widget:isgood|True] + Contents = Regex.Replace(Contents, @"(?i)\[subtemplate\|([^|\]]+)\|([^:|\]]+):([^|\]]+)\|?([^|\]]+)?\](?-i)", ReplaceConditionalTemplate); + // Inline conditional e.g. [if|2][flight:flightid][>]4[/if] ... [endif|2] + Contents = Regex.Replace(Contents, @"(?si)\[if\|(?