diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..e9ca2ee30 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,87 @@ + + + +You are a senior .NET developer, experienced in C#, JavaScript, HTML, ASP.NET Framework 4.8, CSS, and SQL. +You understand the priciples of DNN (DotNetNuke) and how to develop DNN modules. +You use Visual Studio Enterprise for running, debugging, and testing DNN (DotNetNuke) modules. + +## Code Style and Structure +- Write idiomatic and efficient C# code. +- Follow .NET conventions. +- Follow DNN module development best practices. +- Always follow DNN's StyleCop rules for C# and JavaScript. +- Always use StyleCop to add file header license to all C# files. +- Always put using directives inside the namespace, sorted alphabetically and grouped by system and third-party libraries. +- Always put a blank link between system and third-party libraries using directives. +- Use Razor syntax when possible for component-based UI development. +- Async/await should be used where applicable to ensure non-blocking UI operations. +- Classes should always be internal unless they are intended to be public APIs. +- Always add using directives for namespaces that are used in the file, and remove unused using directives. +- Never use 'Active Forums' in code, always use 'DNN Community Forums' instead. + +## Naming Conventions +- Follow PascalCase for component names, method names, and public members. +- Use underscore prefix and then PascalCase for private fields. +- Use camelCase for local variables. +- Prefix interface names with "I" (e.g., IUserService). + +## .NET Specific Guidelines +- Leverage DNN Dependency Injection for services when possible. +- DNN modules should be developed using DNN version 9.11 and compatible with .NET Framework 4.8. +- Always use the latest stable version of .NET libraries and packages compatible with DNN. +- Use NuGet packages for third-party libraries, ensuring they are compatible with DNN and .NET Framework 4.8. +- Use C# compatible with .NET Framework 4.8, avoiding features exclusive to .NET Core or .NET 5+. + +## Error Handling and Validation +- Implement proper error handling for Web API calls. + +## DNN Entities, Controllers, and Services +- Always create and use DNN-style entities (e.g., ForumUserInfo, ForumPostInfo) for data representation. +- Always create and use DNN-style services (e.g., IForumService, IUserService) for business logic. +- Always create controllers in Controllers folder, and use the appropriate namespaces, such as DotNetNuke.Modules.ActiveForums.Controllers. +- Always create controllers that inherit from DotNetNuke.Modules.ActiveForums.Controllers.RepositoryControllerBase for the appropriate entity. +- Always create controllers as internal classes, unless they are intended to be public APIs. +- Always create an entity class for each DNN entity, such as ForumUserInfo, ForumPostInfo, etc., in the Entities folder, and use namespace DotNetNuke.Modules.ActiveForums.Entities. +- Entity classes should use DNN DAL2 PetaPoco standards, and include TableName and PrimaryKey attributes, for example: + [TableName("activeforums_Content")] + [PrimaryKey("ContentId", AutoIncrement = true)] +- Always map entity's DateUpdated and DateCreated properties, ensuring they are stored in UTC format. +- Always add using DotNetNuke.ComponentModel.DataAnnotations; to the entity class files. + +## SQL DataProvider and Database Access +- Use DNN's built-in DataProvider pattern for database access. +- Create SQL scripts for database migrations and updates, ensuring they are compatible with DNN's upgrade process. +- Always use GETUTCDATE() for date and time storage in the database. +- Always add DateCreated and DataModified to all tables. +- Always default DateCreated to GETUTCDATE() and DateUpdated to GETUTCDATE() on insert and update operations. +- Database object names should be in camelCase. +- Always prefix database object names with activeforums_ to avoid conflicts with other modules. +- Always prefix database objects (tables, views, stored procedures) with the {databaseOwner}{objectQualifier} prefixes to ensure compatibility with DNN's multi-tenant architecture. +- Examples : {databaseOwner}[{objectQualifier}activeforums_ForumPosts] for ForumPosts table, IX_{objectQualifier}activeforums_Content_ModuleId for an index. +- Always add an auto-incrementing identity as primary key to all tables, using the naming convention PK_{objectQualifier}activeforums_{TableName} (e.g., PK_activeforums_ForumPosts). +- Always add indexes to frequently queried columns, using the naming convention IX_{objectQualifier}activeforums_{TableName}_{ColumnName} (e.g., IX_activeforums_ForumPosts_ModuleId). +- Always use NOT EXISTS check when creating tables and adding columns ot existing tables. +- Always use EXISTS check with DROP statements when creating indexes. +- Always use parameterized queries to prevent SQL injection attacks. +- Always create a matching entity class when creating a new table, such as ForumUserInfo, ForumPostInfo, etc., in the Entities folder. +- When adding a new SqlDataProvider, always offer to update the DNN manifest file (DnnCommunityForums.dnn) to reference the new version, ensuring it is compatible with DNN's upgrade process. + +## Caching Strategies +- Implement in-memory caching for all Controllers and services to improve performance and reduce database load. +- Caching should use methods in Cache.cs, such as ContentCacheRetrieve, ContentCacheStore, and ContentCacheRemove for content, and SettingsCache, SettingsCacheRetrieve, and SettingsCacheStore for settings. + +## API Design and Integration +- Use HttpClient or other appropriate services to communicate with external APIs or your own backend. +- Implement error handling for API calls using try-catch and provide proper user feedback in the UI. + +## Testing and Debugging in Visual Studio +- Create unit tests for all public and internal methods using NUnit. +- Use Moq for mocking dependencies during tests, leveraging TestBase.cs for shared test setup. +- Create unit tests in DnnCommunityForumsTests project for testing DNN module functionality. + +## Security and Authentication +- All user properties should be accesed using ForumUserInfo and then DNN UserInfo. +- Use HTTPS for all web communication and ensure proper CORS policies are implemented. + +## API Documentation +- Ensure XML documentation for models and API methods for enhancing sufficient documentation. \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.fr-FR.resx b/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.fr-FR.resx index ff4941278..10cb9dfc6 100644 --- a/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.fr-FR.resx +++ b/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.fr-FR.resx @@ -1483,4 +1483,61 @@ Votre méthode de suppression est actuellement définie sur {0}. Vos sujets ser Entrez une chaîne à utiliser lors de la récupération des modèles. Par exemple, si vous souhaitez disposer de fichiers de modèle distincts pour les forums modérés, entrez « modéré », puis les modèles seront récupérés à l’aide de « modéré » dans le nom de fichier, par exemple « TopicsView-moderated.ascx » plutôt que simplement « TopicsView.ascx » lorsque le modèle TopicsView est récupéré. + + Description + + + Insigne + + + Ordre de tri + + + Badges + + + Insigne + + + Nouveau badge + + + Seuil + + + Métrique + + + Image + + + Nouvel utilisateur + + + Sujets créés + + + Réponses aux rubriques + + + J’aime reçus + + + Sujets lus + + + Mettre à jour les utilisateurs + + + Balisage HTML pour badge (par exemple, font-awesome) + + + L’utilisateur ne peut gagner un badge qu’une seule fois + + + # de jours entre l’obtention de ce badge + + + Prix du manuel + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.it-IT.resx b/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.it-IT.resx index 5df13a5c1..a83e6f427 100644 --- a/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.it-IT.resx +++ b/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.it-IT.resx @@ -1480,4 +1480,61 @@ Il metodo di rimozione è attualmente impostato su {0}. I tuoi argomenti verran Immettere una stringa da utilizzare per il recupero dei modelli. Ad esempio, se si desidera avere file modello separati per i forum moderati, immettere "moderato" e quindi i modelli verranno recuperati utilizzando "moderato" come parte del nome del file, ad esempio "TopicsView-moderated.ascx" anziché solo "TopicsView.ascx" quando viene recuperato il modello TopicsView. + + Descrizione + + + Distintivo + + + Ordinamento + + + Distintivi + + + Distintivo + + + Nuovo distintivo + + + Soglia + + + Metrico + + + Immagine + + + Nuovo utente + + + Argomenti creati + + + Risposta agli argomenti + + + Mi piace ricevuti + + + Argomenti Leggi + + + Aggiorna utenti + + + Markup HTML per badge (ad esempio, font-awesome) + + + L'utente può guadagnare il badge una sola volta + + + # di giorni tra l'ottenimento di questo distintivo + + + Premio Manuale + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.nl-NL.resx b/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.nl-NL.resx index f895e4352..19a341a7e 100644 --- a/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.nl-NL.resx +++ b/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.nl-NL.resx @@ -1630,4 +1630,61 @@ De verwijder-methode is momenteel ingesteld op "{0}". Uw onderwerpen worden {1} Voer een tekenreeks in die moet worden gebruikt bij het ophalen van sjablonen. Als u bijvoorbeeld aparte sjabloonbestanden wilt hebben voor gemodereerde forums, voert u 'gemodereerd' in, waarna sjablonen worden opgehaald met 'gemodereerd' als onderdeel van de bestandsnaam, bijvoorbeeld 'TopicsView-moderated.ascx' in plaats van alleen 'TopicsView.ascx' wanneer het TopicsView-sjabloon wordt opgehaald. + + Beschrijving + + + Insigne + + + Sorteervolgorde + + + Badges + + + Insigne + + + Nieuwe badge + + + Drempel + + + Metriek + + + Beeld + + + Nieuwe gebruiker + + + Onderwerpen gemaakt + + + Gereageerd op onderwerpen + + + Likes ontvangen + + + Onderwerpen Lezen + + + Gebruikers bijwerken + + + HTML-opmaak voor badge (bijv. lettertype-geweldig) + + + De gebruiker kan slechts één keer een badge verdienen + + + # dagen tussen het verdienen van deze badge + + + Handleiding Award + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.resx b/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.resx index 29b30e2e0..250f424b5 100644 --- a/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.resx +++ b/Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.resx @@ -1585,4 +1585,61 @@ Your removal method is currently set to {0}. Your topics will be {1} based upon Enter a string to be used when retrieving templates. For example, if you want to have separate template files for moderated forums, enter 'moderated', and then templates will be retrieved using 'moderated' as part of the filename, e.g. 'TopicsView-moderated.ascx' rather than just 'TopicsView.ascx' when the TopicsView template is retrieved. + + Badge + + + Sort Order + + + Badges + + + Badge + + + New Badge + + + Threshold + + + Metric + + + Image + + + Manual Award + + + Description + + + New User + + + Topics Created + + + Replied to Topics + + + Likes Received + + + Topics Read + + + Update Users + + + HTML markup for badge (e.g., font-awesome) + + + User can only earn badge one time + + + # of days between earning this badge + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/Controlpanel.ascx.de-DE.resx b/Dnn.CommunityForums/App_LocalResources/Controlpanel.ascx.de-DE.resx index 35ece8151..5055f1517 100644 --- a/Dnn.CommunityForums/App_LocalResources/Controlpanel.ascx.de-DE.resx +++ b/Dnn.CommunityForums/App_LocalResources/Controlpanel.ascx.de-DE.resx @@ -1585,4 +1585,61 @@ Ihre Entfernungsmethode ist derzeit auf {0} eingestellt. Ihre Themen werden anh Geben Sie eine Zeichenfolge ein, die beim Abrufen von Vorlagen verwendet werden soll. Wenn Sie z. B. separate Vorlagendateien für moderierte Foren haben möchten, geben Sie "moderiert" ein, und dann werden die Vorlagen mit "moderiert" als Teil des Dateinamens abgerufen, z. B. "TopicsView-moderated.ascx" und nicht nur "TopicsView.ascx", wenn die TopicsView-Vorlage abgerufen wird. + + Beschreibung + + + Abzeichen + + + Sortierreihenfolge + + + Kennzeichen + + + Abzeichen + + + Neues Abzeichen + + + Schwelle + + + Metrik + + + Bild + + + Neuer Benutzer + + + Erstellte Themen + + + Auf Themen geantwortet + + + Erhaltene "Gefällt mir"-Angaben + + + Gelesene Themen + + + Aktualisieren von Benutzern + + + HTML-Markup für Badge (z. B. font-awesome) + + + Der Benutzer kann das Abzeichen nur einmal verdienen + + + # der Tage zwischen dem Erhalt dieses Abzeichens + + + Manuelle Auszeichnung + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/Controlpanel.ascx.es-ES.resx b/Dnn.CommunityForums/App_LocalResources/Controlpanel.ascx.es-ES.resx index 4e27b4a99..df0b5b4e8 100644 --- a/Dnn.CommunityForums/App_LocalResources/Controlpanel.ascx.es-ES.resx +++ b/Dnn.CommunityForums/App_LocalResources/Controlpanel.ascx.es-ES.resx @@ -1480,4 +1480,61 @@ El método de eliminación está configurado actualmente en {0}. Los temas se { Introduzca una cadena que se utilizará al recuperar plantillas. Por ejemplo, si desea tener archivos de plantilla separados para foros moderados, escriba 'moderados' y luego las plantillas se recuperarán usando 'moderados' como parte del nombre del archivo, por ejemplo, 'TopicsView-moderated.ascx' en lugar de solo 'TopicsView.ascx' cuando se recupere la plantilla TopicsView. + + Descripción + + + Insignia + + + Criterio de clasificación + + + Insignias + + + Insignia + + + Nueva insignia + + + Umbral + + + Métrico + + + Imagen + + + Nuevo usuario + + + Temas creados + + + Respondido a los temas + + + Me gusta recibidos + + + Temas leídos + + + Actualizar usuarios + + + Marcado HTML para insignia (por ejemplo, font-awesome) + + + El usuario solo puede ganar insignia una vez + + + # de días entre la obtención de esta insignia + + + Premio Manual + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/SharedResources.de-DE.resx b/Dnn.CommunityForums/App_LocalResources/SharedResources.de-DE.resx index 0c91d5a87..fc567bfca 100644 --- a/Dnn.CommunityForums/App_LocalResources/SharedResources.de-DE.resx +++ b/Dnn.CommunityForums/App_LocalResources/SharedResources.de-DE.resx @@ -814,9 +814,6 @@ Von Dies ist Ihre Standardeinstellung, wenn Sie ein Thema erstellen oder eine Antwort hinzufügen. Dies hat keine Auswirkungen auf Abonnements auf Forumsebene. - - Themen abonnieren - Der Forenadministrator hat Ihnen möglicherweise erlaubt, verschiedene Abonnementformen auszuwählen. Sie können Ihre gewünschte Präferenz auswählen. @@ -1862,4 +1859,40 @@ Von Abmelden + + Automatisches Abonnieren von "Meine Themen" + + + Erhalten Sie Benachrichtigungen über Abzeichenauszeichnungen + + + Wählen Sie diese Option aus, wenn Sie Benachrichtigungen erhalten möchten, wenn Sie ein neues Erfolgsabzeichen erhalten. + + + Glückwunsch! Sie wurden mit einem neuen Abzeichen belohnt! + + + [DCF:FORENLINK|Bitte <a href="{0}">besuchen Sie</a> , um weiter teilzunehmen und weitere Belohnungen zu erhalten.] + + + Senden Sie dem Benutzer eine Benachrichtigung, wenn er vergeben wird + + + Senden Sie einem älteren Benutzer keine Benachrichtigung, wenn Sie Prämien auffüllen + + + Zuletzt verliehen + + + Abzeichen + + + Benutzer, die mit dem Abzeichen ausgezeichnet wurden: {0} + + + Abzeichen für Benutzer: {0} + + + Badge noch nicht zugewiesen + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/SharedResources.es-ES.resx b/Dnn.CommunityForums/App_LocalResources/SharedResources.es-ES.resx index da5d91662..1699a9c59 100644 --- a/Dnn.CommunityForums/App_LocalResources/SharedResources.es-ES.resx +++ b/Dnn.CommunityForums/App_LocalResources/SharedResources.es-ES.resx @@ -814,9 +814,6 @@ De Esta será su configuración predeterminada cuando cree un tema o agregue una respuesta. Esto no afecta a las suscripciones a nivel de foro. - - Suscribirse a Temas - Es posible que el administrador del foro le haya permitido elegir diferentes formas de suscripción. Puede seleccionar su preferencia deseada. @@ -1861,4 +1858,40 @@ De Anular la suscripción + + Suscríbete automáticamente a Mis temas + + + Recibir notificaciones de premios de insignias + + + Seleccione esta opción si desea recibir notificaciones cuando se le otorgue una nueva insignia de logro. + + + ¡Felicidades! ¡Has sido recompensado con una nueva insignia! + + + [DCF:FORUMSLINK| <a href="{0}">Visite</a> para seguir participando y ganar más recompensas.] + + + Enviar una notificación al usuario cuando se otorgue + + + No envíes una notificación a un usuario mayor cuando rellenes premios + + + Última adjudicación + + + Insignia + + + Usuarios galardonados con la insignia: {0} + + + Insignias otorgadas al Usuario: {0} + + + Insignia aún no asignada + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/SharedResources.fr-FR.resx b/Dnn.CommunityForums/App_LocalResources/SharedResources.fr-FR.resx index 0797308dd..030347b82 100644 --- a/Dnn.CommunityForums/App_LocalResources/SharedResources.fr-FR.resx +++ b/Dnn.CommunityForums/App_LocalResources/SharedResources.fr-FR.resx @@ -811,9 +811,6 @@ De, Ceci sera votre réglage par défault lors de la création d'un sujet ou l'ajout d'une réponse. Ceci n'affecte pas l'abonnement au niveau du forum. - - S'abonner à des sujets - L'administrateur du forum peut vous avoir permis de choisir différents formulaires pour les abonnements. Vous pouvez choisir votre préférence ici. @@ -1858,4 +1855,40 @@ De, Se désabonner + + S’abonner automatiquement à Mes sujets + + + Recevoir des notifications d’attribution de badge + + + Sélectionnez cette option si vous souhaitez recevoir des notifications lorsque vous recevez un nouvel insigne de succès. + + + Félicitations! Vous avez été récompensé par un nouveau badge ! + + + [DCF :FORUMSLINK|Veuillez <a href="{0}">vous y rendre</a> pour continuer à participer et gagner plus de récompenses.] + + + Envoyer une notification à l’utilisateur lorsqu’il est attribué + + + N’envoyez pas de notification à un utilisateur plus âgé lors du rachat de récompenses + + + Dernier prix + + + Insigne + + + Utilisateurs ayant reçu le badge : {0} + + + Badges attribués à l’utilisateur : {0} + + + Badge non encore attribué + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/SharedResources.it-IT.resx b/Dnn.CommunityForums/App_LocalResources/SharedResources.it-IT.resx index e8184e45d..58bf45b79 100644 --- a/Dnn.CommunityForums/App_LocalResources/SharedResources.it-IT.resx +++ b/Dnn.CommunityForums/App_LocalResources/SharedResources.it-IT.resx @@ -814,9 +814,6 @@ Da Questa sarà l'impostazione predefinita quando crei un argomento o aggiungi una risposta. Ciò non influisce sulle iscrizioni a livello di forum. - - Iscriviti agli argomenti - L'amministratore del forum potrebbe averti permesso di scegliere diverse forme di iscrizione. È possibile selezionare la preferenza desiderata. @@ -1861,4 +1858,40 @@ Da Disiscrizione + + Iscrizione automatica ai miei argomenti + + + Ricevi le notifiche di assegnazione dei badge + + + Seleziona questa opzione se desideri ricevere notifiche quando ti viene assegnato un nuovo badge obiettivo. + + + Felicitazioni! Sei stato ricompensato con un nuovo distintivo! + + + [DCF:FORUMSLINK| <a href="{0}">Visita per</a> continuare a partecipare e guadagnare più premi.] + + + Invia una notifica all'utente quando viene assegnato + + + Non inviare una notifica a un utente meno recente durante il backfill dei premi + + + Ultimo premio + + + Distintivo + + + Utenti che hanno ricevuto il Badge: {0} + + + Badge assegnati all'Utente: {0} + + + Badge non ancora assegnato + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/SharedResources.nl-NL.resx b/Dnn.CommunityForums/App_LocalResources/SharedResources.nl-NL.resx index b39bed637..699b0f082 100644 --- a/Dnn.CommunityForums/App_LocalResources/SharedResources.nl-NL.resx +++ b/Dnn.CommunityForums/App_LocalResources/SharedResources.nl-NL.resx @@ -900,9 +900,6 @@ Type abonnement - - Abonneer op onderwerpen - Uw profiel is bijgewerkt. @@ -1897,4 +1894,40 @@ Van, Uitschrijven + + Automatisch abonneren op Mijn onderwerpen + + + Ontvang meldingen over badges + + + Selecteer deze optie als u meldingen wilt ontvangen wanneer u een nieuwe prestatiebadge krijgt. + + + Gefeliciteerd! Je bent beloond met een nieuwe badge! + + + [DCF:FORUMSLINK|Ga <a href="{0}">naar</a> om te blijven deelnemen en meer beloningen te verdienen.] + + + Stuur de gebruiker een melding wanneer deze is toegekend + + + Stuur een oudere gebruiker geen melding bij het aanvullen van awards + + + Laatst toegekend + + + Insigne + + + Gebruikers met een badge: {0} + + + Badges toegekend aan gebruiker: {0} + + + Badge nog niet toegekend + \ No newline at end of file diff --git a/Dnn.CommunityForums/App_LocalResources/SharedResources.resx b/Dnn.CommunityForums/App_LocalResources/SharedResources.resx index 199ccb5e8..3ba630b9d 100644 --- a/Dnn.CommunityForums/App_LocalResources/SharedResources.resx +++ b/Dnn.CommunityForums/App_LocalResources/SharedResources.resx @@ -904,7 +904,7 @@ Subscription Type - Subscribe to Topics + Auto-Subscribe to My Topics Your profile has been updated. @@ -1861,4 +1861,37 @@ From, Unsubscribe + + Receive Badge Award Notifications + + + Select this option if you wish to receive notifications when you are awarded a new achievement badge. + + + Congratulations! You've been rewarded with a new badge! + + + [DCF:FORUMSLINK|Please <a href="{0}">visit</a> to keep participating and earn more rewards.] + + + last awarded + + + Send user a notification when awarded + + + Don't send an older user a notification when backfilling awards + + + Badge + + + Users awarded Badge: {0} + + + Badges awarded to User: {0} + + + Badge not yet assigned + \ No newline at end of file diff --git a/Dnn.CommunityForums/Classic.ascx.cs b/Dnn.CommunityForums/Classic.ascx.cs index be8d512ab..ad0086494 100644 --- a/Dnn.CommunityForums/Classic.ascx.cs +++ b/Dnn.CommunityForums/Classic.ascx.cs @@ -61,13 +61,14 @@ protected override void OnLoad(EventArgs e) //ForumsConfig.Upgrade_PermissionSets_090000(); //DotNetNuke.Modules.ActiveForums.Helpers.UpgradeModuleSettings.DeleteObsoleteModuleSettings_090000(); //DotNetNuke.Modules.ActiveForums.Helpers.UpgradeModuleSettings.AddAvatarModuleSettings_090100(); + //new ForumsConfig().Install_DefaultBadges_090100(); #endif try { - if (this.MainSettings != null && this.MainSettings.InstallDate > Utilities.NullDate()) + if (this.ModuleSettings != null && this.ModuleSettings.InstallDate > Utilities.NullDate()) { if (this.ForumModuleId < 1) { @@ -102,6 +103,18 @@ protected override void OnLoad(EventArgs e) opts = $"{ParamKeys.ContentId}={this.Request.QueryString[ParamKeys.ContentId]}"; } } + else if (this.Request.Params[ParamKeys.ViewType] != null && this.Request.Params[ParamKeys.ViewType] == Views.Grid && this.Request.Params[ParamKeys.GridType] != null && this.Request.Params[ParamKeys.GridType] == Views.BadgeUsers) + { + ctl = Views.BadgeUsers; + if (this.Request.QueryString[ParamKeys.BadgeId] != null) + { + opts = $"{ParamKeys.BadgeId}={this.Request.QueryString[ParamKeys.BadgeId]}"; + } + } + else if (this.Request.Params[ParamKeys.ViewType] != null && this.Request.Params[ParamKeys.ViewType] == Views.Grid && this.Request.Params[ParamKeys.GridType] != null && this.Request.Params[ParamKeys.GridType] == Views.UserBadges) + { + ctl = Views.UserBadges; + } else if (this.Request.Params[ParamKeys.ViewType] != null) { ctl = this.Request.Params[ParamKeys.ViewType]; @@ -134,7 +147,7 @@ protected override void OnLoad(EventArgs e) if (this.Request.IsAuthenticated) { - if (this.MainSettings.UsersOnlineEnabled) + if (this.ModuleSettings.UsersOnlineEnabled) { DataProvider.Instance().Profiles_UpdateActivity(this.PortalId, this.UserId); } @@ -182,6 +195,14 @@ private void GetControl(string view, string options) { ctl = (ForumBase)this.LoadControl(this.Page.ResolveUrl(Globals.ModulePath + "controls/af_recycle_bin.ascx")); } + else if (view.ToUpperInvariant() == Views.UserBadges.ToUpperInvariant() && this.Request.IsAuthenticated) + { + ctl = (ForumBase)this.LoadControl(this.Page.ResolveUrl(Globals.ModulePath + "controls/af_assign_user_badges.ascx")); + } + else if (view.ToUpperInvariant() == Views.BadgeUsers.ToUpperInvariant() && this.Request.IsAuthenticated) + { + ctl = (ForumBase)this.LoadControl(this.Page.ResolveUrl(Globals.ModulePath + "controls/af_assign_badge_users.ascx")); + } else if (view.ToUpperInvariant() == "FORUMVIEW") { ctl = (ForumBase)new DotNetNuke.Modules.ActiveForums.Controls.ForumView(); @@ -287,8 +308,8 @@ private void GetControl(string view, string options) ControlsConfig cc = new ControlsConfig(); cc.AppPath = this.Page.ResolveUrl(Globals.ModulePath); - cc.ThemePath = this.Page.ResolveUrl(this.MainSettings.ThemeLocation); - cc.TemplatePath = this.Page.ResolveUrl(this.MainSettings.TemplatePath + "/"); + cc.ThemePath = this.Page.ResolveUrl(this.ModuleSettings.ThemeLocation); + cc.TemplatePath = this.Page.ResolveUrl(this.ModuleSettings.TemplatePath + "/"); cc.PortalId = this.PortalId; cc.PageId = this.TabId; cc.ModuleId = this.ModuleId; @@ -360,27 +381,27 @@ private void SetupPage() } } - if (System.IO.File.Exists(Utilities.MapPath(this.MainSettings.ThemeLocation + "theme.min.css"))) + if (System.IO.File.Exists(Utilities.MapPath(this.ModuleSettings.ThemeLocation + "theme.min.css"))) { - ClientResourceManager.RegisterStyleSheet(this.Page, this.MainSettings.ThemeLocation + "theme.min.css", priority: 12); + ClientResourceManager.RegisterStyleSheet(this.Page, this.ModuleSettings.ThemeLocation + "theme.min.css", priority: 12); } else { - if (System.IO.File.Exists(Utilities.MapPath(this.MainSettings.ThemeLocation + "theme.css"))) + if (System.IO.File.Exists(Utilities.MapPath(this.ModuleSettings.ThemeLocation + "theme.css"))) { - ClientResourceManager.RegisterStyleSheet(this.Page, this.MainSettings.ThemeLocation + "theme.css", priority: 12); + ClientResourceManager.RegisterStyleSheet(this.Page, this.ModuleSettings.ThemeLocation + "theme.css", priority: 12); } } - if (System.IO.File.Exists(Utilities.MapPath(this.MainSettings.ThemeLocation + "custom/theme.min.css"))) + if (System.IO.File.Exists(Utilities.MapPath(this.ModuleSettings.ThemeLocation + "custom/theme.min.css"))) { - ClientResourceManager.RegisterStyleSheet(this.Page, this.MainSettings.ThemeLocation + "custom/theme.min.css", priority: 13); + ClientResourceManager.RegisterStyleSheet(this.Page, this.ModuleSettings.ThemeLocation + "custom/theme.min.css", priority: 13); } else { - if (System.IO.File.Exists(Utilities.MapPath(this.MainSettings.ThemeLocation + "custom/theme.css"))) + if (System.IO.File.Exists(Utilities.MapPath(this.ModuleSettings.ThemeLocation + "custom/theme.css"))) { - ClientResourceManager.RegisterStyleSheet(this.Page, this.MainSettings.ThemeLocation + "custom/theme.css", priority: 13); + ClientResourceManager.RegisterStyleSheet(this.Page, this.ModuleSettings.ThemeLocation + "custom/theme.css", priority: 13); } } @@ -421,7 +442,7 @@ private void SetupPage() sLoadImg += "var afSpin = new Image();afSpin.src='" + VirtualPathUtility.ToAbsolute(Globals.ModulePath + "images/spinner.gif") + "';"; sb.AppendLine(sLoadImg); sb.AppendLine(Utilities.LocalizeControl(Utilities.GetFile(Utilities.MapPath(Globals.ModulePath + "scripts/resx.js")), false, true)); - if (HttpContext.Current.Request.IsAuthenticated && this.MainSettings.UsersOnlineEnabled) + if (HttpContext.Current.Request.IsAuthenticated && this.ModuleSettings.UsersOnlineEnabled) { sb.AppendLine("setInterval('amaf_updateuseronline(" + this.ModuleId.ToString() + ")',120000);"); } diff --git a/Dnn.CommunityForums/ControlPanel.ascx b/Dnn.CommunityForums/ControlPanel.ascx index 6a5006706..ffcf5275d 100644 --- a/Dnn.CommunityForums/ControlPanel.ascx +++ b/Dnn.CommunityForums/ControlPanel.ascx @@ -167,6 +167,7 @@ + diff --git a/Dnn.CommunityForums/ControlPanel.ascx.cs b/Dnn.CommunityForums/ControlPanel.ascx.cs index ecf539c41..659320ee7 100644 --- a/Dnn.CommunityForums/ControlPanel.ascx.cs +++ b/Dnn.CommunityForums/ControlPanel.ascx.cs @@ -49,18 +49,22 @@ protected override void OnLoad(EventArgs e) this.btnReturn.ClientSideScript = "window.location.href = '" + Utilities.NavigateURL(this.TabId) + "';"; this.cbModal.LoadingTemplate = this.GetLoadingTemplateSmall(); - Hashtable settings = DotNetNuke.Entities.Modules.ModuleController.Instance.GetModule(moduleId: this.ModuleId, tabId: this.TabId, ignoreCache: false).ModuleSettings; - if (Convert.ToBoolean(settings["AFINSTALLED"]) == false) + + if (!this.Page.IsPostBack) { - try - { - var fc = new ForumsConfig(); - bool configComplete = fc.ForumsInit(this.PortalId, this.ModuleId); - DotNetNuke.Entities.Modules.ModuleController.Instance.UpdateModuleSetting(this.ModuleId, "AFINSTALLED", configComplete.ToString()); - } - catch (Exception ex) + Hashtable settings = DotNetNuke.Entities.Modules.ModuleController.Instance.GetModule(moduleId: this.ModuleId, tabId: this.TabId, ignoreCache: false).ModuleSettings; + if (Convert.ToBoolean(settings["AFINSTALLED"]) == false) { - DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + try + { + var fc = new ForumsConfig(); + bool configComplete = fc.ForumsInit(this.PortalId, this.ModuleId); + DotNetNuke.Entities.Modules.ModuleController.Instance.UpdateModuleSetting(this.ModuleId, "AFINSTALLED", configComplete.ToString()); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } } } diff --git a/Dnn.CommunityForums/Controllers/BadgeController.cs b/Dnn.CommunityForums/Controllers/BadgeController.cs new file mode 100644 index 000000000..2196e94aa --- /dev/null +++ b/Dnn.CommunityForums/Controllers/BadgeController.cs @@ -0,0 +1,86 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// Badge 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 Badge 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.ActiveForums.Controllers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using DotNetNuke.Modules.ActiveForums.Entities; + using static DotNetNuke.Entities.Modules.DesktopModuleInfo; + + /// + /// Controller for managing badges in the DNN Community Forums module. + /// + internal class BadgeController : DotNetNuke.Modules.ActiveForums.Controllers.RepositoryControllerBase + { + internal override string cacheKeyTemplate => CacheKeys.BadgeInfo; + + /// + /// Gets all active badges. + /// + /// List of active badges. + public IEnumerable GetActiveBadges(int moduleId) + { + return this.Get().Where(b => b.ModuleId.Equals(moduleId)); + } + + internal DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo GetById(int badgeId, int moduleId) + { + var cachekey = this.GetCacheKey(moduleId: moduleId, id: badgeId); + DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo badgeInfo = DataCache.SettingsCacheRetrieve(moduleId, cachekey) as DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo; + if (badgeInfo == null) + { + badgeInfo = base.GetById(badgeId, moduleId); + DotNetNuke.Modules.ActiveForums.DataCache.SettingsCacheStore(moduleId, cachekey, badgeInfo); + } + + return badgeInfo; + } + + internal new void DeleteById(TProperty badgeId, int moduleId) + { + var cachekey = this.GetCacheKey(moduleId: moduleId, id: badgeId); + DataCache.SettingsCacheClear(moduleId, cachekey); + this.DeleteById(badgeId); + } + + internal new void Delete(DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo badgeInfo) + { + var cachekey = this.GetCacheKey(moduleId: badgeInfo.ModuleId, id: badgeInfo.BadgeId); + DataCache.SettingsCacheClear(badgeInfo.ModuleId, cachekey); + base.Delete(badgeInfo); + } + + internal new DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo Insert(DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo badgeInfo) + { + base.Insert(badgeInfo); + return this.GetById(badgeInfo.BadgeId, badgeInfo.ModuleId); + } + + internal new DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo Update(DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo badgeInfo) + { + var cachekey = this.GetCacheKey(moduleId: badgeInfo.ModuleId, id: badgeInfo.BadgeId); + DataCache.SettingsCacheClear(badgeInfo.ModuleId, cachekey); + base.Update(badgeInfo); + return this.GetById(badgeInfo.BadgeId, badgeInfo.ModuleId); + } + } +} diff --git a/Dnn.CommunityForums/Controllers/EmailController.cs b/Dnn.CommunityForums/Controllers/EmailController.cs index 2dbef5fb8..12780ed04 100644 --- a/Dnn.CommunityForums/Controllers/EmailController.cs +++ b/Dnn.CommunityForums/Controllers/EmailController.cs @@ -51,7 +51,7 @@ internal static void SendEmail(Enums.TemplateType templateType, int tabId, DotNe fi.FeatureSettings.EmailNotificationSubjectTemplate : (!string.IsNullOrEmpty(fi.ForumGroup.FeatureSettings.EmailNotificationSubjectTemplate) ? fi.ForumGroup.FeatureSettings.EmailNotificationSubjectTemplate : - SettingsBase.GetModuleSettings(fi.ModuleId).ForumFeatureSettings.EmailNotificationSubjectTemplate); + SettingsBase.GetModuleSettings(fi.ModuleId).DefaultFeatureSettings.EmailNotificationSubjectTemplate); var bodyTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(fi.ModuleId, templateType, fi.FeatureSettings.TemplateFileNameSuffix); var subject = TemplateUtils.ParseEmailTemplate(subjectTemplate, fi.PortalId, fi.ModuleId, tabId, fi.ForumID, topicId, replyId, author, accessingUser: author.ForumUser, topicSubscriber: false, new Services.URLNavigator().NavigationManager(), HttpContext.Current.Request.Url, HttpContext.Current.Request.RawUrl); var body = TemplateUtils.ParseEmailTemplate(bodyTemplate, fi.PortalId, fi.ModuleId, tabId, fi.ForumID, topicId, replyId, author, accessingUser: author.ForumUser, topicSubscriber: false, new Services.URLNavigator().NavigationManager(), HttpContext.Current.Request.Url, HttpContext.Current.Request.RawUrl); @@ -82,7 +82,7 @@ internal static void SendTemplatedEmail(int topicId, int replyId, int moduleId, fi.FeatureSettings.EmailNotificationSubjectTemplate : (!string.IsNullOrEmpty(fi.ForumGroup.FeatureSettings.EmailNotificationSubjectTemplate) ? fi.ForumGroup.FeatureSettings.EmailNotificationSubjectTemplate : - SettingsBase.GetModuleSettings(moduleId).ForumFeatureSettings.EmailNotificationSubjectTemplate); + SettingsBase.GetModuleSettings(moduleId).DefaultFeatureSettings.EmailNotificationSubjectTemplate); IEnumerable userCultures = subs.Select(s => s.UserCulture).Distinct(); foreach (CultureInfo userCulture in userCultures) { @@ -105,7 +105,7 @@ internal static void SendTemplatedEmail(int topicId, int replyId, int moduleId, { topicSubscriber.Email, }, - Subject = Utilities.StripHTMLTag(TemplateUtils.ParseEmailTemplate(subjectTemplate, portalID: fi.PortalId, moduleID: moduleId, tabID: tabId, forumID: fi.ForumID, topicId: topicId, replyId: replyId, author: author, accessingUser: topicSubscriber.User, topicSubscriber: true, navigationManager: navigationManager, requestUrl: requestUrl, rawUrl: rawUrl)), + Subject = Utilities.StripHTMLTag(System.Net.WebUtility.HtmlDecode(TemplateUtils.ParseEmailTemplate(subjectTemplate, portalID: fi.PortalId, moduleID: moduleId, tabID: tabId, forumID: fi.ForumID, topicId: topicId, replyId: replyId, author: author, accessingUser: topicSubscriber.User, topicSubscriber: true, navigationManager: navigationManager, requestUrl: requestUrl, rawUrl: rawUrl))), Body = TemplateUtils.ParseEmailTemplate(bodyTemplate, portalID: fi.PortalId, moduleID: moduleId, tabID: tabId, forumID: fi.ForumID, topicId: topicId, replyId: replyId, author: author, accessingUser: topicSubscriber.User, topicSubscriber: true, navigationManager: navigationManager, requestUrl: requestUrl, rawUrl: rawUrl), }); } @@ -122,7 +122,7 @@ internal static void SendTemplatedEmail(int topicId, int replyId, int moduleId, { forumSubscriber.Email, }, - Subject = Utilities.StripHTMLTag(TemplateUtils.ParseEmailTemplate(subjectTemplate, portalID: fi.PortalId, moduleID: moduleId, tabID: tabId, forumID: fi.ForumID, topicId: topicId, replyId: replyId, author: author, accessingUser: forumSubscriber.User, topicSubscriber: false, navigationManager: navigationManager, requestUrl: requestUrl, rawUrl: rawUrl)), + Subject = Utilities.StripHTMLTag(System.Net.WebUtility.HtmlDecode(TemplateUtils.ParseEmailTemplate(subjectTemplate, portalID: fi.PortalId, moduleID: moduleId, tabID: tabId, forumID: fi.ForumID, topicId: topicId, replyId: replyId, author: author, accessingUser: forumSubscriber.User, topicSubscriber: false, navigationManager: navigationManager, requestUrl: requestUrl, rawUrl: rawUrl))), Body = TemplateUtils.ParseEmailTemplate(bodyTemplate, portalID: fi.PortalId, moduleID: moduleId, tabID: tabId, forumID: fi.ForumID, topicId: topicId, replyId: replyId, author: author, accessingUser: forumSubscriber.User, topicSubscriber: false, navigationManager: navigationManager, requestUrl: requestUrl, rawUrl: rawUrl), }); } diff --git a/Dnn.CommunityForums/Controllers/ForumController.cs b/Dnn.CommunityForums/Controllers/ForumController.cs index e0e89c5ad..420cf00a2 100644 --- a/Dnn.CommunityForums/Controllers/ForumController.cs +++ b/Dnn.CommunityForums/Controllers/ForumController.cs @@ -260,14 +260,14 @@ public int Forums_Save(int portalId, DotNetNuke.Modules.ActiveForums.Entities.Fo copyDownGroupSettings = true; } - forumInfo.ForumSettingsKey = useGroupFeatures ? (forumGroupInfo != null ? forumGroupInfo.GroupSettingsKey : string.Empty) : (forumInfo.ForumID > 0 ? $"F:{forumInfo.ForumID}" : string.Empty); + forumInfo.ForumSettingsKey = useGroupFeatures ? (forumGroupInfo != null ? forumGroupInfo.GroupSettingsKey : string.Empty) : (forumInfo.ForumID > 0 ? $"F{forumInfo.ForumID}" : string.Empty); // TODO: When this method is updated to use DAL2 for update, uncomment Cacheable attribute on ForumInfo var forumId = Convert.ToInt32(DotNetNuke.Modules.ActiveForums.DataProvider.Instance().Forum_Save(portalId, forumInfo.ForumID, forumInfo.ModuleId, forumInfo.ForumGroupId, forumInfo.ParentForumId, forumInfo.ForumName, forumInfo.ForumDesc, forumInfo.SortOrder, forumInfo.Active, forumInfo.Hidden, forumInfo.ForumSettingsKey, forumInfo.PermissionsId, forumInfo.PrefixURL, forumInfo.SocialGroupId, forumInfo.HasProperties)); forumInfo = this.GetById(forumId, forumInfo.ModuleId); if (!useGroupFeatures && string.IsNullOrEmpty(forumInfo.ForumSettingsKey)) { - forumInfo.ForumSettingsKey = $"F:{forumId}"; + forumInfo.ForumSettingsKey = $"F{forumId}"; this.Update(forumInfo); } @@ -287,7 +287,7 @@ public int Forums_Save(int portalId, DotNetNuke.Modules.ActiveForums.Entities.Fo // if now inheriting group settings, remove any previously-defined forum settings if (forumInfo.InheritSettings) { - DataContext.Instance().Execute(System.Data.CommandType.Text, "DELETE FROM {databaseOwner}{objectQualifier}activeforums_Settings WHERE ModuleId = @0 AND GroupKey = @1", forumInfo.ModuleId, $"F:{forumInfo.ForumID}"); + new DotNetNuke.Modules.ActiveForums.Controllers.SettingsController().DeleteForModuleIdSettingsKey(forumInfo.ModuleId, $"F{forumInfo.ForumID}"); } // Clear the caches @@ -314,14 +314,14 @@ internal static void IterateForumsList(System.Collections.Generic.List subForumAction, bool includeHiddenForums) { - string tmpGroupKey = string.Empty; + string tmpSettingsKey = string.Empty; foreach (DotNetNuke.Modules.ActiveForums.Entities.ForumInfo fi in forums.Where(f => (includeHiddenForums || !f.Hidden) && f.ForumGroup != null && (includeHiddenForums || !f.ForumGroup.Hidden) && (forumUserInfo.IsSuperUser || DotNetNuke.Modules.ActiveForums.Controllers.PermissionController.HasRequiredPerm(f.Security?.ViewRoleIds, forumUserInfo.UserRoleIds)))) { - string groupKey = $"{fi.GroupName}{fi.ForumGroupId}"; - if (tmpGroupKey != groupKey) + string settingsKey = $"{fi.GroupName}{fi.ForumGroupId}"; + if (tmpSettingsKey != settingsKey) { groupAction(fi); - tmpGroupKey = groupKey; + tmpSettingsKey = settingsKey; } if (fi.ParentForumId == 0) diff --git a/Dnn.CommunityForums/Controllers/ForumGroupController.cs b/Dnn.CommunityForums/Controllers/ForumGroupController.cs index 744cee541..73b673968 100644 --- a/Dnn.CommunityForums/Controllers/ForumGroupController.cs +++ b/Dnn.CommunityForums/Controllers/ForumGroupController.cs @@ -120,7 +120,7 @@ public int Groups_Save(int portalId, DotNetNuke.Modules.ActiveForums.Entities.Fo if (!isNew || forumGroupInfo.InheritSettings) { // reset any forum settings keys previously mapped to the module default to map to new settings key - forumGroupInfo.GroupSettingsKey = $"G:{forumGroupInfo.ForumGroupId}"; + forumGroupInfo.GroupSettingsKey = $"G{forumGroupInfo.ForumGroupId}"; foreach (var forum in fc.GetForums(moduleId: forumGroupInfo.ModuleId).Where(f => f.ForumGroupId == forumGroupInfo.ForumGroupId && f.ForumSettingsKey == SettingsBase.GetModuleSettings(forumGroupInfo.ModuleId).DefaultSettingsKey)) { forum.ForumSettingsKey = forumGroupInfo.GroupSettingsKey; @@ -135,14 +135,14 @@ public int Groups_Save(int portalId, DotNetNuke.Modules.ActiveForums.Entities.Fo forumGroupInfo = this.GetById(forumGroupInfo.ForumGroupId, forumGroupInfo.ModuleId); if (string.IsNullOrEmpty(forumGroupInfo.GroupSettingsKey)) { - forumGroupInfo.GroupSettingsKey = $"G:{forumGroupInfo.ForumGroupId}"; + forumGroupInfo.GroupSettingsKey = $"G{forumGroupInfo.ForumGroupId}"; this.Update(forumGroupInfo); } // if new group and not using default features, copy default features to group features as starting point if (copyDownDefaultSettings) { - forumGroupInfo.FeatureSettings = SettingsBase.GetModuleSettings(forumGroupInfo.ModuleId).ForumFeatureSettings; + forumGroupInfo.FeatureSettings = SettingsBase.GetModuleSettings(forumGroupInfo.ModuleId).DefaultFeatureSettings; FeatureSettings.Save(forumGroupInfo.ModuleId, forumGroupInfo.GroupSettingsKey, forumGroupInfo.FeatureSettings); this.Update(forumGroupInfo); } @@ -152,9 +152,10 @@ public int Groups_Save(int portalId, DotNetNuke.Modules.ActiveForums.Entities.Fo new DotNetNuke.Modules.ActiveForums.Controllers.PermissionController().RemoveIfUnused(permissionId: oldPermissionsId, moduleId: forumGroupInfo.ModuleId); } - if (useDefaultFeatures) /* if now using default module settings, remove group settings */ + /* if now using default module settings, remove group settings */ + if (useDefaultFeatures) { - DataContext.Instance().Execute(System.Data.CommandType.Text, "DELETE FROM {databaseOwner}{objectQualifier}activeforums_Settings WHERE ModuleId = @0 AND GroupKey = @1", forumGroupInfo.ModuleId, $"G:{forumGroupInfo.ForumGroupId}"); + new DotNetNuke.Modules.ActiveForums.Controllers.SettingsController().DeleteForModuleIdSettingsKey(forumGroupInfo.ModuleId, $"G{forumGroupInfo.ForumGroupId}"); } ClearSettingsCache(forumGroupInfo.ModuleId); diff --git a/Dnn.CommunityForums/Controllers/ForumUserController.cs b/Dnn.CommunityForums/Controllers/ForumUserController.cs index c6cab0db9..e36671c0d 100644 --- a/Dnn.CommunityForums/Controllers/ForumUserController.cs +++ b/Dnn.CommunityForums/Controllers/ForumUserController.cs @@ -21,24 +21,18 @@ namespace DotNetNuke.Modules.ActiveForums.Controllers { using System; + using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Web; using System.Web.UI.WebControls; + using DotNetNuke.Data; - using DotNetNuke.Data; - using DotNetNuke.Entities.Portals; using DotNetNuke.Entities.Portals; using DotNetNuke.Entities.Users; - using DotNetNuke.Entities.Users; - using DotNetNuke.Services.GeneratedImage; - using DotNetNuke.Services.Journal; using DotNetNuke.Services.Journal; using DotNetNuke.Services.Log.EventLog; - using DotNetNuke.Services.Log.EventLog; - using DotNetNuke.Services.Social.Notifications; - using DotNetNuke.UI.UserControls; internal class ForumUserController : DotNetNuke.Modules.ActiveForums.Controllers.RepositoryControllerBase { @@ -65,6 +59,25 @@ public DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo GetById(int profil throw new NotImplementedException("There is no probably need to call this method; if you do, you probably should be using GetByUserId."); } + public IEnumerable GetActiveUsers(int portalId) + { + var forumUsers = this.Get().Where(u => u.PortalId.Equals(portalId)); + var users = DotNetNuke.Entities.Users.UserController.GetUsers(includeDeleted: false, superUsersOnly: false, portalId: portalId); + var superUsers = DotNetNuke.Entities.Users.UserController.GetUsers(includeDeleted: false, superUsersOnly: true, portalId: DotNetNuke.Common.Utilities.Null.NullInteger); + users.AddRange(superUsers); + return forumUsers + .Join( + users.Cast(), + forumUser => forumUser.UserId, + user => user.UserID, + (forumUser, user) => + { + forumUser.UserInfo = user; + return forumUser; + } + ); + } + public DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo GetByUserId(int portalId, int userId) { var cachekey = this.GetCacheKey(portalId: portalId, id: userId); @@ -90,6 +103,7 @@ public DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo GetByUserId(int po PrefBlockSignatures = false, PrefBlockAvatars = false, PrefTopicSubscribe = false, + BadgeNotificationsEnabled = true, LikeNotificationsEnabled = true, PrefJumpLastPost = false, PrefDefaultShowReplies = false, @@ -222,11 +236,13 @@ public static int Save(DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo us return forumUser.UserId; } + [Obsolete("Deprecated in Community Forums. Removing in 10.00.00. Not Needed.")] public bool GetUserIsAdmin(int portalId, int moduleId, int userId) { return this.GetByUserId(portalId, userId).IsAdmin; } + [Obsolete("Deprecated in Community Forums. Removing in 10.00.00. Not Needed.")] public bool GetUserIsSuperUser(int portalId, int moduleId, int userId) { return this.GetByUserId(portalId, userId).IsSuperUser; @@ -363,7 +379,7 @@ public static string GetUserRank(int moduleId, DotNetNuke.Modules.ActiveForums.E } } - internal static bool CanLinkToProfile(DotNetNuke.Entities.Portals.PortalSettings portalSettings, SettingsInfo mainSettings, int moduleId, DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo accessingUser, DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo forumUser) + internal static bool CanLinkToProfile(DotNetNuke.Entities.Portals.PortalSettings portalSettings, ModuleSettings moduleSettings, int moduleId, DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo accessingUser, DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo forumUser) { if (portalSettings == null) { @@ -380,7 +396,7 @@ internal static bool CanLinkToProfile(DotNetNuke.Entities.Portals.PortalSettings portalSettings?.UserTabId != DotNetNuke.Common.Utilities.Null.NullInteger && portalSettings?.UserTabId != -1) { - var profileVisibility = mainSettings.ProfileVisibility; + var profileVisibility = moduleSettings.ProfileVisibility; switch (profileVisibility) { @@ -409,7 +425,7 @@ internal static bool CanLinkToProfile(DotNetNuke.Entities.Portals.PortalSettings return canLinkToProfile; } - internal static string GetDisplayName(DotNetNuke.Entities.Portals.PortalSettings portalSettings, SettingsInfo mainSettings, bool isMod, bool isAdmin, int userId, string username, string firstName = "", string lastName = "", string displayName = "") + internal static string GetDisplayName(DotNetNuke.Entities.Portals.PortalSettings portalSettings, ModuleSettings mainSettings, bool isMod, bool isAdmin, int userId, string username, string firstName = "", string lastName = "", string displayName = "") { if (portalSettings == null) { @@ -526,18 +542,31 @@ internal static string GetAvatar(PortalSettings portalSettings, int userId, int internal static void UpdateUserTopicCount(int portalId, int userId) { - string sSql = "UPDATE {databaseOwner}{objectQualifier}activeforums_UserProfiles SET TopicCount = ISNULL((Select Count(t.TopicId) FROM "; - sSql += "{databaseOwner}{objectQualifier}activeforums_Topics as t INNER JOIN "; - sSql += "{databaseOwner}{objectQualifier}activeforums_Content as c ON t.ContentId = c.ContentId AND c.AuthorId = @1 INNER JOIN "; - sSql += "{databaseOwner}{objectQualifier}activeforums_ForumTopics as ft ON ft.TopicId = t.TopicId INNER JOIN "; - sSql += "{databaseOwner}{objectQualifier}activeforums_Forums as f ON ft.ForumId = f.ForumId "; + string sSql = "UPDATE {databaseOwner}{objectQualifier}activeforums_UserProfiles SET TopicCount = ISNULL((SELECT COUNT(t.TopicId) "; + sSql += "FROM {databaseOwner}{objectQualifier}activeforums_Topics as t "; + sSql += "INNER JOIN {databaseOwner}{objectQualifier}activeforums_Content as c ON c.ContentId = t.ContentId AND c.AuthorId = @1 "; + sSql += "INNER JOIN {databaseOwner}{objectQualifier}activeforums_ForumTopics as ft ON ft.TopicId = t.TopicId "; + sSql += "INNER JOIN {databaseOwner}{objectQualifier}activeforums_Forums as f ON f.ForumId = ft.ForumId "; sSql += "WHERE c.AuthorId = @1 AND t.IsApproved = 1 AND t.IsDeleted=0 AND f.PortalId=@0),0) "; sSql += "WHERE UserId = @1 AND PortalId = @0"; DataContext.Instance().Execute(System.Data.CommandType.Text, sSql, portalId, userId); DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.ClearCache(portalId, userId); } - internal string GetUsersOnline(DotNetNuke.Entities.Portals.PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.SettingsInfo mainSettings, int moduleId, DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo forumUser) + internal static void UpdateUserReplyCount(int portalId, int userId) + { + string sSql = "UPDATE {databaseOwner}{objectQualifier}activeforums_UserProfiles SET ReplyCount = ISNULL((SELECT COUNT(r.ReplyId) "; + sSql += "FROM {databaseOwner}{objectQualifier}activeforums_Replies as r "; + sSql += "INNER JOIN {databaseOwner}{objectQualifier}activeforums_Content as c ON c.ContentId = r.ContentId AND c.AuthorId = @1 "; + sSql += "INNER JOIN {databaseOwner}{objectQualifier}activeforums_ForumTopics as ft ON ft.TopicId = r.TopicId "; + sSql += "INNER JOIN {databaseOwner}{objectQualifier}activeforums_Forums as f ON f.ForumId = ft.ForumId "; + sSql += "WHERE c.AuthorId = @1 AND r.IsApproved = 1 AND r.IsDeleted=0 AND f.PortalId=@0),0) "; + sSql += "WHERE UserId = @1 AND PortalId = @0"; + DataContext.Instance().Execute(System.Data.CommandType.Text, sSql, portalId, userId); + DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.ClearCache(portalId, userId); + } + + internal string GetUsersOnline(DotNetNuke.Entities.Portals.PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings mainSettings, int moduleId, DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo forumUser) { bool isAdmin = forumUser.IsAdmin || forumUser.IsSuperUser; var sb = new StringBuilder(); diff --git a/Dnn.CommunityForums/Controllers/LikeController.cs b/Dnn.CommunityForums/Controllers/LikeController.cs index 6f1e91257..7b0f38dbd 100644 --- a/Dnn.CommunityForums/Controllers/LikeController.cs +++ b/Dnn.CommunityForums/Controllers/LikeController.cs @@ -157,6 +157,7 @@ public int Like(int contentId, int userId, int authorId, int tabId, int forumGro contentId: contentId, authorId: authorId, userId: userId, + badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: requestUrl); } diff --git a/Dnn.CommunityForums/Controllers/ProcessQueueController.cs b/Dnn.CommunityForums/Controllers/ProcessQueueController.cs index 8755c5955..447189f54 100644 --- a/Dnn.CommunityForums/Controllers/ProcessQueueController.cs +++ b/Dnn.CommunityForums/Controllers/ProcessQueueController.cs @@ -29,7 +29,12 @@ namespace DotNetNuke.Modules.ActiveForums.Controllers internal class ProcessQueueController : DotNetNuke.Modules.ActiveForums.Controllers.RepositoryControllerBase { - public bool Add(ProcessType processType, int portalId, int tabId, int moduleId, int forumGroupId, int forumId, int topicId, int replyId, int contentId, int authorId, int userId, string requestUrl) + public bool Add(ProcessType processType, int portalId, int tabId, int moduleId, int forumGroupId, int forumId, int topicId, int replyId, int contentId, int authorId, int userId, int badgeId, string requestUrl) + { + return this.Add(processType: processType, portalId: portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, badgeId: badgeId, dateCreated: DateTime.UtcNow, requestUrl: requestUrl); + } + + public bool Add(ProcessType processType, int portalId, int tabId, int moduleId, int forumGroupId, int forumId, int topicId, int replyId, int contentId, int authorId, int userId, int badgeId, DateTime dateCreated, string requestUrl) { try { @@ -46,7 +51,8 @@ public bool Add(ProcessType processType, int portalId, int tabId, int moduleId, ContentId = contentId, AuthorId = authorId, UserId = userId, - DateCreated = DateTime.UtcNow, + BadgeId = badgeId, + DateCreated = dateCreated, RequestUrl = requestUrl, }); return true; diff --git a/Dnn.CommunityForums/Controllers/ReplyController.cs b/Dnn.CommunityForums/Controllers/ReplyController.cs index 21c024985..b66ddbdde 100644 --- a/Dnn.CommunityForums/Controllers/ReplyController.cs +++ b/Dnn.CommunityForums/Controllers/ReplyController.cs @@ -28,6 +28,7 @@ namespace DotNetNuke.Modules.ActiveForums.Controllers using DotNetNuke.Collections; using DotNetNuke.Modules.ActiveForums.Enums; using DotNetNuke.Modules.ActiveForums.Services.ProcessQueue; + using DotNetNuke.Modules.ActiveForums.ViewModels; using DotNetNuke.Services.FileSystem; using DotNetNuke.Services.Log.EventLog; @@ -270,12 +271,12 @@ public DotNetNuke.Modules.ActiveForums.Entities.ReplyInfo ApproveReply(int porta internal static bool QueueApprovedReplyAfterAction(int portalId, int tabId, int moduleId, int forumGroupId, int forumId, int topicId, int replyId, int contentId, int authorId, int userId) { - return new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.ApprovedReplyCreated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, requestUrl: HttpContext.Current.Request.Url.ToString()); + return new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.ApprovedReplyCreated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: HttpContext.Current.Request.Url.ToString()); } internal static bool QueueUnapprovedReplyAfterAction(int portalId, int tabId, int moduleId, int forumGroupId, int forumId, int topicId, int replyId, int contentId, int authorId, int userId) { - return new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.UnapprovedReplyCreated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, requestUrl: HttpContext.Current.Request.Url.ToString()); + return new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.UnapprovedReplyCreated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: HttpContext.Current.Request.Url.ToString()); } internal static bool ProcessApprovedReplyAfterAction(int portalId, int tabId, int moduleId, int forumGroupId, int forumId, int topicId, int replyId, int contentId, int authorId, int userId, string requestUrl) @@ -315,10 +316,16 @@ internal static bool ProcessApprovedReplyAfterAction(int portalId, int tabId, in DataCache.CacheClearPrefix(reply.ModuleId, string.Format(CacheKeys.TopicViewPrefix, reply.ModuleId)); DataCache.CacheClearPrefix(reply.ModuleId, string.Format(CacheKeys.TopicsViewPrefix, reply.ModuleId)); var pqc = new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController(); - pqc.Add(ProcessType.UpdateForumTopicPointers, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, requestUrl: requestUrl); - pqc.Add(ProcessType.UpdateForumLastUpdated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, requestUrl: requestUrl); + pqc.Add(ProcessType.UpdateForumTopicPointers, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: requestUrl); + pqc.Add(ProcessType.UpdateForumLastUpdated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: requestUrl); Utilities.UpdateModuleLastContentModifiedOnDate(moduleId); + + if (reply.IsApproved && reply.Content.AuthorId > 0) + { + DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.UpdateUserReplyCount(portalId, reply.Content.AuthorId); + } + return true; } catch (Exception ex) diff --git a/Dnn.CommunityForums/Controllers/RepositoryControllerBase.cs b/Dnn.CommunityForums/Controllers/RepositoryControllerBase.cs index a1e420a38..654a7e05b 100644 --- a/Dnn.CommunityForums/Controllers/RepositoryControllerBase.cs +++ b/Dnn.CommunityForums/Controllers/RepositoryControllerBase.cs @@ -84,14 +84,14 @@ internal IPagedList Find(int pageIndex, int pageSize, string sqlCondition, pa internal void Update(T item) { + var property = typeof(T).GetProperty("DateUpdated"); + if (property != null && property.CanWrite && property.PropertyType == typeof(System.DateTime)) + { + property.SetValue(item, System.DateTime.UtcNow, null); + } this.repo.Update(item); } - public void Update(string sqlCondition, params object[] args) - { - this.repo.Update(sqlCondition, args); - } - internal void Insert(T item) { this.repo.Insert(item); diff --git a/Dnn.CommunityForums/Controllers/SettingsController.cs b/Dnn.CommunityForums/Controllers/SettingsController.cs new file mode 100644 index 000000000..0c05a20c0 --- /dev/null +++ b/Dnn.CommunityForums/Controllers/SettingsController.cs @@ -0,0 +1,91 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Controllers +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Text.RegularExpressions; + + using DotNetNuke.Collections; + + internal class SettingsController : DotNetNuke.Modules.ActiveForums.Controllers.RepositoryControllerBase + { + public static void SaveSetting(int moduleId, string settingsKey, string settingName, string settingValue) + { + try + { + var sc = new DotNetNuke.Modules.ActiveForums.Controllers.SettingsController(); + var setting = sc.GetSettingForModuleIdSettingsKeySettingName(moduleId, settingsKey, settingName); + if (setting == null) + { + setting = new DotNetNuke.Modules.ActiveForums.Entities.SettingsInfo + { + ModuleId = moduleId, + SettingsKey = settingsKey, + SettingName = settingName, + SettingValue = settingValue, + }; + sc.Insert(setting); + } + else + { + setting.SettingValue = settingValue; + sc.Update(setting); + } + } + catch (Exception ex) + { + DotNetNuke.Modules.ActiveForums.Exceptions.LogException(ex); + } + } + + public IEnumerable GetSettingsForModuleIdSettingsKey(int moduleID, string settingsKey) + { + return this.Find("WHERE ModuleId = @0 AND SettingsKey = @1", moduleID, settingsKey); + } + + public Hashtable GetSettingsHashTableForModuleIdSettingsKey(int moduleId, string settingsKey) + { + var ht = new Hashtable(); + this.GetSettingsForModuleIdSettingsKey(moduleId, settingsKey).ForEach(s => ht.Add(s.SettingName, s.SettingValue)); + return ht; + } + + public DotNetNuke.Modules.ActiveForums.Entities.SettingsInfo GetSettingForModuleIdSettingsKeySettingName(int moduleID, string settingsKey, string settingName) + { + return this.Find("WHERE ModuleId = @0 AND SettingsKey = @1 AND SettingName = @2", moduleID, settingsKey, settingName).FirstOrDefault(); + } + + public void DeleteForModuleIdSettingsKey(int moduleId, string settingsKey) + { + this.Delete("WHERE ModuleId = @0 AND SettingsKey = @1", moduleId, settingsKey); + } + + public void DeleteForModuleIdSettingsKeySettingName(int moduleId, string settingsKey, string settingName) + { + this.Delete("WHERE ModuleId = @0 AND SettingsKey = @1 AND SettingName = @2", moduleId, settingsKey, settingName); + } + } +} diff --git a/Dnn.CommunityForums/Controllers/TemplateController.cs b/Dnn.CommunityForums/Controllers/TemplateController.cs index 15bbbdf5f..3a8d65e8b 100644 --- a/Dnn.CommunityForums/Controllers/TemplateController.cs +++ b/Dnn.CommunityForums/Controllers/TemplateController.cs @@ -35,7 +35,7 @@ public void Template_Save(int moduleId, DotNetNuke.Modules.ActiveForums.Entities { string templatePathFileName = Globals.TemplatesPath + templateInfo.FileName; - SettingsInfo moduleSettings = SettingsBase.GetModuleSettings(moduleId); + ModuleSettings moduleSettings = SettingsBase.GetModuleSettings(moduleId); templatePathFileName = moduleSettings.TemplatePath + templateInfo.FileName; if (!System.IO.Directory.Exists(Utilities.MapPath(moduleSettings.TemplatePath))) { @@ -53,7 +53,7 @@ public void Template_Save(int moduleId, DotNetNuke.Modules.ActiveForums.Entities public void Template_Delete(int moduleId, Enums.TemplateType templateType, string templateFileNameSuffix) { string fileNameBase = templateType.ToString().ToLowerInvariant(); - SettingsInfo moduleSettings = SettingsBase.GetModuleSettings(moduleId); + ModuleSettings moduleSettings = SettingsBase.GetModuleSettings(moduleId); try { if (!string.IsNullOrEmpty(templateFileNameSuffix)) @@ -101,7 +101,7 @@ private static string Template_Get(int moduleId, string templateBaseFileName, st string sTemplate = string.Empty; string fileName = string.Empty; string templateFilePathFileName = string.Empty; - SettingsInfo moduleSettings = SettingsBase.GetModuleSettings(moduleId); + ModuleSettings moduleSettings = SettingsBase.GetModuleSettings(moduleId); templateBaseFileName = templateBaseFileName.ToLowerInvariant(); string cacheKey = string.Format(CacheKeys.Template, moduleId, templateBaseFileName, templateFileNameSuffix); object obj = null; diff --git a/Dnn.CommunityForums/Controllers/TopicController.cs b/Dnn.CommunityForums/Controllers/TopicController.cs index 6e880ce6c..d9e5fdadf 100644 --- a/Dnn.CommunityForums/Controllers/TopicController.cs +++ b/Dnn.CommunityForums/Controllers/TopicController.cs @@ -199,7 +199,7 @@ public static void Move(int moduleId, int userId, int topicId, int newForumId) { DotNetNuke.Modules.ActiveForums.Entities.TopicInfo ti = new DotNetNuke.Modules.ActiveForums.Controllers.TopicController(moduleId).GetById(topicId); int oldForumId = (int)ti.ForumId; - SettingsInfo settings = SettingsBase.GetModuleSettings(ti.ModuleId); + ModuleSettings settings = SettingsBase.GetModuleSettings(ti.ModuleId); if (settings.URLRewriteEnabled) { try @@ -231,8 +231,8 @@ public static void Move(int moduleId, int userId, int topicId, int newForumId) DotNetNuke.Modules.ActiveForums.Controllers.EmailController.SendEmail(TemplateType.ModMove, ti.Forum.GetTabId(), oldForum, topicId: ti.TopicId, replyId: -1, author: ti.Author); } - new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.UpdateForumLastUpdated, ti.PortalId, tabId: -1, moduleId: ti.ModuleId, forumGroupId: oldForum.ForumGroupId, forumId: oldForum.ForumID, topicId: topicId, replyId: -1, contentId: ti.ContentId, authorId: ti.Content.AuthorId, userId: userId, requestUrl: null); - new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.UpdateForumLastUpdated, ti.PortalId, tabId: -1, moduleId: ti.ModuleId, forumGroupId: newForum.ForumGroupId, forumId: newForum.ForumID, topicId: topicId, replyId: -1, contentId: ti.ContentId, authorId: ti.Content.AuthorId, userId: userId, requestUrl: null); + new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.UpdateForumLastUpdated, ti.PortalId, tabId: -1, moduleId: ti.ModuleId, forumGroupId: oldForum.ForumGroupId, forumId: oldForum.ForumID, topicId: topicId, replyId: -1, contentId: ti.ContentId, authorId: ti.Content.AuthorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: null); + new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.UpdateForumLastUpdated, ti.PortalId, tabId: -1, moduleId: ti.ModuleId, forumGroupId: newForum.ForumGroupId, forumId: newForum.ForumID, topicId: topicId, replyId: -1, contentId: ti.ContentId, authorId: ti.Content.AuthorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: null); Utilities.UpdateModuleLastContentModifiedOnDate(ti.ModuleId); DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheClearForForum(moduleId, ti.ForumId); DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheClearForTopic(moduleId, topicId); @@ -265,13 +265,6 @@ public static int Save(DotNetNuke.Modules.ActiveForums.Entities.TopicInfo ti) ti.Content.DateCreated = DateTime.UtcNow; } - if (ti.IsApproved && ti.Author.AuthorId > 0) - { - // TODO: put this in a better place and make it consistent with reply counter - DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.UpdateUserTopicCount(ti.Forum.PortalId, ti.Author.AuthorId); - } - - DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.ClearCache(ti.Forum.PortalId, ti.Content.AuthorId); Utilities.UpdateModuleLastContentModifiedOnDate(ti.ModuleId); DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheClearForForum(ti.ModuleId, ti.ForumId); DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheClearForTopic(ti.ModuleId, ti.TopicId); @@ -355,12 +348,12 @@ public void DeleteById(int topicId, DotNetNuke.Modules.ActiveForums.Enums.Delete internal static bool QueueApprovedTopicAfterAction(int portalId, int tabId, int moduleId, int forumGroupId, int forumId, int topicId, int replyId, int contentId, int authorId, int userId) { - return new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.ApprovedTopicCreated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, requestUrl: HttpContext.Current.Request.Url.ToString()); + return new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.ApprovedTopicCreated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: HttpContext.Current.Request.Url.ToString()); } internal static bool QueueUnapprovedTopicAfterAction(int portalId, int tabId, int moduleId, int forumGroupId, int forumId, int topicId, int replyId, int contentId, int authorId, int userId) { - return new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.UnapprovedTopicCreated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, requestUrl: HttpContext.Current.Request.Url.ToString()); + return new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add(ProcessType.UnapprovedTopicCreated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: HttpContext.Current.Request.Url.ToString()); } internal static bool ProcessApprovedTopicAfterAction(int portalId, int tabId, int moduleId, int forumGroupId, int forumId, int topicId, int replyId, int contentId, int authorId, int userId, string requestUrl) @@ -386,11 +379,16 @@ internal static bool ProcessApprovedTopicAfterAction(int portalId, int tabId, in amas.AddTopicToJournal(portalId, moduleId, tabId, forumId, topicId, topic.Author.AuthorId, sUrl, topic.Content.Subject, string.Empty, topic.Content.Body, topic.Forum.Security.Read, topic.Forum.SocialGroupId); var pqc = new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController(); - pqc.Add(ProcessType.UpdateForumTopicPointers, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, requestUrl: requestUrl); - pqc.Add(ProcessType.UpdateForumLastUpdated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, requestUrl: requestUrl); + pqc.Add(ProcessType.UpdateForumTopicPointers, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: requestUrl); + pqc.Add(ProcessType.UpdateForumLastUpdated, portalId, tabId: tabId, moduleId: moduleId, forumGroupId: forumGroupId, forumId: forumId, topicId: topicId, replyId: replyId, contentId: contentId, authorId: authorId, userId: userId, badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: requestUrl); Utilities.UpdateModuleLastContentModifiedOnDate(moduleId); + if (topic.IsApproved && topic.Content.AuthorId > 0) + { + DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.UpdateUserTopicCount(portalId, topic.Content.AuthorId); + } + return true; } catch (Exception ex) diff --git a/Dnn.CommunityForums/Controllers/TopicTrackingController.cs b/Dnn.CommunityForums/Controllers/TopicTrackingController.cs index f76dcb696..458878b88 100644 --- a/Dnn.CommunityForums/Controllers/TopicTrackingController.cs +++ b/Dnn.CommunityForums/Controllers/TopicTrackingController.cs @@ -20,6 +20,7 @@ namespace DotNetNuke.Modules.ActiveForums.Controllers { + using System; using System.Linq; using DotNetNuke.Data; @@ -53,5 +54,17 @@ internal int GetTopicsReadCountForUserForum(int moduleId, int userId, int forumI return (int)topicReadCount; } + + internal int GetTopicsReadCountByUser(int moduleId, int userId) + { + // this accommodates duplicates which may exist since currently no uniqueness applied in database + return DataContext.Instance().ExecuteQuery(System.Data.CommandType.Text, "SELECT COUNT(*) FROM {databaseOwner}{objectQualifier}activeforums_Topics_Tracking tt WHERE tt.UserId = @0", userId).FirstOrDefault(); + } + + internal int GetTopicsReadCountByUser(int moduleId, int userId, DateTime minDateTime) + { + // this accommodates duplicates which may exist since currently no uniqueness applied in database + return DataContext.Instance().ExecuteQuery(System.Data.CommandType.Text, "SELECT COUNT(*) FROM {databaseOwner}{objectQualifier}activeforums_Topics_Tracking tt WHERE tt.UserId = @0 AND DateAdded IS NOT NULL AND DateAdded >= @1", userId, minDateTime).FirstOrDefault(); + } } } diff --git a/Dnn.CommunityForums/Controllers/UrlController.cs b/Dnn.CommunityForums/Controllers/UrlController.cs index 7a4c90d4c..9da339828 100644 --- a/Dnn.CommunityForums/Controllers/UrlController.cs +++ b/Dnn.CommunityForums/Controllers/UrlController.cs @@ -93,14 +93,14 @@ internal static string BuildForumUrlSegment(int portalId, int moduleId, DotNetNu return url; } - internal static string BuildForumUrl(INavigationManager navigationManager, DotNetNuke.Abstractions.Portals.IPortalSettings portalSettings, SettingsInfo mainSettings, DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forumInfo) + internal static string BuildForumUrl(INavigationManager navigationManager, DotNetNuke.Abstractions.Portals.IPortalSettings portalSettings, ModuleSettings mainSettings, DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forumInfo) { // Build the forum Url return mainSettings.UseShortUrls ? navigationManager.NavigateURL(forumInfo.GetTabId(), portalSettings, string.Empty, new[] { $"{ParamKeys.ForumId}={forumInfo.ForumID}" }) : navigationManager.NavigateURL(forumInfo.GetTabId(), portalSettings, string.Empty, new[] { $"{ParamKeys.ForumId}={forumInfo.ForumID}", $"{ParamKeys.ViewType}={Views.Topics}" }); } - internal static string BuildModeratorUrl(INavigationManager navigationManager, DotNetNuke.Abstractions.Portals.IPortalSettings portalSettings, SettingsInfo mainSettings, DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forumInfo) + internal static string BuildModeratorUrl(INavigationManager navigationManager, DotNetNuke.Abstractions.Portals.IPortalSettings portalSettings, ModuleSettings mainSettings, DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forumInfo) { return navigationManager.NavigateURL(forumInfo.GetTabId(), portalSettings, string.Empty, new[] { $"{ParamKeys.ViewType}={Views.ModerateTopics}", $"{ParamKeys.ForumId}={forumInfo.ForumID}" }); } diff --git a/Dnn.CommunityForums/Controllers/UserBadgeController.cs b/Dnn.CommunityForums/Controllers/UserBadgeController.cs new file mode 100644 index 000000000..d8b1bb401 --- /dev/null +++ b/Dnn.CommunityForums/Controllers/UserBadgeController.cs @@ -0,0 +1,280 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Controllers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + using DotNetNuke.Collections; + using DotNetNuke.Modules.ActiveForums.Services.ProcessQueue; + using DotNetNuke.Services.Log.EventLog; + using DotNetNuke.Services.Social.Notifications; + + internal partial class UserBadgeController : RepositoryControllerBase + { + private readonly int moduleId = -1; + private readonly int portalId = -1; + + internal override string cacheKeyTemplate => CacheKeys.UserBadgeInfo; + + internal UserBadgeController() + { + } + + internal UserBadgeController(int portalId, int moduleId) + { + this.portalId = portalId; + this.moduleId = moduleId; + } + + internal DotNetNuke.Modules.ActiveForums.Entities.UserBadgeInfo GetById(int id) + { + var cachekey = this.GetCacheKey(moduleId: this.moduleId, id: id); + DotNetNuke.Modules.ActiveForums.Entities.UserBadgeInfo UserBadge = DataCache.ContentCacheRetrieve(this.moduleId, cachekey) as DotNetNuke.Modules.ActiveForums.Entities.UserBadgeInfo; + if (UserBadge == null) + { + UserBadge = this.GetById(id, this.moduleId); + if (UserBadge != null) + { + UserBadge.ModuleId = this.moduleId; + UserBadge.PortalId = this.portalId; + UserBadge.GetBadge(); + UserBadge.GetForumUser(); + } + + DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheStore(this.moduleId, cachekey, UserBadge); + } + + return UserBadge; + } + + internal IEnumerable GetForUser(int portalId, int userId) + { + var cachekey = string.Format(CacheKeys.UserBadges, this.moduleId, userId); + var UserBadges = (IEnumerable)DataCache.ContentCacheRetrieve(this.moduleId, cachekey); + + if (UserBadges == null) + { + UserBadges = this.Find("WHERE PortalId = @0 AND UserId = @1", portalId, userId); + DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheStore(this.moduleId, cachekey, UserBadges); + } + + return UserBadges; + } + + internal IEnumerable GetDistinctForUser(int portalId, int userId) + { + var cachekey = string.Format(CacheKeys.UserBadges, this.moduleId, userId); + var distinctUserBadges = (IEnumerable)DataCache.ContentCacheRetrieve(this.moduleId, cachekey); + + if (distinctUserBadges == null) + { + distinctUserBadges = this.Find("WHERE PortalId = @0 AND UserId = @1", portalId, userId) + .GroupBy(b => b.BadgeId) + .Select(g => g.OrderByDescending(b => b.DateAssigned).First()) + .ToList(); + DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheStore(this.moduleId, cachekey, distinctUserBadges); + } + + return distinctUserBadges; + } + + internal IEnumerable GetForUserAndBadge(int portalId, int userId, int badgeId) + { + return this.Find("WHERE PortalId = @0 AND UserId = @1 AND BadgeId = @2", portalId, userId, badgeId); + } + + internal DotNetNuke.Modules.ActiveForums.Entities.UserBadgeInfo GetForUserAndBadgeAndDateAssigned(int portalId, int userId, int badgeId, DateTime dateAssigned) + { + return this.Find("WHERE PortalId = @0 AND UserId = @1 AND BadgeId = @2 AND DateAssigned = @3", portalId, userId, badgeId, dateAssigned).FirstOrDefault(); + } + + internal DotNetNuke.Modules.ActiveForums.Entities.UserBadgeInfo GetLatestForUserAndBadge(int portalId, int userId, int badgeId) + { + return this.Find("WHERE PortalId = @0 AND UserId = @1 AND BadgeId = @2", portalId, userId, badgeId).OrderByDescending(b => b.DateAssigned).FirstOrDefault(); + } + + internal IEnumerable GetForBadge(int badgeId) + { + var cachekey = string.Format(CacheKeys.BadgeUsers, this.moduleId, badgeId); + var UserBadges = (IEnumerable)DataCache.ContentCacheRetrieve(this.moduleId, cachekey); + + if (UserBadges == null) + { + UserBadges = this.Find("WHERE BadgeId = @0", badgeId); + DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheStore(this.moduleId, cachekey, UserBadges); + } + + return UserBadges; + } + + internal int BadgeCount(int portalId, int userId, int badgeId) + { + var cachekey = string.Format(CacheKeys.BadgeUserCount, this.moduleId, badgeId, userId); + var count = (int?)DataCache.ContentCacheRetrieve(this.moduleId, cachekey); + if (count == null) + { + count = this.Count("WHERE PortalId = @0 AND UserId = @1 AND BadgeId = @2", portalId, userId, badgeId); + DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheStore(this.moduleId, cachekey, count); + } + + return (int)count; + } + + internal static void AssignUserBadge(int portalId, int moduleId, int userId, int badgeId, string requestUrl) + { + try + { + var award = true; + var userBadgeController = new DotNetNuke.Modules.ActiveForums.Controllers.UserBadgeController(portalId: portalId, moduleId: moduleId); + DotNetNuke.Modules.ActiveForums.Entities.UserBadgeInfo userBadge = null; + var badge = new DotNetNuke.Modules.ActiveForums.Controllers.BadgeController().GetById(badgeId); + if (badge.OneTimeAward) + { + userBadge = userBadgeController.GetLatestForUserAndBadge(portalId: portalId, userId: userId, badgeId: badgeId); + if (userBadge != null) + { + // If the badge is one-time award and already assigned, do not reassign. + award = false; + } + } + + if (award) + { + userBadge = new DotNetNuke.Modules.ActiveForums.Entities.UserBadgeInfo + { + BadgeId = badgeId, + UserId = userId, + PortalId = portalId, + ModuleId = moduleId, + DateAssigned = DateTime.UtcNow, + }; + userBadgeController.Insert(userBadge); + ClearBadgeCache(userBadge); + + new DotNetNuke.Modules.ActiveForums.Controllers.ProcessQueueController().Add( + processType: ProcessType.BadgeAssigned, + portalId: portalId, + tabId: DotNetNuke.Common.Utilities.Null.NullInteger, + moduleId: moduleId, + forumGroupId: DotNetNuke.Common.Utilities.Null.NullInteger, + forumId: DotNetNuke.Common.Utilities.Null.NullInteger, + topicId: DotNetNuke.Common.Utilities.Null.NullInteger, + replyId: DotNetNuke.Common.Utilities.Null.NullInteger, + contentId: DotNetNuke.Common.Utilities.Null.NullInteger, + authorId: DotNetNuke.Common.Utilities.Null.NullInteger, + userId: userId, + badgeId: badgeId, + dateCreated: userBadge.DateAssigned, + requestUrl: requestUrl); + } + } + catch (Exception e) + { + DotNetNuke.Modules.ActiveForums.Exceptions.LogException(e); + } + } + + private static void ClearBadgeCache(DotNetNuke.Modules.ActiveForums.Entities.UserBadgeInfo userBadge) + { + DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheClear(userBadge.ModuleId, string.Format(CacheKeys.UserBadgeInfo, userBadge.ModuleId, userBadge.UserBadgeId)); + DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheClear(userBadge.ModuleId, string.Format(CacheKeys.UserBadges, userBadge.ModuleId, userBadge.UserId)); + DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheClear(userBadge.ModuleId, string.Format(CacheKeys.BadgeUsers, userBadge.ModuleId, userBadge.BadgeId)); + DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheClear(userBadge.ModuleId, string.Format(CacheKeys.BadgeUserCount, userBadge.ModuleId, userBadge.BadgeId, userBadge.UserId)); + } + + internal void UnassignUserBadge(int portalId, int userId, int badgeId, DateTime dateAssigned) + { + try + { + var userBadge = this.GetForUserAndBadgeAndDateAssigned(portalId: portalId, userId: userId, badgeId: badgeId, dateAssigned: dateAssigned); + if (userBadge != null) + { + ClearBadgeCache(userBadge); + this.DeleteById(userBadge.UserBadgeId); + } + } + catch (Exception e) + { + DotNetNuke.Modules.ActiveForums.Exceptions.LogException(e); + } + } + + internal bool AssignUserBadgeAfterAction(int portalId, int userId, int badgeId, DateTime dateAssigned, string requestUrl) + { + try + { + var userBadge = this.GetForUserAndBadgeAndDateAssigned(portalId: portalId, userId: userId, badgeId: badgeId, dateAssigned: dateAssigned); + if (userBadge == null) + { + // If the user badge does not exist, cannot proceed but return true to indicate no error occurred; we just won't send a notification but need to clear the process action from the queue. + return true; + } + + // Check if badge notifications should be sent to the user. + // Conditions: + // - The badge is configured to send award notifications. + // - The forum user has enabled badge notifications. + // - Either notifications are not suppressed for backfill, or user was assigned badge after backfill completed date. + if (userBadge.ForumUser.BadgeNotificationsEnabled + && userBadge.Badge.SendAwardNotification + && (!userBadge.Badge.SuppresssAwardNotificationOnBackfill + || (userBadge.Badge.InitialBackfillCompletedDate.HasValue && userBadge.DateAssigned > userBadge.Badge.InitialBackfillCompletedDate.Value))) + { + var subject = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.moduleId, Enums.TemplateType.BadgeNotificationSubject, SettingsBase.GetModuleSettings(this.moduleId).DefaultFeatureSettings.TemplateFileNameSuffix); + subject = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceBadgeTokens(new StringBuilder(subject), userBadge, userBadge.ForumUser.PortalSettings, userBadge.ForumUser.ModuleSettings, new Services.URLNavigator().NavigationManager(), userBadge.ForumUser, string.IsNullOrEmpty(requestUrl) ? null : new Uri(requestUrl), string.IsNullOrEmpty(requestUrl) ? string.Empty : new Uri(requestUrl).PathAndQuery).ToString(); + subject = subject.Length > 400 ? subject.Substring(0, 400) : subject; + var body = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.moduleId, Enums.TemplateType.BadgeNotificationBody, SettingsBase.GetModuleSettings(this.moduleId).DefaultFeatureSettings.TemplateFileNameSuffix); + body = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceBadgeTokens(new StringBuilder(body), userBadge, userBadge.ForumUser.PortalSettings, userBadge.ForumUser.ModuleSettings, new Services.URLNavigator().NavigationManager(), userBadge.ForumUser, string.IsNullOrEmpty(requestUrl) ? null : new Uri(requestUrl), string.IsNullOrEmpty(requestUrl) ? string.Empty : new Uri(requestUrl).PathAndQuery).ToString(); + + string notificationKey = BuildNotificationContextKey(this.portalId, this.moduleId, badgeId, userId, userBadge.DateAssigned); + + NotificationType notificationType = NotificationsController.Instance.GetNotificationType(Globals.BadgeNotificationType); + Notification notification = new Notification + { + NotificationTypeID = notificationType.NotificationTypeId, + Subject = subject, + Body = body, + IncludeDismissAction = true, + SenderUserID = userId, + Context = notificationKey, + }; + var users = new List { userBadge.ForumUser.UserInfo }; + NotificationsController.Instance.SendNotification(notification, this.portalId, null, users); + } + + return true; + } + catch (Exception e) + { + DotNetNuke.Modules.ActiveForums.Exceptions.LogException(e); + return false; + } + } + + private static string BuildNotificationContextKey(int portalId, int moduleId, int badgeId, int userId, DateTime dateAssigned) + { + return $"{portalId}:{moduleId}:{badgeId}:{userId}:{dateAssigned}"; + } + } +} diff --git a/Dnn.CommunityForums/CustomControls/HTML/TopicBrowser.cs b/Dnn.CommunityForums/CustomControls/HTML/TopicBrowser.cs index 4a475059d..d0e45ff17 100644 --- a/Dnn.CommunityForums/CustomControls/HTML/TopicBrowser.cs +++ b/Dnn.CommunityForums/CustomControls/HTML/TopicBrowser.cs @@ -67,7 +67,7 @@ public class TopicBrowser public bool MaintainPage { get; set; } = false; - private SettingsInfo _mainSettings = null; + private ModuleSettings _mainSettings = null; private bool _canEdit = false; public string Render() diff --git a/Dnn.CommunityForums/CustomControls/ServerControls/QuickReply.cs b/Dnn.CommunityForums/CustomControls/ServerControls/QuickReply.cs index e9d4f10a4..cb048bd9e 100644 --- a/Dnn.CommunityForums/CustomControls/ServerControls/QuickReply.cs +++ b/Dnn.CommunityForums/CustomControls/ServerControls/QuickReply.cs @@ -182,7 +182,7 @@ private void SaveQuickReply() DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forumInfo = DotNetNuke.Modules.ActiveForums.Controllers.ForumController.Forums_Get(this.portalId, this.moduleId, this.ForumId, false, this.TopicId); if (!Utilities.HasFloodIntervalPassed(floodInterval: this.ForumInfo.MainSettings.FloodInterval, forumUser: this.ForumUser, forumInfo: forumInfo)) { - this.plhMessage.Controls.Add(new InfoMessage { Message = "
" + string.Format(this.GetSharedResource("[RESX:Error:FloodControl]"), this.MainSettings.FloodInterval) + "
" }); + this.plhMessage.Controls.Add(new InfoMessage { Message = "
" + string.Format(this.GetSharedResource("[RESX:Error:FloodControl]"), this.ModuleSettings.FloodInterval) + "
" }); return; } diff --git a/Dnn.CommunityForums/CustomControls/ServerControls/TagCloud.cs b/Dnn.CommunityForums/CustomControls/ServerControls/TagCloud.cs index 9d086e207..8c01cd9a5 100644 --- a/Dnn.CommunityForums/CustomControls/ServerControls/TagCloud.cs +++ b/Dnn.CommunityForums/CustomControls/ServerControls/TagCloud.cs @@ -60,7 +60,7 @@ protected override void Render(HtmlTextWriter writer) } } - SettingsInfo _mainSettings = SettingsBase.GetModuleSettings(this.ModuleId); + ModuleSettings _mainSettings = SettingsBase.GetModuleSettings(this.ModuleId); Data.Common db = new Data.Common(); IDataReader dr = db.TagCloud_Get(this.PortalId, this.ModuleId, this.ForumIds, this.TagCount); ControlUtils ctlUtils = new ControlUtils(); diff --git a/Dnn.CommunityForums/CustomControls/ServerControls/TopicNavigator.cs b/Dnn.CommunityForums/CustomControls/ServerControls/TopicNavigator.cs index 8d066d286..78c319bc1 100644 --- a/Dnn.CommunityForums/CustomControls/ServerControls/TopicNavigator.cs +++ b/Dnn.CommunityForums/CustomControls/ServerControls/TopicNavigator.cs @@ -79,7 +79,7 @@ protected override void Render(HtmlTextWriter writer) tb.ModuleId = this.ForumModuleId; tb.TabId = this.ForumTabId; tb.PageIndex = this.PageId; - tb.PageSize = this.MainSettings.PageSize; + tb.PageSize = this.ModuleSettings.PageSize; tb.Template = this.ItemTemplate.Text; // tb.HeaderTemplate = HeaderTemplate.Text diff --git a/Dnn.CommunityForums/CustomControls/ServerControls/TopicsNavigator.cs b/Dnn.CommunityForums/CustomControls/ServerControls/TopicsNavigator.cs index 9e69f3e83..ace2b23d9 100644 --- a/Dnn.CommunityForums/CustomControls/ServerControls/TopicsNavigator.cs +++ b/Dnn.CommunityForums/CustomControls/ServerControls/TopicsNavigator.cs @@ -130,7 +130,7 @@ protected override void Render(HtmlTextWriter writer) tb.ForumUser = this.ForumUser; tb.PageIndex = this.PageId; - tb.PageSize = this.MainSettings.PageSize; + tb.PageSize = this.ModuleSettings.PageSize; tb.Template = this.ItemTemplate.Text; tb.HeaderTemplate = this.HeaderTemplate.Text; tb.FooterTemplate = this.FooterTemplate.Text; diff --git a/Dnn.CommunityForums/CustomControls/UserControls/ForumView.cs b/Dnn.CommunityForums/CustomControls/UserControls/ForumView.cs index 293402c32..27928f82c 100644 --- a/Dnn.CommunityForums/CustomControls/UserControls/ForumView.cs +++ b/Dnn.CommunityForums/CustomControls/UserControls/ForumView.cs @@ -142,18 +142,18 @@ public string BuildForumView() { try { - string sTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.ForumModuleId, Enums.TemplateType.ForumView, SettingsBase.GetModuleSettings(this.ForumModuleId).ForumFeatureSettings.TemplateFileNameSuffix); + string sTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.ForumModuleId, Enums.TemplateType.ForumView, SettingsBase.GetModuleSettings(this.ForumModuleId).DefaultFeatureSettings.TemplateFileNameSuffix); StringBuilder stringBuilder = new StringBuilder(sTemplate); #region "Backward compatilbility -- remove in v10.00.00" stringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.RemoveObsoleteTokens(stringBuilder); - stringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyUserTokenSynonyms(stringBuilder, this.PortalSettings, this.MainSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale); + stringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyUserTokenSynonyms(stringBuilder, this.PortalSettings, this.ModuleSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale); stringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyForumTokenSynonyms(stringBuilder, this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale); #endregion "Backward compatilbility -- remove in v10.00.00" stringBuilder.Replace("[JUMPTO]", ""); stringBuilder.Replace("[STATISTICS]", ""); - stringBuilder.Replace("[WHOSONLINE]", this.MainSettings.UsersOnlineEnabled ? "" : string.Empty); + stringBuilder.Replace("[WHOSONLINE]", this.ModuleSettings.UsersOnlineEnabled ? "" : string.Empty); if (stringBuilder.ToString().Contains("[NOTOOLBAR]")) { @@ -233,7 +233,7 @@ public string BuildForumView() sGroupName = this.Forums?.Where(f => f.ForumID == this.ParentForumId).FirstOrDefault().GroupName; } - if (this.MainSettings.UseSkinBreadCrumb && this.Forums?.Count > 0 && this.SubsOnly == false && this.ForumGroupId != -1) + if (this.ModuleSettings.UseSkinBreadCrumb && this.Forums?.Count > 0 && this.SubsOnly == false && this.ForumGroupId != -1) { DotNetNuke.Modules.ActiveForums.Environment.UpdateBreadCrumb(this.Page.Controls, "" + sGroupName + ""); sTemplate = sTemplate.Replace("
[FORUMMAINLINK] > [FORUMGROUPLINK]
", string.Empty); @@ -253,7 +253,7 @@ public string BuildForumView() foreach (var fi in this.Forums.Where(f => !this.SubsOnly || f.ParentForumId > 0).OrderBy(f => f.ForumGroup?.SortOrder).ThenBy(f => f.ForumGroupId).ThenBy(f => f.SortOrder).Take(Globals.ForumCount)) { fi.PortalSettings = this.PortalSettings; - fi.MainSettings = this.MainSettings; + fi.MainSettings = this.ModuleSettings; bool canView = DotNetNuke.Modules.ActiveForums.Controllers.PermissionController.HasRequiredPerm(fi.Security?.ViewRoleIds, this.ForumUser.UserRoleIds); if (this.UserInfo.IsSuperUser || (canView && !fi.ForumGroup.Hidden)) { @@ -272,12 +272,12 @@ public string BuildForumView() sGroupSectionTemp = TemplateUtils.GetTemplateSection(sTemplate, "[GROUPSECTION]", "[/GROUPSECTION]"); StringBuilder sGroupSectionTempStringBuilder = new StringBuilder(sGroupSectionTemp); - sGroupSectionTempStringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumGroupTokens(sGroupSectionTempStringBuilder, fi.ForumGroup, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl); + sGroupSectionTempStringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumGroupTokens(sGroupSectionTempStringBuilder, fi.ForumGroup, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl); sGroupSectionTemp = sGroupSectionTempStringBuilder.ToString(); // any replacements on the group StringBuilder sNewGroupStringBuilder = new StringBuilder("
" + sGroupTemplate + "
"); - sNewGroupStringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumGroupTokens(sNewGroupStringBuilder, fi.ForumGroup, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl); + sNewGroupStringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumGroupTokens(sNewGroupStringBuilder, fi.ForumGroup, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl); string sNewGroup = sNewGroupStringBuilder.ToString(); sGroupSectionTemp = TemplateUtils.ReplaceSubSection(sGroupSectionTemp, sNewGroup, "[GROUP]", "[/GROUP]"); @@ -385,7 +385,7 @@ private string ParseForumRow(string template, DotNetNuke.Modules.ActiveForums.En } StringBuilder templateStringBuilder = new StringBuilder(template); - templateStringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(templateStringBuilder, fi, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl); + templateStringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(templateStringBuilder, fi, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl); if (templateStringBuilder.ToString().Contains("[AF:CONTROL:TOGGLESUBSCRIBE]")) { @@ -426,7 +426,7 @@ private string GetSubForums(string template, int forumId, int tabId) string subForum; foreach (DotNetNuke.Modules.ActiveForums.Entities.ForumInfo fi in subforums) { - subForum = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(new StringBuilder("[FORUMLINK]"), fi, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl).ToString(); + subForum = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(new StringBuilder("[FORUMLINK]"), fi, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl).ToString(); if (subForum != string.Empty) { sb.Append(subForum); diff --git a/Dnn.CommunityForums/CustomControls/UserControls/Members.cs b/Dnn.CommunityForums/CustomControls/UserControls/Members.cs index 6ad9bf607..24c136a64 100644 --- a/Dnn.CommunityForums/CustomControls/UserControls/Members.cs +++ b/Dnn.CommunityForums/CustomControls/UserControls/Members.cs @@ -97,8 +97,8 @@ protected override void OnLoad(EventArgs e) private void BuildControl() { System.Text.StringBuilder sb = new System.Text.StringBuilder(1024); - SettingsInfo moduleSettings = SettingsBase.GetModuleSettings(this.ForumModuleId); - string sTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.ForumModuleId, Enums.TemplateType._memberList, SettingsBase.GetModuleSettings(this.ForumModuleId).ForumFeatureSettings.TemplateFileNameSuffix); + ModuleSettings moduleSettings = SettingsBase.GetModuleSettings(this.ForumModuleId); + string sTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.ForumModuleId, Enums.TemplateType._memberList, SettingsBase.GetModuleSettings(this.ForumModuleId).DefaultFeatureSettings.TemplateFileNameSuffix); if (!(sTemplate == string.Empty)) { string sGrid = TemplateUtils.GetTemplateSection(sTemplate, "[AF:CONTROL:LIST]", "[/AF:CONTROL:LIST]"); @@ -212,7 +212,7 @@ private string BuildAlphaList() { List upl = new List(); DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo upi = null; - this.pageSize = this.MainSettings.PageSize; + this.pageSize = this.ModuleSettings.PageSize; if (this.PageId == 1) { this.rowIndex = 0; diff --git a/Dnn.CommunityForums/CustomControls/UserControls/SubmitForm.cs b/Dnn.CommunityForums/CustomControls/UserControls/SubmitForm.cs index 280317f4b..aac847a8e 100644 --- a/Dnn.CommunityForums/CustomControls/UserControls/SubmitForm.cs +++ b/Dnn.CommunityForums/CustomControls/UserControls/SubmitForm.cs @@ -705,7 +705,7 @@ private string ParseForm(string template) if (template.Contains("[AF:CONTROL:POSTICONS]") && this.ForumInfo.FeatureSettings.AllowPostIcon) { template = template.Replace("[AF:UI:FIELDSET:POSTICONS]", "
[RESX:PostIcons]
[RESX:PostIcons:Note]
"); - template = template.Replace("[AF:CONTROL:POSTICONS]", ""); + template = template.Replace("[AF:CONTROL:POSTICONS]", ""); template = template.Replace("[/AF:UI:FIELDSET:POSTICONS]", "
"); /* tokens [AF:UI:SECTION:POSTICONS][/AF:UI:SECTION:POSTICONS] can now surround post icons to support removing entire section; if using post icons, just remove the tokens*/ template = template.Replace("[AF:UI:SECTION:POSTICONS]", string.Empty); @@ -723,7 +723,7 @@ private string ParseForm(string template) if (template.Contains("[AF:CONTROL:EMOTICONS]") && this.ForumInfo.FeatureSettings.AllowEmoticons) { - template = template.Replace("[AF:CONTROL:EMOTICONS]", "
[RESX:Smilies]" + DotNetNuke.Modules.ActiveForums.Controllers.EmoticonController.LoadEmoticons(this.ForumModuleId, this.Page.ResolveUrl(this.MainSettings.ThemeLocation), this.EditorType) + "
"); + template = template.Replace("[AF:CONTROL:EMOTICONS]", "
[RESX:Smilies]" + DotNetNuke.Modules.ActiveForums.Controllers.EmoticonController.LoadEmoticons(this.ForumModuleId, this.Page.ResolveUrl(this.ModuleSettings.ThemeLocation), this.EditorType) + "
"); } else { @@ -1035,7 +1035,7 @@ protected override void OnLoad(EventArgs e) // not sure why this gets set twice. this.txtSubject.CssClass = "aftextbox dcf-topic-edit-subject"; - string myTheme = this.MainSettings.Theme; + string myTheme = this.ModuleSettings.Theme; string myThemePath = this.Page.ResolveUrl("~/DesktopModules/ActiveForums/themes/" + myTheme); this.txtSubject.MaxLength = 255; this.txtSummary.MaxLength = 2000; diff --git a/Dnn.CommunityForums/CustomControls/UserControls/TopicView.cs b/Dnn.CommunityForums/CustomControls/UserControls/TopicView.cs index 3baa7164a..9ae23b49f 100644 --- a/Dnn.CommunityForums/CustomControls/UserControls/TopicView.cs +++ b/Dnn.CommunityForums/CustomControls/UserControls/TopicView.cs @@ -125,7 +125,7 @@ protected override void OnLoad(EventArgs e) if (firstUnreadPost > lastPostRead) { var tURL = Utilities.NavigateURL(this.TabId, string.Empty, new[] { ParamKeys.ForumId + "=" + this.ForumId, ParamKeys.TopicId + "=" + this.TopicId, ParamKeys.ViewType + "=topic", ParamKeys.ContentJumpId + "=" + firstUnreadPost }); - if (this.MainSettings.UseShortUrls) + if (this.ModuleSettings.UseShortUrls) { tURL = Utilities.NavigateURL(this.TabId, string.Empty, new[] { ParamKeys.TopicId + "=" + this.TopicId, ParamKeys.ContentJumpId + "=" + firstUnreadPost }); } @@ -184,7 +184,7 @@ private void LoadData(int pageId) this.pageSize = this.OptPageSize; if (this.pageSize <= 0) { - this.pageSize = this.UserId > 0 ? this.UserDefaultPageSize : this.MainSettings.PageSize; + this.pageSize = this.UserId > 0 ? this.UserDefaultPageSize : this.ModuleSettings.PageSize; if (this.pageSize < 5) { this.pageSize = 10; @@ -231,7 +231,7 @@ private void LoadData(int pageId) { if (pageId > 1) { - if (this.MainSettings.UseShortUrls) + if (this.ModuleSettings.UseShortUrls) { this.Response.Redirect(Utilities.NavigateURL(this.TabId, string.Empty, new[] { ParamKeys.TopicId + "=" + this.TopicId }), false); this.Context.ApplicationInstance.CompleteRequest(); @@ -244,7 +244,7 @@ private void LoadData(int pageId) } else { - if (this.MainSettings.UseShortUrls) + if (this.ModuleSettings.UseShortUrls) { this.Response.Redirect(Utilities.NavigateURL(this.TabId, string.Empty, new[] { ParamKeys.ForumId + "=" + this.ForumId }), false); this.Context.ApplicationInstance.CompleteRequest(); @@ -376,7 +376,7 @@ private void LoadData(int pageId) var sURL = string.Empty; - if (this.MainSettings.URLRewriteEnabled && !string.IsNullOrEmpty(this.topic.TopicUrl)) + if (this.ModuleSettings.URLRewriteEnabled && !string.IsNullOrEmpty(this.topic.TopicUrl)) { var db = new Data.Common(); sURL = db.GetUrl(this.ModuleId, this.ForumGroupId, this.ForumId, this.TopicId, this.UserId, contentJumpId); @@ -402,7 +402,7 @@ private void LoadData(int pageId) $"{ParamKeys.TopicId}={this.TopicId}", $"{ParamKeys.ViewType}={Views.Topic}", }; - if (this.MainSettings.UseShortUrls) + if (this.ModuleSettings.UseShortUrls) { @params = new List { ParamKeys.TopicId + "=" + this.TopicId }; } @@ -516,8 +516,8 @@ private void BindTopic() this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.RemoveObsoleteTokens(new StringBuilder(this.MetaTemplate)).ToString(); this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyForumTokenSynonyms(new StringBuilder(this.MetaTemplate), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyTopicTokenSynonyms(new StringBuilder(this.MetaTemplate), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); - this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceTopicTokens(new StringBuilder(this.MetaTemplate), this.topic, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl).ToString(); - this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(new StringBuilder(this.MetaTemplate), this.ForumInfo, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl).ToString(); + this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceTopicTokens(new StringBuilder(this.MetaTemplate), this.topic, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl).ToString(); + this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(new StringBuilder(this.MetaTemplate), this.ForumInfo, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl).ToString(); this.MetaTemplate = this.MetaTemplate.Replace("[TAGS]", this.tags); this.MetaTitle = TemplateUtils.GetTemplateSection(this.MetaTemplate, "[TITLE]", "[/TITLE]").Replace("[TITLE]", string.Empty).Replace("[/TITLE]", string.Empty); @@ -533,7 +533,7 @@ private void BindTopic() var breadCrumb = TemplateUtils.GetTemplateSection(sOutput, "[BREADCRUMB]", "[/BREADCRUMB]").Replace("[BREADCRUMB]", string.Empty).Replace("[/BREADCRUMB]", string.Empty); - if (this.MainSettings.UseSkinBreadCrumb) + if (this.ModuleSettings.UseSkinBreadCrumb) { var ctlUtils = new ControlUtils(); @@ -576,7 +576,7 @@ private void BindTopic() { sOutput = TemplateUtils.ReplaceSubSection(sOutput, "", "[AF:CONTROL:CALLBACK]", "[/AF:CONTROL:CALLBACK]"); sOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyTopicTokenSynonyms(new StringBuilder(sOutput), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); - sOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceTopicTokens(new StringBuilder(sOutput), this.topic, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl).ToString(); + sOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceTopicTokens(new StringBuilder(sOutput), this.topic, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl).ToString(); sOutput = Utilities.DecodeBrackets(sOutput); sOutput = Utilities.LocalizeControl(sOutput); sOutput = Utilities.StripTokens(sOutput); @@ -958,8 +958,8 @@ private string ParseTopic(string sOutput) var sReplyTemplate = TemplateUtils.GetTemplateSection(sOutput, "[REPLIES]", "[/REPLIES]"); #region "Backward compatilbility -- remove in v10.00.00" - sTopicTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyUserTokenSynonyms(new StringBuilder(sTopicTemplate), this.PortalSettings, this.MainSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); - sTopicTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyAuthorTokenSynonyms(new StringBuilder(sTopicTemplate), this.PortalSettings, this.MainSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); + sTopicTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyUserTokenSynonyms(new StringBuilder(sTopicTemplate), this.PortalSettings, this.ModuleSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); + sTopicTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyAuthorTokenSynonyms(new StringBuilder(sTopicTemplate), this.PortalSettings, this.ModuleSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); sTopicTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyTopicTokenSynonyms(new StringBuilder(sTopicTemplate), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); sTopicTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyPostTokenSynonyms(new StringBuilder(sTopicTemplate), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); sReplyTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyPostTokenSynonyms(new StringBuilder(sReplyTemplate), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); @@ -1021,7 +1021,7 @@ private string ParseTopic(string sOutput) /* this handles token replacement for anything outside of the [TOPIC] or [REPLIES] sections */ sOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyTopicTokenSynonyms(new StringBuilder(sOutput), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); - sOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceTopicTokens(new StringBuilder(sOutput), this.topic, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl).ToString(); + sOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceTopicTokens(new StringBuilder(sOutput), this.topic, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl).ToString(); return sOutput; } @@ -1115,13 +1115,13 @@ private string ParseContent(DataRow dr, string template, int rowcount) }; sbOutput.Replace("[ATTACHMENTS]", this.GetAttachments(reply.ContentId, true, this.PortalId, this.ForumModuleId)); sbOutput.Replace("[SPLITCHECKBOX]", "
"); - sbOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplacePostTokens(sbOutput, reply, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl); + sbOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplacePostTokens(sbOutput, reply, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl); } else { sbOutput.Replace("[ATTACHMENTS]", this.GetAttachments(this.topic.ContentId, true, this.PortalId, this.ForumModuleId)); sbOutput.Replace("[SPLITCHECKBOX]", string.Empty); - sbOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplacePostTokens(sbOutput, this.topic, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl); + sbOutput = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplacePostTokens(sbOutput, this.topic, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl); } sOutput = sbOutput.ToString(); @@ -1218,13 +1218,13 @@ private void BuildPager() pager1.CurrentPage = this.PageId; pager1.TabID = Utilities.SafeConvertInt(this.Request.Params["TabId"], -1); pager1.ForumID = this.ForumId; - pager1.UseShortUrls = this.MainSettings.UseShortUrls; + pager1.UseShortUrls = this.ModuleSettings.UseShortUrls; pager1.PageText = Utilities.GetSharedResource("[RESX:Page]"); pager1.OfText = Utilities.GetSharedResource("[RESX:PageOf]"); pager1.View = Views.Topic; pager1.TopicId = this.topic.TopicId; pager1.PageMode = PagerNav.Mode.Links; - if (this.MainSettings.URLRewriteEnabled) + if (this.ModuleSettings.URLRewriteEnabled) { pager1.BaseURL = URL.ForumLink(this.TabId, this.ForumInfo) + this.topic.TopicUrl; } @@ -1238,13 +1238,13 @@ private void BuildPager() pager2.CurrentPage = this.PageId; pager2.TabID = Utilities.SafeConvertInt(this.Request.Params["TabId"], -1); pager2.ForumID = this.ForumId; - pager2.UseShortUrls = this.MainSettings.UseShortUrls; + pager2.UseShortUrls = this.ModuleSettings.UseShortUrls; pager2.PageText = Utilities.GetSharedResource("[RESX:Page]"); pager2.OfText = Utilities.GetSharedResource("[RESX:PageOf]"); pager2.View = Views.Topic; pager2.TopicId = this.topic.TopicId; pager2.PageMode = PagerNav.Mode.Links; - if (this.MainSettings.URLRewriteEnabled) + if (this.ModuleSettings.URLRewriteEnabled) { pager2.BaseURL = URL.ForumLink(this.TabId, this.ForumInfo) + this.topic.TopicUrl; } diff --git a/Dnn.CommunityForums/CustomControls/UserControls/TopicsView.cs b/Dnn.CommunityForums/CustomControls/UserControls/TopicsView.cs index df30fcb91..f3a7f6366 100644 --- a/Dnn.CommunityForums/CustomControls/UserControls/TopicsView.cs +++ b/Dnn.CommunityForums/CustomControls/UserControls/TopicsView.cs @@ -127,15 +127,15 @@ protected override void OnLoad(EventArgs e) } topicsTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.RemoveObsoleteTokens(new StringBuilder(topicsTemplate)).ToString(); - topicsTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyUserTokenSynonyms(new StringBuilder(topicsTemplate), this.PortalSettings, this.MainSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); - topicsTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyAuthorTokenSynonyms(new StringBuilder(topicsTemplate), this.PortalSettings, this.MainSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); + topicsTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyUserTokenSynonyms(new StringBuilder(topicsTemplate), this.PortalSettings, this.ModuleSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); + topicsTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyAuthorTokenSynonyms(new StringBuilder(topicsTemplate), this.PortalSettings, this.ModuleSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); topicsTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyForumTokenSynonyms(new StringBuilder(topicsTemplate), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); topicsTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyTopicTokenSynonyms(new StringBuilder(topicsTemplate), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale).ToString(); topicsTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyTopicActionTokenSynonyms(new StringBuilder(topicsTemplate), this.PortalSettings, this.ForumUser.UserInfo?.Profile?.PreferredLocale, this.useListActions).ToString(); #endregion "Backward compatilbility -- remove in v10.00.00" - this.pageSize = this.MainSettings.PageSize; + this.pageSize = this.ModuleSettings.PageSize; if (this.UserId > 0) { this.pageSize = this.UserDefaultPageSize; @@ -198,7 +198,7 @@ protected override void OnLoad(EventArgs e) this.isSubscribedForum = new DotNetNuke.Modules.ActiveForums.Controllers.SubscriptionController().Subscribed(this.PortalId, this.ForumModuleId, this.UserId, this.ForumId); } - if (this.MainSettings.UseSkinBreadCrumb) + if (this.ModuleSettings.UseSkinBreadCrumb) { string groupURL = new ControlUtils().BuildUrl(this.PortalId, this.TabId, this.ModuleId, this.ForumInfo.ForumGroup.PrefixURL, string.Empty, this.ForumInfo.ForumGroupId, -1, -1, -1, string.Empty, 1, -1, this.SocialGroupId); DotNetNuke.Modules.ActiveForums.Environment.UpdateBreadCrumb(this.Page.Controls, "" + this.ForumInfo.ForumGroup.GroupName + ""); @@ -215,7 +215,7 @@ protected override void OnLoad(EventArgs e) if (!string.IsNullOrEmpty(this.MetaTemplate)) { this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.RemoveObsoleteTokens(new StringBuilder(this.MetaTemplate)).ToString(); - this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(new StringBuilder(this.MetaTemplate), this.ForumInfo, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl).ToString(); + this.MetaTemplate = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(new StringBuilder(this.MetaTemplate), this.ForumInfo, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl).ToString(); this.MetaTitle = TemplateUtils.GetTemplateSection(this.MetaTemplate, "[TITLE]", "[/TITLE]").Replace("[TITLE]", string.Empty).Replace("[/TITLE]", string.Empty); this.MetaTitle = this.MetaTitle.TruncateAtWord(SEOConstants.MaxMetaTitleLength); this.MetaDescription = TemplateUtils.GetTemplateSection(this.MetaTemplate, "[DESCRIPTION]", "[/DESCRIPTION]").Replace("[DESCRIPTION]", string.Empty).Replace("[/DESCRIPTION]", string.Empty); @@ -310,7 +310,7 @@ private void BindTopics(string topicsTemplate) } StringBuilder stringBuilder = new StringBuilder(sOutput); - stringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(stringBuilder, this.ForumInfo, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl); + stringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceForumTokens(stringBuilder, this.ForumInfo, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.TabId, this.ForumUser.CurrentUserType, this.Request.Url, this.Request.RawUrl); sOutput = stringBuilder.ToString(); sOutput = Utilities.LocalizeControl(sOutput); @@ -371,7 +371,7 @@ private void LinkControls(ControlCollection ctrls) private string ParseControls(string Template) { - string MyTheme = this.MainSettings.Theme; + string MyTheme = this.ModuleSettings.Theme; string sOutput = Template; sOutput = "<%@ Register TagPrefix=\"ac\" Namespace=\"DotNetNuke.Modules.ActiveForums.Controls\" Assembly=\"DotNetNuke.Modules.ActiveForums\" %>" + sOutput; @@ -434,7 +434,7 @@ private string ParseControls(string Template) if (this.Request.IsAuthenticated) { string Url = this.NavigateUrl(this.TabId, string.Empty, new string[] { ParamKeys.ViewType + "=sendto", ParamKeys.ForumId + "=" + this.ForumId, ParamKeys.TopicId + "=" + this.TopicId }); - sOutput = sOutput.Replace("[AF:CONTROL:EMAIL]", "\"[RESX:EmailThis]\""); + sOutput = sOutput.Replace("[AF:CONTROL:EMAIL]", "\"[RESX:EmailThis]\""); } else { @@ -617,7 +617,7 @@ private string ParseTopics(string Template, DataTable Topics, string Section) stringBuilder.Replace("[AF:URL:LASTREAD]", string.Empty); } - stringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceTopicTokens(stringBuilder, topicInfo, this.PortalSettings, this.MainSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl); + stringBuilder = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceTopicTokens(stringBuilder, topicInfo, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), this.ForumUser, this.Request.Url, this.Request.RawUrl); stringBuilder.Replace("[LASTPOST]", string.Empty).Replace("[/LASTPOST]", string.Empty); stringBuilder.Replace("[ROWCSS]", this.GetRowCSS(UserLastTopicRead, UserLastReplyRead, topicInfo.TopicId, topicInfo.LastReplyId, rowcount)); @@ -657,7 +657,7 @@ private void BuildPager() intPages = Convert.ToInt32(System.Math.Ceiling(this.topicRowCount / (double)this.pageSize)); pager1.PageCount = intPages; pager1.PageMode = PagerNav.Mode.Links; - if (this.MainSettings.URLRewriteEnabled) + if (this.ModuleSettings.URLRewriteEnabled) { pager1.BaseURL = URL.ForumLink(this.TabId, this.ForumInfo); } @@ -665,7 +665,7 @@ private void BuildPager() pager1.CurrentPage = this.PageId; pager1.TabID = Convert.ToInt32(this.Request.Params["TabId"]); pager1.ForumID = this.ForumId; - pager1.UseShortUrls = this.MainSettings.UseShortUrls; + pager1.UseShortUrls = this.ModuleSettings.UseShortUrls; pager1.PageText = Utilities.GetSharedResource("[RESX:Page]"); pager1.OfText = Utilities.GetSharedResource("[RESX:PageOf]"); pager1.View = Views.Topics; @@ -683,11 +683,11 @@ private void BuildPager() if (pager2 != null) { pager2.PageMode = Modules.ActiveForums.Controls.PagerNav.Mode.Links; - if (this.MainSettings.URLRewriteEnabled) + if (this.ModuleSettings.URLRewriteEnabled) { pager2.BaseURL = URL.ForumLink(this.TabId, this.ForumInfo); } - pager2.UseShortUrls = this.MainSettings.UseShortUrls; + pager2.UseShortUrls = this.ModuleSettings.UseShortUrls; pager2.PageCount = intPages; pager2.CurrentPage = this.PageId; pager2.TabID = Convert.ToInt32(this.Request.Params["TabId"]); @@ -707,7 +707,7 @@ private string GetSubPages(int tabID, int replies, int forumID, int postID) if (replies + 1 > this.pageSize) { List Params = new List(); - sOut = "
(\"[RESX:MultiPageTopic]\""; + sOut = "
(\"[RESX:MultiPageTopic]\""; // Jump to pages int intPostPages = 0; @@ -718,7 +718,7 @@ private string GetSubPages(int tabID, int replies, int forumID, int postID) { Params = new List { ParamKeys.ForumId + "=" + forumID, ParamKeys.TopicId + "=" + postID, ParamKeys.ViewType + "=" + Views.Topic }; - if (this.MainSettings.UseShortUrls) + if (this.ModuleSettings.UseShortUrls) { Params = new List { ParamKeys.TopicId + "=" + postID }; } @@ -736,7 +736,7 @@ private string GetSubPages(int tabID, int replies, int forumID, int postID) } Params = new List { ParamKeys.ForumId + "=" + forumID, ParamKeys.TopicId + "=" + postID, ParamKeys.ViewType + "=" + Views.Topic }; - if (this.MainSettings.UseShortUrls) + if (this.ModuleSettings.UseShortUrls) { Params = new List { ParamKeys.TopicId + "=" + postID }; } @@ -756,7 +756,7 @@ private string GetSubPages(int tabID, int replies, int forumID, int postID) for (i = 1; i <= intPostPages; i++) { Params = new List { ParamKeys.ForumId + "=" + forumID, ParamKeys.TopicId + "=" + postID, ParamKeys.ViewType + "=" + Views.Topic }; - if (this.MainSettings.UseShortUrls) + if (this.ModuleSettings.UseShortUrls) { Params = new List { ParamKeys.TopicId + "=" + postID }; } diff --git a/Dnn.CommunityForums/CustomControls/UserControls/UserProfile.cs b/Dnn.CommunityForums/CustomControls/UserControls/UserProfile.cs index d94855658..2d0e5cde1 100644 --- a/Dnn.CommunityForums/CustomControls/UserControls/UserProfile.cs +++ b/Dnn.CommunityForums/CustomControls/UserControls/UserProfile.cs @@ -116,7 +116,7 @@ protected override void OnInit(EventArgs e) protected override void OnLoad(EventArgs e) { base.OnLoad(e); - string sTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.ForumModuleId, Enums.TemplateType._userProfile, SettingsBase.GetModuleSettings(this.ForumModuleId).ForumFeatureSettings.TemplateFileNameSuffix); + string sTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.ForumModuleId, Enums.TemplateType._userProfile, SettingsBase.GetModuleSettings(this.ForumModuleId).DefaultFeatureSettings.TemplateFileNameSuffix); if (this.ProfileMode == ProfileModes.Edit) { @@ -226,7 +226,7 @@ protected override void OnLoad(EventArgs e) { ForumView ctlForums = new ForumView(); ctlForums.ModuleConfiguration = this.ModuleConfiguration; - ctlForums.DisplayTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.ForumModuleId, (Enums.TemplateType)Enum.Parse(typeof(Enums.TemplateType), "ForumTracking", true), SettingsBase.GetModuleSettings(this.ForumModuleId).ForumFeatureSettings.TemplateFileNameSuffix); + ctlForums.DisplayTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.ForumModuleId, (Enums.TemplateType)Enum.Parse(typeof(Enums.TemplateType), "ForumTracking", true), SettingsBase.GetModuleSettings(this.ForumModuleId).DefaultFeatureSettings.TemplateFileNameSuffix); ctlForums.CurrentUserId = this.UID; ctlForums.ForumIds = user.UserForums; this.plhTracker.Controls.Add(ctlForums); @@ -358,13 +358,13 @@ private bool SaveProfile() var user = new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ForumModuleId).GetByUserId(this.PortalId, this.UID); if (user != null) { - if (this.MainSettings.AllowSignatures == 1) + if (this.ModuleSettings.AllowSignatures == 1) { user.Signature = Utilities.XSSFilter(this.txtSignature.Text, true); user.Signature = Utilities.StripHTMLTag(user.Signature); user.Signature = System.Net.WebUtility.HtmlEncode(user.Signature); } - else if (this.MainSettings.AllowSignatures == 2) + else if (this.ModuleSettings.AllowSignatures == 2) { user.Signature = Utilities.XSSFilter(this.txtSignature.Text, false); } diff --git a/Dnn.CommunityForums/DnnCommunityForums.csproj b/Dnn.CommunityForums/DnnCommunityForums.csproj index 124102fa4..22b5a0d63 100644 --- a/Dnn.CommunityForums/DnnCommunityForums.csproj +++ b/Dnn.CommunityForums/DnnCommunityForums.csproj @@ -12,8 +12,8 @@ Discussion Forum Module for DNN dnncommunity.org dnncommunity.org - 09.01.01.00 - 09.01.01.00 + 09.02.00.00 + 09.02.00.00 False True @@ -25,15 +25,22 @@ + + + + + + + @@ -75,7 +82,6 @@ - @@ -88,6 +94,15 @@ + + + + ASPXCodeBehind + + + ASPXCodeBehind + + diff --git a/Dnn.CommunityForums/DnnCommunityForums.dnn b/Dnn.CommunityForums/DnnCommunityForums.dnn index 25eeaebdc..069437234 100644 --- a/Dnn.CommunityForums/DnnCommunityForums.dnn +++ b/Dnn.CommunityForums/DnnCommunityForums.dnn @@ -1,6 +1,6 @@  - + DNN Community Forums DNN Community Forums: The official online forums module for the DNN Community. DesktopModules/ActiveForums/images/branding/logo/DNN-Community-Forums-Icon-64px.png @@ -75,7 +75,7 @@ DotNetNuke.Modules.ActiveForums.TopicsController, DotNetNuke.Modules.ActiveForums [DESKTOPMODULEID] - 07.00.07,07.00.11,07.00.12,08.00.00,08.01.00,08.02.00,08.02.02,08.02.03,08.02.04,08.02.08,09.00.00,09.01.00 + 07.00.07,07.00.11,07.00.12,08.00.00,08.01.00,08.02.00,08.02.02,08.02.03,08.02.04,08.02.08,09.00.00,09.01.00,09.02.00 @@ -86,7 +86,7 @@ DotNetNuke.Modules.ActiveForums.dll bin\DotNetNuke.Modules.ActiveForums.dll - 09.01.01 + 09.02.00 @@ -436,13 +436,13 @@ @@ -485,8 +485,8 @@ - - + + DNN Community Forums What's New ActiveForumsWhatsNew DNN Community Forums: Display the most recent topics or replies from selected forums on any page within your site. @@ -555,7 +555,7 @@ - + DNN Community Forums Forums Viewer ActiveForumsViewer DNN Community Forums: Display any forum topic view on any page within your site. diff --git a/Dnn.CommunityForums/DnnCommunityForums_Symbols.dnn b/Dnn.CommunityForums/DnnCommunityForums_Symbols.dnn index 7a9340c9a..be5cde55a 100644 --- a/Dnn.CommunityForums/DnnCommunityForums_Symbols.dnn +++ b/Dnn.CommunityForums/DnnCommunityForums_Symbols.dnn @@ -1,6 +1,6 @@  - + DNN Community Forums Symbols DNN Community Forums: The official online forums module for the DNN Community. DesktopModules/ActiveForums/images/branding/logo/DNN-Community-Forums-Icon-64px.png @@ -14,7 +14,7 @@ True - Active Forums + Active Forums diff --git a/Dnn.CommunityForums/Entities/BadgeInfo.cs b/Dnn.CommunityForums/Entities/BadgeInfo.cs new file mode 100644 index 000000000..ca34cc99f --- /dev/null +++ b/Dnn.CommunityForums/Entities/BadgeInfo.cs @@ -0,0 +1,121 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Entities +{ + using System; + using System.Web.Caching; + + using DotNetNuke.ComponentModel.DataAnnotations; + using DotNetNuke.Services.Tokens; + using DotNetNuke.UI.UserControls; + + /// + /// Represents a badge in the DNN Community Forums module. + /// + [TableName("activeforums_Badges")] + [PrimaryKey("BadgeId", AutoIncrement = true)] + [Cacheable("activeforums_Badges", CacheItemPriority.Normal)] + [Scope("ModuleId")] + public class BadgeInfo + { + /// + /// Gets or sets the badge ID. + /// + public int BadgeId { get; set; } + + /// + /// Gets or sets the ModuleId. + /// + public int ModuleId { get; set; } + + /// + /// Gets or sets the badge name. + /// + public string Name { get; set; } + + /// + /// Gets or sets the badge description. + /// + public string Description { get; set; } + + /// + /// Gets or sets the badge image markup (optional). + /// + public string ImageMarkup { get; set; } + + /// + /// Gets or sets the file Id for the badge. + /// + public int FileId{ get; set; } + + /// + /// Gets or sets the SortOrder for the badge. + /// + public int SortOrder { get; set; } + + /// + /// Gets or sets One Time Award. + /// + public bool OneTimeAward { get; set; } + + /// + /// Gets or sets the BadgeMetric. + /// + public DotNetNuke.Modules.ActiveForums.Enums.BadgeMetric BadgeMetric { get; set; } + + /// + /// Gets or sets the Threshold. + /// + public int Threshold { get; set; } + + /// + /// Gets or sets the interval days. + /// + public int IntervalDays { get; set; } + + /// + /// Gets or sets the SendAwardNotification. + /// + public bool SendAwardNotification { get; set; } + + /// + /// Gets or sets the InitialBackfillCompletedDate. + /// + public DateTime? InitialBackfillCompletedDate { get; set; } + + /// + /// Gets or sets the SuppresssAwardNotificationOnBackfill. + /// + public bool SuppresssAwardNotificationOnBackfill { get; set; } + + /// + /// Gets the enum name/description for the badge metric. + /// + [IgnoreColumn] + public string BadgeMetricEnumName => Enum.GetName(typeof(DotNetNuke.Modules.ActiveForums.Enums.BadgeMetric), this.BadgeMetric); + + /// + /// Gets the Url for the badge image. + /// + [IgnoreColumn] + public string GetBadgeImageUrl(int portalId, int size = 32) => this.FileId <= 0 ? string.Empty : Utilities.ResolveUrl($"https://{Utilities.GetPortalSettings(portalId).DefaultPortalAlias}/DnnImageHandler.ashx?mode=securefile&fileId={this.FileId}&h={size}&w={size}"); + } +} diff --git a/Dnn.CommunityForums/Entities/FeatureSettings.cs b/Dnn.CommunityForums/Entities/FeatureSettings.cs index 457a83319..33b380255 100644 --- a/Dnn.CommunityForums/Entities/FeatureSettings.cs +++ b/Dnn.CommunityForums/Entities/FeatureSettings.cs @@ -41,12 +41,18 @@ public FeatureSettings(Hashtable featureSettings) internal static void Save(int moduleId, string settingsKey, FeatureSettings settings) { + new DotNetNuke.Modules.ActiveForums.Controllers.SettingsController().DeleteForModuleIdSettingsKey(moduleId, settingsKey); foreach (DictionaryEntry setting in settings.featureSettings) { - Settings.SaveSetting(moduleId, settingsKey, setting.Key.ToString(), setting.Value.ToString()); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, settingsKey, setting.Key.ToString(), setting.Value.ToString()); } } + internal static void Delete(int moduleId, string settingsKey, string settingName) + { + new DotNetNuke.Modules.ActiveForums.Controllers.SettingsController().DeleteForModuleIdSettingsKeySettingName(moduleId, settingsKey, settingName); + } + [IgnoreColumn] public bool AllowAttach => Utilities.SafeConvertBool(this.featureSettings[ForumSettingKeys.AllowAttach]); diff --git a/Dnn.CommunityForums/Entities/ForumGroupInfo.cs b/Dnn.CommunityForums/Entities/ForumGroupInfo.cs index f807189c3..958ffb693 100644 --- a/Dnn.CommunityForums/Entities/ForumGroupInfo.cs +++ b/Dnn.CommunityForums/Entities/ForumGroupInfo.cs @@ -40,7 +40,7 @@ public partial class ForumGroupInfo : DotNetNuke.Services.Tokens.IPropertyAccess private DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo security; private FeatureSettings featureSettings; - private DotNetNuke.Modules.ActiveForums.SettingsInfo mainSettings; + private DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings; private PortalSettings portalSettings; private ModuleInfo moduleInfo; private int? tabId; @@ -79,10 +79,10 @@ public int TabId public string ThemeLocation => Utilities.ResolveUrl(SettingsBase.GetModuleSettings(this.ModuleId).ThemeLocation); [IgnoreColumn] - public bool InheritSecurity => this.PermissionsId == this.MainSettings.DefaultPermissionId; + public bool InheritSecurity => this.PermissionsId == this.ModuleSettings.DefaultPermissionId; [IgnoreColumn] - public bool InheritSettings => this.GroupSettingsKey == this.MainSettings.DefaultSettingsKey; + public bool InheritSettings => this.GroupSettingsKey == this.ModuleSettings.DefaultSettingsKey; [IgnoreColumn] public DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo Security @@ -148,29 +148,29 @@ internal FeatureSettings LoadFeatureSettings() } [IgnoreColumn] - public SettingsInfo MainSettings + public DotNetNuke.Modules.ActiveForums.ModuleSettings ModuleSettings { get { - if (this.mainSettings == null) + if (this.moduleSettings == null) { - this.mainSettings = this.LoadMainSettings(); + this.moduleSettings = this.LoadModuleSettings(); this.UpdateCache(); } - return this.mainSettings; + return this.moduleSettings; } set { - this.mainSettings = value; + this.moduleSettings = value; this.UpdateCache(); } } - internal SettingsInfo LoadMainSettings() + internal DotNetNuke.Modules.ActiveForums.ModuleSettings LoadModuleSettings() { - return this.mainSettings = SettingsBase.GetModuleSettings(this.ModuleId); + return this.moduleSettings = SettingsBase.GetModuleSettings(this.ModuleId); } [IgnoreColumn] diff --git a/Dnn.CommunityForums/Entities/ForumInfo.cs b/Dnn.CommunityForums/Entities/ForumInfo.cs index 4e52db101..b1587dbaa 100644 --- a/Dnn.CommunityForums/Entities/ForumInfo.cs +++ b/Dnn.CommunityForums/Entities/ForumInfo.cs @@ -50,7 +50,7 @@ public class ForumInfo : DotNetNuke.Services.Tokens.IPropertyAccess private DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo security; private DotNetNuke.Modules.ActiveForums.Entities.IPostInfo lastPostInfo; private FeatureSettings featureSettings; - private DotNetNuke.Modules.ActiveForums.SettingsInfo mainSettings; + private DotNetNuke.Modules.ActiveForums.ModuleSettings mainSettings; private PortalSettings portalSettings; private ModuleInfo moduleInfo; private int? subscriberCount; @@ -117,9 +117,9 @@ public ForumInfo(DotNetNuke.Entities.Portals.PortalSettings portalSettings) public string ForumSettingsKey { get; set; } - public DateTime DateCreated { get; set; } = DateTime.Now; + public DateTime DateCreated { get; set; } = DateTime.UtcNow; - public DateTime DateUpdated { get; set; } = DateTime.Now; + public DateTime DateUpdated { get; set; } = DateTime.UtcNow; public int LastTopicId { get; set; } @@ -547,7 +547,7 @@ internal PermissionInfo LoadSecurity() } [IgnoreColumn] - public SettingsInfo MainSettings + public DotNetNuke.Modules.ActiveForums.ModuleSettings MainSettings { get { @@ -567,7 +567,7 @@ public SettingsInfo MainSettings } } - internal SettingsInfo LoadMainSettings() + internal DotNetNuke.Modules.ActiveForums.ModuleSettings LoadMainSettings() { return this.mainSettings = SettingsBase.GetModuleSettings(this.ModuleId); } @@ -713,7 +713,7 @@ internal string GetForumStatusCss(DotNetNuke.Modules.ActiveForums.Entities.Forum } } - internal string GetForumFolderIcon(DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo forumUser, DotNetNuke.Modules.ActiveForums.SettingsInfo mainSettings) + internal string GetForumFolderIcon(DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo forumUser, DotNetNuke.Modules.ActiveForums.ModuleSettings mainSettings) { switch (this.GetForumStatusForUser(forumUser)) { @@ -908,7 +908,8 @@ public string GetProperty(string propertyName, string format, System.Globalizati case "lastpostdisplayname": case "lastpostauthordisplayname": var forumUserController = new Controllers.ForumUserController(this.ModuleId); - return this.LastPostID > 0 && this.LastPostUserID > 0 ? PropertyAccess.FormatString(Controllers.ForumUserController.GetDisplayName(this.PortalSettings, this.MainSettings, forumUserController.GetByUserId(accessingUser.PortalID, accessingUser.UserID).GetIsMod(this.ModuleId), forumUserController.GetUserIsAdmin(accessingUser.PortalID, this.ModuleId, accessingUser.UserID) || forumUserController.GetUserIsSuperUser(accessingUser.PortalID, this.ModuleId, accessingUser.UserID), this.LastPostUserID, this.LastPostUserName, this.LastPostFirstName, this.LastPostLastName, this.LastPostDisplayName).Replace("&#", "&#").Replace("Anonymous", this.LastPostDisplayName), format) : string.Empty; + var forumUser = forumUserController.GetByUserId(accessingUser.PortalID, accessingUser.UserID); + return this.LastPostID > 0 && this.LastPostUserID > 0 ? PropertyAccess.FormatString(Controllers.ForumUserController.GetDisplayName(this.PortalSettings, this.MainSettings, forumUser.GetIsMod(this.ModuleId), forumUser.IsAdmin || forumUser.IsSuperUser, this.LastPostUserID, this.LastPostUserName, this.LastPostFirstName, this.LastPostLastName, this.LastPostDisplayName).Replace("&#", "&#").Replace("Anonymous", this.LastPostDisplayName), format) : string.Empty; case "statuscssclass": return PropertyAccess.FormatString(this.GetForumStatusCss(new Controllers.ForumUserController(this.ModuleId).GetByUserId(accessingUser.PortalID, accessingUser.UserID)), format); diff --git a/Dnn.CommunityForums/Entities/ForumUserInfo.cs b/Dnn.CommunityForums/Entities/ForumUserInfo.cs index e7817cdf9..4e7fa5596 100644 --- a/Dnn.CommunityForums/Entities/ForumUserInfo.cs +++ b/Dnn.CommunityForums/Entities/ForumUserInfo.cs @@ -19,6 +19,9 @@ // DEALINGS IN THE SOFTWARE. using System.Linq; +using System.Text; + +using DotNetNuke.Collections; namespace DotNetNuke.Modules.ActiveForums.Entities { @@ -27,10 +30,12 @@ namespace DotNetNuke.Modules.ActiveForums.Entities using System.Linq; using DotNetNuke.ComponentModel.DataAnnotations; + using DotNetNuke.Data; using DotNetNuke.Entities.Modules; using DotNetNuke.Entities.Portals; using DotNetNuke.Entities.Users; using DotNetNuke.Services.Tokens; + using DotNetNuke.UI.UserControls; [TableName("activeforums_UserProfiles")] [PrimaryKey("ProfileId", AutoIncrement = true)] @@ -41,8 +46,9 @@ public class ForumUserInfo : DotNetNuke.Services.Tokens.IPropertyAccess private string cacheKeyTemplate => CacheKeys.ForumUser; private DotNetNuke.Entities.Users.UserInfo userInfo; + private IEnumerable userBadges; private PortalSettings portalSettings; - private SettingsInfo mainSettings; + private DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings; private ModuleInfo moduleInfo; private HashSet userRoleIds; private string userPermSet; @@ -92,7 +98,7 @@ public ForumUserInfo(int moduleId, DotNetNuke.Entities.Users.UserInfo userInfo) public int TopicCount { get; set; } - public int ReplyCount { get; set; } + public int ReplyCount { get; set; } public int ViewCount { get; set; } @@ -108,11 +114,9 @@ public ForumUserInfo(int moduleId, DotNetNuke.Entities.Users.UserInfo userInfo) public int? AvatarFileId { get; set; } - [IgnoreColumn] - public DateTime? DateCreated => this.UserInfo?.CreatedOnDate; + public DateTime DateCreated { get; set; } - [IgnoreColumn] - public DateTime? DateUpdated => this.UserInfo?.LastModifiedOnDate; + public DateTime? DateUpdated { get; set; } public DateTime? DateLastActivity { get; set; } @@ -120,6 +124,13 @@ public ForumUserInfo(int moduleId, DotNetNuke.Entities.Users.UserInfo userInfo) public DateTime? DateLastReply { get; set; } + [IgnoreColumn] + public DateTime? DNNUserDateCreated => this.UserInfo?.CreatedOnDate; + + [IgnoreColumn] + public DateTime? DNNUserDateUpdated => this.UserInfo?.LastModifiedOnDate; + + public string Signature { get; set; } public bool SignatureDisabled { get; set; } @@ -162,6 +173,8 @@ public ForumUserInfo(int moduleId, DotNetNuke.Entities.Users.UserInfo userInfo) public bool EnableNotificationsForOwnContent { get; set; } = false; + public bool BadgeNotificationsEnabled { get; set; } = true; + [IgnoreColumn] public string RawUrl { get; set; } @@ -262,29 +275,29 @@ public CurrentUserTypes CurrentUserType TimeSpan TimeZoneOffsetForUser => Utilities.GetTimeZoneOffsetForUser(this.UserInfo); [IgnoreColumn] - public SettingsInfo MainSettings + public DotNetNuke.Modules.ActiveForums.ModuleSettings ModuleSettings { get { - if (this.mainSettings == null) + if (this.moduleSettings == null) { - this.mainSettings = this.LoadMainSettings(); + this.moduleSettings = this.LoadModuleSettings(); this.UpdateCache(); } - return this.mainSettings; + return this.moduleSettings; } set { - this.mainSettings = value; + this.moduleSettings = value; this.UpdateCache(); } } - internal SettingsInfo LoadMainSettings() + internal DotNetNuke.Modules.ActiveForums.ModuleSettings LoadModuleSettings() { - return this.mainSettings = SettingsBase.GetModuleSettings(this.ModuleId); + return this.moduleSettings = SettingsBase.GetModuleSettings(this.ModuleId); } [IgnoreColumn] @@ -495,11 +508,31 @@ internal int GetLastTopicRead(DotNetNuke.Modules.ActiveForums.Entities.ForumInfo return 0; } + internal int GetLikeCountForUser() + { + return new DotNetNuke.Modules.ActiveForums.Controllers.LikeController().Count("WHERE UserId = @0 AND Checked = 1", this.UserId); + } + + internal int GetLikeCountForUserSince(DateTime minDateTime) + { + return new DotNetNuke.Modules.ActiveForums.Controllers.LikeController().Count("WHERE UserId = @0 AND Checked = 1 AND DateCreated >= @1", this.UserId, minDateTime); + } + internal int GetTopicReadCount(DotNetNuke.Modules.ActiveForums.Entities.ForumInfo fi) { return new DotNetNuke.Modules.ActiveForums.Controllers.TopicTrackingController().GetTopicsReadCountForUserForum(this.ModuleId, this.UserId, fi.ForumID); } + internal int GetTopicReadCount() + { + return new DotNetNuke.Modules.ActiveForums.Controllers.TopicTrackingController().GetTopicsReadCountByUser(this.ModuleId, this.UserId); + } + + internal int GetTopicReadCountSince(DateTime minDateTimeRead) + { + return new DotNetNuke.Modules.ActiveForums.Controllers.TopicTrackingController().GetTopicsReadCountByUser(this.ModuleId, this.UserId, minDateTimeRead); + } + internal int GetLastTopicReplyRead(DotNetNuke.Modules.ActiveForums.Entities.TopicInfo ti) { var topicTrak = new DotNetNuke.Modules.ActiveForums.Controllers.TopicTrackingController().GetByUserIdTopicId(this.ModuleId, this.UserId, ti.TopicId); @@ -522,6 +555,24 @@ public bool RunningInViewer } } + [IgnoreColumn] + public IEnumerable Badges + { + get + { + if (this.userBadges == null) + { + this.GetUserBadges(); + this.UpdateCache(); + } + + return this.userBadges; + } + set => this.userBadges = value; + } + + internal IEnumerable GetUserBadges() => this.userBadges = new DotNetNuke.Modules.ActiveForums.Controllers.UserBadgeController(this.PortalId, this.ModuleId).GetForUser(this.PortalId, this.UserId); + [IgnoreColumn] public int ForumsOrViewerModuleId { @@ -544,6 +595,18 @@ public int ForumsOrViewerModuleId } } + public int GetTopicCountSince(DateTime minDateTime) + { + string sSql = "SELECT COUNT(*) FROM {databaseOwner}{objectQualifier}activeforums_Content c INNER JOIN {databaseOwner}{objectQualifier}activeforums_Topics t ON t.ContentId = c.ContentId WHERE c.ModuleId = @0 AND c.AuthorId = @1 AND c.IsDeleted = 0 AND c.DateCreated >= @2"; + return DataContext.Instance().ExecuteQuery(System.Data.CommandType.Text, sSql, this.ModuleId, this.UserId, minDateTime).FirstOrDefault(); + } + + public int GetReplyCountSince(DateTime minDateTime) + { + string sSql = "SELECT COUNT(*) FROM {databaseOwner}{objectQualifier}activeforums_Content c INNER JOIN {databaseOwner}{objectQualifier}activeforums_Replies r ON r.ContentId = c.ContentId WHERE c.ModuleId = @0 AND c.AuthorId = @1 AND c.IsDeleted = 0 AND c.DateCreated >= @2"; + return DataContext.Instance().ExecuteQuery(System.Data.CommandType.Text, sSql, this.ModuleId, this.UserId, minDateTime).FirstOrDefault(); + } + [IgnoreColumn] public DotNetNuke.Services.Tokens.CacheLevel Cacheability => DotNetNuke.Services.Tokens.CacheLevel.notCacheable; @@ -579,8 +642,8 @@ public string GetProperty(string propertyName, string format, System.Globalizati return PropertyAccess.FormatString(string.Empty, format); } - var height = this.MainSettings.AvatarHeight; - var width = this.MainSettings.AvatarWidth; + var height = this.ModuleSettings.AvatarHeight; + var width = this.ModuleSettings.AvatarWidth; if (length > 0) { height = length; @@ -591,11 +654,15 @@ public string GetProperty(string propertyName, string format, System.Globalizati case "usercaption": return PropertyAccess.FormatString(this.UserCaption, format); case "displayname": - return PropertyAccess.FormatString(DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.GetDisplayName(this.PortalSettings, this.MainSettings, isMod: new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ModuleId).GetByUserId(portalId: accessingUser.PortalID, userId: accessingUser.UserID).GetIsMod(this.ModuleId), isAdmin: new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ModuleId).GetByUserId(portalId: accessingUser.PortalID, userId: accessingUser.UserID).IsAdmin, this.UserId, this.Username, this.FirstName, this.LastName, this.DisplayName), format); + return PropertyAccess.FormatString(DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.GetDisplayName(this.PortalSettings, this.ModuleSettings, isMod: new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ModuleId).GetByUserId(portalId: accessingUser.PortalID, userId: accessingUser.UserID).GetIsMod(this.ModuleId), isAdmin: new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ModuleId).GetByUserId(portalId: accessingUser.PortalID, userId: accessingUser.UserID).IsAdmin, this.UserId, this.Username, this.FirstName, this.LastName, this.DisplayName), format); case "datecreated": return Utilities.GetUserFormattedDateTime(this.DateCreated, formatProvider, accessingUser.Profile.PreferredTimeZone.GetUtcOffset(DateTime.UtcNow)); + case "dnnuserdatecreated": + return Utilities.GetUserFormattedDateTime(this.DNNUserDateCreated, formatProvider, accessingUser.Profile.PreferredTimeZone.GetUtcOffset(DateTime.UtcNow)); case "dateupdated": return Utilities.GetUserFormattedDateTime(this.DateUpdated, formatProvider, accessingUser.Profile.PreferredTimeZone.GetUtcOffset(DateTime.UtcNow)); + case "dnnuserdateupdated": + return Utilities.GetUserFormattedDateTime(this.DNNUserDateUpdated, formatProvider, accessingUser.Profile.PreferredTimeZone.GetUtcOffset(DateTime.UtcNow)); case "datelastpost": return Utilities.GetUserFormattedDateTime(this.DateLastPost, formatProvider, accessingUser.Profile.PreferredTimeZone.GetUtcOffset(DateTime.UtcNow)); case "datelastreply": @@ -611,31 +678,31 @@ public string GetProperty(string propertyName, string format, System.Globalizati case "topiccount": return PropertyAccess.FormatString(this.TopicCount.ToString(), format); case "answercount": - return PropertyAccess.FormatString(this.MainSettings.EnablePoints && this.UserId > 0 ? this.AnswerCount.ToString() : string.Empty, format); + return PropertyAccess.FormatString(this.ModuleSettings.EnablePoints && this.UserId > 0 ? this.AnswerCount.ToString() : string.Empty, format); case "rewardpoints": - return PropertyAccess.FormatString(this.MainSettings.EnablePoints && this.UserId > 0 ? this.RewardPoints.ToString() : string.Empty, format); + return PropertyAccess.FormatString(this.ModuleSettings.EnablePoints && this.UserId > 0 ? this.RewardPoints.ToString() : string.Empty, format); case "totalpoints": - return PropertyAccess.FormatString(this.MainSettings.EnablePoints && this.UserId > 0 ? ((this.TopicCount * this.MainSettings.TopicPointValue) + (this.ReplyCount * this.MainSettings.ReplyPointValue) + (this.AnswerCount * this.MainSettings.AnswerPointValue) + this.RewardPoints).ToString() : string.Empty, format); + return PropertyAccess.FormatString(this.ModuleSettings.EnablePoints && this.UserId > 0 ? ((this.TopicCount * this.ModuleSettings.TopicPointValue) + (this.ReplyCount * this.ModuleSettings.ReplyPointValue) + (this.AnswerCount * this.ModuleSettings.AnswerPointValue) + this.RewardPoints).ToString() : string.Empty, format); case "rankdisplay": return PropertyAccess.FormatString(this.UserId > 0 ? DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.GetUserRank(this.ModuleId, this, 0) : string.Empty, format); case "rankname": return PropertyAccess.FormatString(this.UserId > 0 ? DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.GetUserRank(this.ModuleId, this, 1) : string.Empty, format); case "userprofilelink": return PropertyAccess.FormatString(DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.CanLinkToProfile(portalSettings: this.PortalSettings, - mainSettings: this.MainSettings, + moduleSettings: this.ModuleSettings, moduleId: this.ModuleId, accessingUser: new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ModuleId).GetByUserId(accessingUser.PortalID, accessingUser.UserID), forumUser: this) ? Utilities.NavigateURL(this.PortalSettings.UserTabId, string.Empty, new[] { $"userId={this.UserId}" }) : string.Empty, format); case "signature": var sSignature = string.Empty; - if (this.MainSettings.AllowSignatures != 0 && !this.PrefBlockSignatures && !this.SignatureDisabled) + if (this.ModuleSettings.AllowSignatures != 0 && !this.PrefBlockSignatures && !this.SignatureDisabled) { sSignature = this?.Signature ?? string.Empty; if (!string.IsNullOrEmpty(sSignature)) { sSignature = Utilities.ManageImagePath(sSignature, this.RequestUri); - switch (this.MainSettings.AllowSignatures) + switch (this.ModuleSettings.AllowSignatures) { case 1: sSignature = System.Net.WebUtility.HtmlEncode(sSignature); @@ -651,12 +718,12 @@ public string GetProperty(string propertyName, string format, System.Globalizati return PropertyAccess.FormatString(sSignature, format); case "userstatus": { - return PropertyAccess.FormatString(this.MainSettings != null && this.MainSettings.UsersOnlineEnabled && this.UserId > 0 ? DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.GetTokenFormatString(this.IsUserOnline ? "[FORUMUSER-USERONLINE]" : "[FORUMUSER-USEROFFLINE]", this.PortalSettings, accessingUser.Profile.PreferredLocale) : string.Empty, format); + return PropertyAccess.FormatString(this.ModuleSettings != null && this.ModuleSettings.UsersOnlineEnabled && this.UserId > 0 ? DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.GetTokenFormatString(this.IsUserOnline ? "[FORUMUSER-USERONLINE]" : "[FORUMUSER-USEROFFLINE]", this.PortalSettings, accessingUser.Profile.PreferredLocale) : string.Empty, format); } case "userstatuscss": { - return PropertyAccess.FormatString(this.MainSettings != null && this.MainSettings.UsersOnlineEnabled && this.UserId > 0 ? DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.GetTokenFormatString(this.IsUserOnline ? "[FORUMUSER-USERONLINECSS]" : "[FORUMUSER-USEROFFLINECSS]", this.PortalSettings, accessingUser.Profile.PreferredLocale) : string.Empty, format); + return PropertyAccess.FormatString(this.ModuleSettings != null && this.ModuleSettings.UsersOnlineEnabled && this.UserId > 0 ? DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.GetTokenFormatString(this.IsUserOnline ? "[FORUMUSER-USERONLINECSS]" : "[FORUMUSER-USEROFFLINECSS]", this.PortalSettings, accessingUser.Profile.PreferredLocale) : string.Empty, format); } case "userid": @@ -668,7 +735,7 @@ public string GetProperty(string propertyName, string format, System.Globalizati return PropertyAccess.FormatString( Controllers.ForumUserController.CanLinkToProfile( this.PortalSettings, - this.MainSettings, + this.ModuleSettings, this.ModuleId, new Controllers.ForumUserController(this.ModuleId).GetByUserId( accessingUser.PortalID, @@ -685,7 +752,7 @@ public string GetProperty(string propertyName, string format, System.Globalizati return PropertyAccess.FormatString(string.IsNullOrEmpty(this.DisplayName) ? this.Username : DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController.GetDisplayName( this.PortalSettings, - this.MainSettings, + this.ModuleSettings, isMod: new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ModuleId).GetByUserId(accessingUser.PortalID, accessingUser.UserID).GetIsMod(this.ModuleId), isAdmin: new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ModuleId).GetByUserId(accessingUser.PortalID, accessingUser.UserID).IsAdmin || new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ModuleId).GetByUserId(accessingUser.PortalID, accessingUser.UserID).IsSuperUser, this.UserId, @@ -705,6 +772,21 @@ public string GetProperty(string propertyName, string format, System.Globalizati return PropertyAccess.FormatString((accessingUser.IsAdmin || accessingUser.IsSuperUser) && this.UserId > 0 ? this.UserId.ToString() : string.Empty, format); case "displaynameforjson": return PropertyAccess.FormatString(Utilities.JSON.EscapeJsonString(this.DisplayName), format); + case "badges": + if (length < 1) + { + length = 5; /* if no length specified, default to 5 badges */ + } + + var badgeString = string.Empty; + var userBadgesToDisplay = this.Badges.GroupBy(b => b.BadgeId).Select(g => g.OrderByDescending(b => b.DateAssigned).First()).ToList().OrderBy(b => b.Badge.SortOrder).Take(length); + var badgeTemplate = new StringBuilder(DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(this.ModuleId, Enums.TemplateType.UserBadge, SettingsBase.GetModuleSettings(this.ModuleId).DefaultFeatureSettings.TemplateFileNameSuffix)); + foreach (var userBadge in userBadgesToDisplay) + { + badgeString += DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.ReplaceBadgeTokens(badgeTemplate, userBadge, this.PortalSettings, this.ModuleSettings, new Services.URLNavigator().NavigationManager(), new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ModuleId).GetByUserId(accessingUser.PortalID, accessingUser.UserID), this.RequestUri, this.RawUrl); + } + + return PropertyAccess.FormatString(badgeString, format); } } catch (Exception ex) diff --git a/Dnn.CommunityForums/Entities/LikeInfo.cs b/Dnn.CommunityForums/Entities/LikeInfo.cs index 0e91d3324..750ba0f19 100644 --- a/Dnn.CommunityForums/Entities/LikeInfo.cs +++ b/Dnn.CommunityForums/Entities/LikeInfo.cs @@ -45,6 +45,8 @@ internal class LikeInfo : DotNetNuke.Services.Tokens.IPropertyAccess public bool Checked { get; set; } + public DateTime DateCreated { get; set; } + [IgnoreColumn] public int ForumId => this.Content.Post.ForumId; diff --git a/Dnn.CommunityForums/Entities/ProcessQueueInfo.cs b/Dnn.CommunityForums/Entities/ProcessQueueInfo.cs index e1095315f..0e6cfe060 100644 --- a/Dnn.CommunityForums/Entities/ProcessQueueInfo.cs +++ b/Dnn.CommunityForums/Entities/ProcessQueueInfo.cs @@ -53,6 +53,8 @@ public class ProcessQueueInfo public int UserId { get; set; } + public int BadgeId { get; set; } + public DateTime DateCreated { get; set; } = DateTime.UtcNow; public string RequestUrl { get; set; } diff --git a/Dnn.CommunityForums/Entities/SettingsInfo.cs b/Dnn.CommunityForums/Entities/SettingsInfo.cs new file mode 100644 index 000000000..bfba7e61c --- /dev/null +++ b/Dnn.CommunityForums/Entities/SettingsInfo.cs @@ -0,0 +1,43 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Entities +{ + using System.Web.Caching; + + using DotNetNuke.ComponentModel.DataAnnotations; + + [TableName("activeforums_Settings")] + [PrimaryKey("SettingsId", AutoIncrement = true)] + [Scope("ModuleId")] + [Cacheable("activeforums_Settings", CacheItemPriority.High)] + public partial class SettingsInfo + { + public int ModuleId { get; set; } + + public int SettingsId { get; set; } + + public string SettingsKey { get; set; } + + public string SettingName { get; set; } + + public string SettingValue { get; set; } + } +} diff --git a/Dnn.CommunityForums/Entities/UserBadgeInfo.cs b/Dnn.CommunityForums/Entities/UserBadgeInfo.cs new file mode 100644 index 000000000..95219f26c --- /dev/null +++ b/Dnn.CommunityForums/Entities/UserBadgeInfo.cs @@ -0,0 +1,216 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Entities +{ + using System; + using System.Web.Caching; + + using DotNetNuke.ComponentModel.DataAnnotations; + using DotNetNuke.Services.Tokens; + + /// + /// Represents a user badge assignment in the DNN Community Forums module. + /// + [TableName("activeforums_UserBadges")] + [PrimaryKey("UserBadgeId", AutoIncrement = true)] + [Cacheable("activeforums_UserBadges", CacheItemPriority.Normal)] + [Scope("ModuleId")] + public class UserBadgeInfo : DotNetNuke.Services.Tokens.IPropertyAccess + { + [IgnoreColumn] + private string cacheKeyTemplate => CacheKeys.UserBadgeInfo; + + private DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo forumUserInfo; + private DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo badgeInfo; + private string badgeName; + private string userName; + + public UserBadgeInfo() + { + } + + public UserBadgeInfo(int userBadgeId, int badgeId, string badgeName, int userId, string userName, int portalId, int moduleId, DateTime? dateAssigned, bool assigned) + { + this.UserBadgeId = userBadgeId; + this.BadgeId = badgeId; + this.UserId = userId; + this.PortalId = portalId; + this.ModuleId = moduleId; + this.BadgeName = badgeName; + this.UserName = userName; + this.Assigned = assigned; + this.DateAssigned = dateAssigned.HasValue ? dateAssigned.Value : DotNetNuke.Common.Utilities.Null.NullDate; + } + + /// + /// Gets or sets the badge ID. + /// + public int UserBadgeId { get; set; } + + /// + /// Gets or sets the badge ID. + /// + public int BadgeId { get; set; } + + /// + /// Gets or sets the User ID. + /// + public int UserId { get; set; } + + /// + /// Gets or sets the PortalId. + /// + public int PortalId { get; set; } + + /// Gets or sets the ModuleId. + /// + public int ModuleId { get; set; } + + /// + /// Gets or sets the UTC date and time the badge was assigned. + /// + public DateTime DateAssigned { get; set; } = DateTime.UtcNow; + + [IgnoreColumn] + public DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo Badge + { + get + { + if (this.badgeInfo == null) + { + this.badgeInfo = this.GetBadge(); + this.UpdateCache(); + } + + return this.badgeInfo; + } + set => this.badgeInfo = value; + } + + internal DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo GetBadge() => this.badgeInfo = new Controllers.BadgeController().GetById(this.BadgeId, this.ModuleId); + + [IgnoreColumn] + public string BadgeName { get => this.badgeName ?? (this.badgeName = this.Badge.Name); set => this.badgeName = value; } + + [IgnoreColumn] + public string UserName { get => this.userName ?? (this.userName = this.ForumUser.DisplayName); set => this.userName = value; } + + [IgnoreColumn] + public bool Assigned { get; set; } + + public int GetAwardCount() + { + return new DotNetNuke.Modules.ActiveForums.Controllers.UserBadgeController().BadgeCount(this.PortalId, this.UserId, this.BadgeId); + } + + [IgnoreColumn] + public DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo ForumUser + { + get + { + if (this.forumUserInfo == null) + { + this.forumUserInfo = this.GetForumUser(); + this.UpdateCache(); + } + + return this.forumUserInfo; + } + set => this.forumUserInfo = value; + } + + internal DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo GetForumUser() => this.forumUserInfo = new Controllers.ForumUserController((int)this.ModuleId).GetByUserId(this.PortalId, this.UserId); + + [IgnoreColumn] + public DotNetNuke.Services.Tokens.CacheLevel Cacheability + { + get + { + return DotNetNuke.Services.Tokens.CacheLevel.notCacheable; + } + } + + [IgnoreColumn] + public string GetProperty(string propertyName, string format, System.Globalization.CultureInfo formatProvider, DotNetNuke.Entities.Users.UserInfo accessingUser, Scope accessLevel, ref bool propertyNotFound) + { + // replace any embedded tokens in format string + if (format.Contains("[")) + { + var tokenReplacer = new DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer(this.ForumUser.PortalSettings, this, this.ForumUser.RequestUri, this.ForumUser.RawUrl) + { + AccessingUser = accessingUser, + }; + format = tokenReplacer.ReplaceEmbeddedTokens(format); + } + + int length = -1; + if (propertyName.Contains(":")) + { + var splitPropertyName = propertyName.Split(':'); + propertyName = splitPropertyName[0]; + length = Utilities.SafeConvertInt(splitPropertyName[1], -1); + } + + propertyName = propertyName.ToLowerInvariant(); + try + { + switch (propertyName) + { + case "id": + case "badgeid": + return PropertyAccess.FormatString(this.BadgeId.ToString(), format); + case "awardcount": + return PropertyAccess.FormatString(this.GetAwardCount() > 1 ? this.GetAwardCount().ToString() : string.Empty, format); + case "name": + return PropertyAccess.FormatString(this.Badge.Name, format); + case "description": + return PropertyAccess.FormatString(Utilities.EncodeBrackets(length > 0 && this.Badge.Description.Length > length ? string.Concat(Utilities.StripHTMLTag(this.Badge.Description), "...") : Utilities.StripHTMLTag(this.Badge.Description)), format); + case "imagemarkup": + return PropertyAccess.FormatString(System.Web.HttpUtility.HtmlDecode(this.Badge.ImageMarkup), format); + case "imageurl": + return PropertyAccess.FormatString(length > 0 ? this.Badge.GetBadgeImageUrl(this.PortalId, length) : this.Badge.GetBadgeImageUrl(this.PortalId), format); + case "dateassigned": + return Utilities.GetUserFormattedDateTime((DateTime?)this.DateAssigned, formatProvider, accessingUser.Profile.PreferredTimeZone.GetUtcOffset(DateTime.UtcNow)); + case "intervaldays": + return PropertyAccess.FormatString(this.Badge.IntervalDays.ToString(), format); + case "threshold": + return PropertyAccess.FormatString(this.Badge.Threshold.ToString(), format); + case "metricname": + return PropertyAccess.FormatString(this.Badge.BadgeMetricEnumName, format); + } + } + catch (Exception ex) + { + DotNetNuke.Modules.ActiveForums.Exceptions.LogException(ex); + DotNetNuke.Modules.ActiveForums.Exceptions.LogException(new ArgumentException(string.Format(Utilities.GetSharedResource("[RESX:TokenReplacementException]"), "UserBadgeInfo", this.UserBadgeId, propertyName, format))); + return string.Empty; + } + + propertyNotFound = true; + return string.Empty; + } + + internal string GetCacheKey() => string.Format(this.cacheKeyTemplate, this.ModuleId, this.UserBadgeId); + + internal void UpdateCache() => DotNetNuke.Modules.ActiveForums.DataCache.ContentCacheStore(this.ModuleId, this.GetCacheKey(), this); + } +} diff --git a/Dnn.CommunityForums/Enums/BadgeMetric.cs b/Dnn.CommunityForums/Enums/BadgeMetric.cs new file mode 100644 index 000000000..922e9b440 --- /dev/null +++ b/Dnn.CommunityForums/Enums/BadgeMetric.cs @@ -0,0 +1,32 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Enums +{ + public enum BadgeMetric + { + BadgeMetricManual, + BadgeMetricNewUser, + BadgeMetricTopicsCreated, + BadgeMetricRepliesCreated, + BadgeMetricLikesReceived, + BadgeMetricTopicsRead, + } +} diff --git a/Dnn.CommunityForums/Enums/TemplateType.cs b/Dnn.CommunityForums/Enums/TemplateType.cs index 08b612f7c..bc7fb36ad 100644 --- a/Dnn.CommunityForums/Enums/TemplateType.cs +++ b/Dnn.CommunityForums/Enums/TemplateType.cs @@ -48,5 +48,8 @@ public enum TemplateType : int TopicResults, _userProfile, _memberList, + BadgeNotificationSubject, + BadgeNotificationBody, + UserBadge, } } diff --git a/Dnn.CommunityForums/ForumSettings.ascx.cs b/Dnn.CommunityForums/ForumSettings.ascx.cs index 4f89d0953..792f996ed 100644 --- a/Dnn.CommunityForums/ForumSettings.ascx.cs +++ b/Dnn.CommunityForums/ForumSettings.ascx.cs @@ -22,11 +22,13 @@ namespace DotNetNuke.Modules.ActiveForums.Controls { using System; using System.Linq; + using System.Reflection; using System.Text; using System.Web; using System.Web.UI.WebControls; using System.Xml; + using DotNetNuke.Collections; using DotNetNuke.Entities.Tabs; using DotNetNuke.Entities.Urls; using DotNetNuke.Framework; @@ -254,17 +256,30 @@ public override void UpdateSettings() this.TimeFormatString = !string.IsNullOrWhiteSpace(this.txtTimeFormat.Text) ? this.txtTimeFormat.Text : "h:mm tt"; this.DateFormatString = !string.IsNullOrWhiteSpace(this.txtDateFormat.Text) ? this.txtDateFormat.Text : "M/d/yyyy"; - this.ForumGroupTemplate = Utilities.SafeConvertInt(this.drpForumGroupTemplate.SelectedValue); - var adminSec = this.txtGroupModSec.Value.Split(','); - this.SaveForumSecurity("groupadmin", adminSec); - var memSec = this.txtGroupMemSec.Value.Split(','); - this.SaveForumSecurity("groupmember", memSec); - var regSec = this.txtGroupRegSec.Value.Split(','); - this.SaveForumSecurity("registereduser", regSec); - var anonSec = this.txtGroupAnonSec.Value.Split(','); - this.SaveForumSecurity("anon", anonSec); - - DotNetNuke.Modules.ActiveForums.Controllers.ForumController.UpdatePermissionsForSocialGroupForums(this.ModuleId); + if (this.Mode.Equals("SocialGroup")) + { + this.ForumGroupTemplate = Utilities.SafeConvertInt(this.drpForumGroupTemplate.SelectedValue); + var adminSec = this.txtGroupModSec.Value.Split(','); + this.SaveForumSecurity("groupadmin", adminSec); + var memSec = this.txtGroupMemSec.Value.Split(','); + this.SaveForumSecurity("groupmember", memSec); + var regSec = this.txtGroupRegSec.Value.Split(','); + this.SaveForumSecurity("registereduser", regSec); + var anonSec = this.txtGroupAnonSec.Value.Split(','); + this.SaveForumSecurity("anon", anonSec); + DotNetNuke.Modules.ActiveForums.Controllers.ForumController.UpdatePermissionsForSocialGroupForums(this.ModuleId); + } + else + { + DotNetNuke.Entities.Modules.ModuleController.Instance.DeleteModuleSetting(this.ModuleId, "ForumConfig"); + DotNetNuke.Entities.Modules.ModuleController.Instance.DeleteModuleSetting(this.ModuleId, "ForumGroupTemplate"); + var fc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumController(); + fc.Get(this.ModuleId).Where(f => f.SocialGroupId != 0).ForEach(forum => + { + forum.SocialGroupId = 0; + fc.Update(forum); + }); + } try { diff --git a/Dnn.CommunityForums/Providers/DataProviders/SqlDataProvider/SqlDataProvider.cs b/Dnn.CommunityForums/Providers/DataProviders/SqlDataProvider/SqlDataProvider.cs index b553ad276..fad1d9319 100644 --- a/Dnn.CommunityForums/Providers/DataProviders/SqlDataProvider/SqlDataProvider.cs +++ b/Dnn.CommunityForums/Providers/DataProviders/SqlDataProvider/SqlDataProvider.cs @@ -124,6 +124,13 @@ public override DataSet Dashboard_Get(int PortalId, int ModuleId) return (DataSet)SqlHelper.ExecuteDataset(this.ConnectionString, this.DatabaseOwner + this.ObjectQualifier + "activeforums_DashBoard_Stats", PortalId, ModuleId); } + #endregion + #region Badges + public override IDataReader Badges_List(int ModuleId) + { + return (IDataReader)SqlHelper.ExecuteReader(this.ConnectionString, this.DatabaseOwner + this.ObjectQualifier + "activeforums_Badges_List", ModuleId); + } + #endregion #region Filters [Obsolete("Deprecated in Community Forums. Scheduled removal in 10.00.00. Use DotNetNuke.Modules.ActiveForums.Controllers.FilterController.Delete()")] @@ -236,7 +243,7 @@ public override void Groups_Move(int ModuleId, int ForumGroupId, int SortDirecti [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No longer used.")] public override int Groups_Save(int PortalId, int ModuleId, int ForumGroupId, string GroupName, int SortOrder, bool Active, bool Hidden, int PermissionsId, string PrefixURL) { - return Convert.ToInt32(SqlHelper.ExecuteScalar(this.ConnectionString, this.DatabaseOwner + this.ObjectQualifier + "activeforums_Groups_Save", PortalId, ModuleId, ForumGroupId, GroupName, SortOrder, Active, Hidden, PermissionsId, PrefixURL, $"G:{ForumGroupId}")); + return Convert.ToInt32(SqlHelper.ExecuteScalar(this.ConnectionString, this.DatabaseOwner + this.ObjectQualifier + "activeforums_Groups_Save", PortalId, ModuleId, ForumGroupId, GroupName, SortOrder, Active, Hidden, PermissionsId, PrefixURL, $"G{ForumGroupId}")); } public override int Groups_Save(int PortalId, int ModuleId, int ForumGroupId, string GroupName, int SortOrder, bool Active, bool Hidden, int PermissionsId, string PrefixURL, string GroupSettingsKey) @@ -403,27 +410,31 @@ public override IDataReader Security_GetByKey(string SecurityKey) #endregion #region Settings + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public override void Settings_Delete(int ModuleId, string GroupKey, string SettingName) { SqlHelper.ExecuteNonQuery(this.ConnectionString, this.DatabaseOwner + this.ObjectQualifier + "activeforums_Settings_Delete", ModuleId, GroupKey, SettingName); } + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public override string Settings_Get(int ModuleId, string GroupKey, string SettingName) { return Convert.ToString(SqlHelper.ExecuteScalar(this.ConnectionString, this.DatabaseOwner + this.ObjectQualifier + "activeforums_Settings_Get", ModuleId, GroupKey, SettingName)); } + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public override System.Data.IDataReader Settings_List(int ModuleId, string GroupKey) { return SqlHelper.ExecuteReader(this.ConnectionString, this.DatabaseOwner + this.ObjectQualifier + "activeforums_Settings_List", ModuleId, GroupKey); } - // KR - grabs all settings for caching + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public override System.Data.IDataReader Settings_ListAll(int ModuleId) { return SqlHelper.ExecuteReader(this.ConnectionString, this.DatabaseOwner + this.ObjectQualifier + "activeforums_Settings_ListAll", ModuleId); } + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public override void Settings_Save(int ModuleId, string GroupKey, string SettingName, string SettingValue) { SqlHelper.ExecuteNonQuery(this.ConnectionString, this.DatabaseOwner + this.ObjectQualifier + "activeforums_Settings_Save", ModuleId, GroupKey, SettingName, SettingValue); diff --git a/Dnn.CommunityForums/ReleaseNotes.txt b/Dnn.CommunityForums/ReleaseNotes.txt index 429149212..93c1e4005 100644 --- a/Dnn.CommunityForums/ReleaseNotes.txt +++ b/Dnn.CommunityForums/ReleaseNotes.txt @@ -46,19 +46,20 @@ DNN Community Forums Release Notes

- 09.01.01 + 09.02.00

- -

New Features & Enhancements

    +
  • NEW: User Badges (PR# 1579)
  • +
  • UPDATE: Change User Setting "Subscribe to Topics" to "Auto-Subscribe to My Topics (Issue 1579)
  • +
  • UPDATE: Encode non-Latin characters in content-disposition for attachments (Issue 1604)
  • None at this time.
  • +-->

Bug Fixes

    -
  • FIX: Poor performance for avatar refresh queue on large sites (Issue 1584)
  • + +
  • FIX: Error moving topics to another forum (Issue 1594)
  • +
  • FIX: Forum permissions changing under certain rare conditions when updating module settings (Issue 1606)
  • +
  • FIX: Missing (resource) text when viewing tags in Control Panel (Issue 1593)
  • +
  • FIX: On "My Subscriptions" page, forums subscriptions not showing if not subscribed to any forums yet (Issue 1608)
  • +
  • FIX: Reserved HTML characters in topic subjects no longer are encoded in e-mail notification subjects (Issue 1607)

Tasks / Development Updates (and Technical Debt)

    +
  • Modernize "Settings" table (Issue 1582)
  • +
  • Track Dates for Likes (Issue 1535)
  • +
  • Remove colon from internally-used settings keys (Issue 1547)
  • +
  • 09.02.00 Release Prep (Issue 1612)
  • None at this time.
  • +-->

diff --git a/Dnn.CommunityForums/Services/AdminServiceController.cs b/Dnn.CommunityForums/Services/AdminServiceController.cs index f2b8244d0..1cb8e8f5d 100644 --- a/Dnn.CommunityForums/Services/AdminServiceController.cs +++ b/Dnn.CommunityForums/Services/AdminServiceController.cs @@ -72,7 +72,7 @@ public class RunMaintenanceDTO public HttpResponseMessage RunMaintenance(RunMaintenanceDTO dto) { - var moduleSettings = new SettingsInfo { ModuleId = dto.ModuleId, MainSettings = DotNetNuke.Entities.Modules.ModuleController.Instance.GetModule(moduleId: dto.ModuleId, DotNetNuke.Common.Utilities.Null.NullInteger, true).ModuleSettings }; + var moduleSettings = new ModuleSettings { ModuleId = dto.ModuleId, MainSettings = DotNetNuke.Entities.Modules.ModuleController.Instance.GetModule(moduleId: dto.ModuleId, DotNetNuke.Common.Utilities.Null.NullInteger, true).ModuleSettings }; var rows = DataProvider.Instance().Forum_Maintenance(dto.ForumId, dto.OlderThan, dto.LastActive, dto.ByUserId, dto.WithNoReplies, dto.DryRun, (int)moduleSettings.DeleteBehavior); if (dto.DryRun) { diff --git a/Dnn.CommunityForums/Services/Avatars/AvatarRefreshQueue.cs b/Dnn.CommunityForums/Services/Avatars/AvatarRefreshQueue.cs index e83e92f9e..2c6526e76 100644 --- a/Dnn.CommunityForums/Services/Avatars/AvatarRefreshQueue.cs +++ b/Dnn.CommunityForums/Services/Avatars/AvatarRefreshQueue.cs @@ -99,28 +99,33 @@ private static int RefreshGravatars(int portalId, int moduleId) { try { - var forumUserController = new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(moduleId: moduleId); - string sSql = "SELECT TOP 50 fup.UserId FROM {databaseOwner}{objectQualifier}activeforums_UserProfiles fup "; - sSql += "INNER JOIN {databaseOwner}{objectQualifier}UserPortals as up ON up.PortalId = fup.PortalId AND up.UserId = fup.UserId AND up.IsDeleted = 0 "; - sSql += "INNER JOIN {databaseOwner}{objectQualifier}ProfilePropertyDefinition ppd ON ppd.PortalID = @0 AND ppd.PropertyName = 'Photo' "; - sSql += "LEFT OUTER JOIN {databaseOwner}{objectQualifier}UserProfile as upr ON upr.UserId = fup.UserId AND upr.PropertyDefinitionID = ppd.PropertyDefinitionID "; - sSql += "WHERE fup.PortalId = @0 AND fup.AvatarDisabled = 0 AND fup.PrefBlockAvatars = 0 "; - sSql += "AND ( (fup.AvatarLastRefresh IS NULL AND upr.PropertyValue IS NULL) "; - sSql += " OR (fup.AvatarLastRefresh IS NOT NULL AND DATEDIFF(dd,GETUTCDATE(),fup.AvatarLastRefresh) > 90) ) "; - sSql += "ORDER BY fup.AvatarLastRefresh DESC"; - var userIds = DotNetNuke.Data.DataContext.Instance().ExecuteQuery(System.Data.CommandType.Text, sSql, portalId); - - var users = new List(); - foreach (var userId in userIds) - { - var forumUser = forumUserController.GetByUserId(portalId: portalId, userId: userId); - if (forumUser != null) - { - users.Add(forumUser); - } - } - - return users; + return new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(moduleId: moduleId).GetActiveUsers(portalId: portalId).Where(u => (!u.UserInfo.IsDeleted && !u.AvatarDisabled && !u.PrefBlockAvatars) && + ((string.IsNullOrEmpty(u.UserInfo.Profile.GetPropertyValue("Photo")) && !u.AvatarLastRefresh.HasValue) || /* anyone without an avatar who has never had their avatar refreshed */ + (u.AvatarLastRefresh.HasValue && DateTime.UtcNow.Subtract(u.AvatarLastRefresh.Value).TotalDays > 90))) /* or anyone whose avatar was last refreshed more than 90 days ago */ + .OrderByDescending(u => u.AvatarLastRefresh).Take(50).ToList(); + + //var forumUserController = new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(moduleId: moduleId); + //string sSql = "SELECT TOP 50 fup.UserId FROM {databaseOwner}{objectQualifier}activeforums_UserProfiles fup "; + //sSql += "INNER JOIN {databaseOwner}{objectQualifier}UserPortals as up ON up.PortalId = fup.PortalId AND up.UserId = fup.UserId AND up.IsDeleted = 0 "; + //sSql += "INNER JOIN {databaseOwner}{objectQualifier}ProfilePropertyDefinition ppd ON ppd.PortalID = @0 AND ppd.PropertyName = 'Photo' "; + //sSql += "LEFT OUTER JOIN {databaseOwner}{objectQualifier}UserProfile as upr ON upr.UserId = fup.UserId AND upr.PropertyDefinitionID = ppd.PropertyDefinitionID "; + //sSql += "WHERE fup.PortalId = @0 AND fup.AvatarDisabled = 0 AND fup.PrefBlockAvatars = 0 "; + //sSql += "AND ( (fup.AvatarLastRefresh IS NULL AND upr.PropertyValue IS NULL) "; + //sSql += " OR (fup.AvatarLastRefresh IS NOT NULL AND DATEDIFF(dd,GETUTCDATE(),fup.AvatarLastRefresh) > 90) ) "; + //sSql += "ORDER BY fup.AvatarLastRefresh DESC"; + //var userIds = DotNetNuke.Data.DataContext.Instance().ExecuteQuery(System.Data.CommandType.Text, sSql, portalId); + + //var users = new List(); + //foreach (var userId in userIds) + //{ + // var forumUser = forumUserController.GetByUserId(portalId: portalId, userId: userId); + // if (forumUser != null) + // { + // users.Add(forumUser); + // } + //} + + //return users; } catch (Exception ex) { diff --git a/Dnn.CommunityForums/Services/Badges/BadgeAwardQueue.cs b/Dnn.CommunityForums/Services/Badges/BadgeAwardQueue.cs new file mode 100644 index 000000000..4573bbb93 --- /dev/null +++ b/Dnn.CommunityForums/Services/Badges/BadgeAwardQueue.cs @@ -0,0 +1,193 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Services.Badges +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using DotNetNuke.Collections; + using DotNetNuke.Common.Utilities; + using DotNetNuke.Entities.Modules; + using DotNetNuke.Modules.ActiveForums.Enums; + using DotNetNuke.Services.Log.EventLog; + using DotNetNuke.Services.Scheduling; + + public class BadgeAwardQueue : DotNetNuke.Services.Scheduling.SchedulerClient + { + public BadgeAwardQueue(ScheduleHistoryItem scheduleHistoryItem) + { + this.ScheduleHistoryItem = scheduleHistoryItem; + } + + public override void DoWork() + { + try + { + foreach (DotNetNuke.Abstractions.Portals.IPortalInfo portal in DotNetNuke.Entities.Portals.PortalController.Instance.GetPortals()) + { + foreach (ModuleInfo module in DotNetNuke.Entities.Modules.ModuleController.Instance.GetModules(portal.PortalId)) + { + if (!module.IsDeleted && module.DesktopModule.ModuleName.Trim().ToLowerInvariant().Equals(Globals.ModuleName.ToLowerInvariant())) + { + var badgeCount = ProcessBadgeAwards(module.PortalID, module.ModuleID); + this.ScheduleHistoryItem.Succeeded = true; + this.ScheduleHistoryItem.AddLogNote($"Processed {badgeCount} badge awards for {module.ModuleTitle} on portal {portal.PortalName}. "); + } + } + } + } + catch (Exception ex) + { + this.ScheduleHistoryItem.Succeeded = false; + this.ScheduleHistoryItem.AddLogNote(string.Concat("Badge Award Queue Failed. ", ex)); + this.Errored(ref ex); + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + } + + private static int ProcessBadgeAwards(int portalId, int moduleId) + { + var badgeCount = 0; + try + { + var badges = new DotNetNuke.Modules.ActiveForums.Controllers.BadgeController().Get(moduleId).Where(b => b.BadgeMetric != BadgeMetric.BadgeMetricManual); + GetBatch(portalId, moduleId).ForEach(forumUser => + { + foreach (var badge in badges) + { + var awarded = ProcessBadgesForUser(portalId: portalId, moduleId: moduleId, forumUser: forumUser, badge: badge); + if (awarded) + { + badgeCount += 1; + } + } + }); + badges.Where(b => !b.InitialBackfillCompletedDate.HasValue).ForEach(b => { + b.InitialBackfillCompletedDate = DateTime.UtcNow; + new DotNetNuke.Modules.ActiveForums.Controllers.BadgeController().Update(b); + }); + + return badgeCount; + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return -1; + } + } + + private static IEnumerable GetBatch(int portalId, int moduleId) + { + try + { + return new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(moduleId: moduleId).GetActiveUsers(portalId); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return null; + } + } + + private static bool ProcessBadgesForUser(int portalId, int moduleId, DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo forumUser, DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo badge) + { + try + { + if (forumUser == null) + { + return false; + } + + if (badge.OneTimeAward && forumUser.Badges.Any(b => b.BadgeId.Equals(badge.BadgeId))) + { + // One-time award badge has already been awarded to this user + return false; + } + + var lastAward = forumUser.Badges.Where(b => b.BadgeId.Equals(badge.BadgeId)).OrderByDescending(b => b.DateAssigned).FirstOrDefault(); + if (lastAward != null && lastAward.DateAssigned.AddDays(badge.IntervalDays) > DateTime.UtcNow) + { + // Badge has already been awarded within the interval period + return false; + } + + var awardBadge = false; + switch (badge.BadgeMetric) + { + case BadgeMetric.BadgeMetricNewUser: + if (DateTime.UtcNow.Subtract(forumUser.DateCreated).TotalDays < (badge.IntervalDays > 0 ? badge.IntervalDays : 30)) + { + awardBadge = true; + } + + break; + case BadgeMetric.BadgeMetricLikesReceived: + if ((badge.IntervalDays > 0 && forumUser.GetLikeCountForUserSince(DateTime.UtcNow.AddDays(-1 * badge.IntervalDays)) >= badge.Threshold) || + (forumUser.GetLikeCountForUser() >= badge.Threshold)) + { + awardBadge = true; + } + + break; + case BadgeMetric.BadgeMetricTopicsCreated: + if ((badge.IntervalDays > 0 && forumUser.GetTopicCountSince(DateTime.UtcNow.AddDays(-1 * badge.IntervalDays)) >= badge.Threshold) || + (forumUser.TopicCount >= badge.Threshold)) + { + awardBadge = true; + } + + break; + case BadgeMetric.BadgeMetricRepliesCreated: + if ((badge.IntervalDays > 0 && forumUser.GetReplyCountSince(DateTime.UtcNow.AddDays(-1 * badge.IntervalDays)) >= badge.Threshold) || + (forumUser.ReplyCount >= badge.Threshold)) + { + awardBadge = true; + } + + break; + case BadgeMetric.BadgeMetricTopicsRead: + if ((badge.IntervalDays > 0 && forumUser.GetTopicReadCountSince(DateTime.UtcNow.AddDays(-1 * badge.IntervalDays)) >= badge.Threshold) || + (forumUser.GetTopicReadCount() >= badge.Threshold)) + { + awardBadge = true; + } + + break; + } + + if (awardBadge) + { + DotNetNuke.Modules.ActiveForums.Controllers.UserBadgeController.AssignUserBadge(portalId, moduleId, forumUser.UserId, badge.BadgeId, string.Empty); + return true; + } + + return false; + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return false; + } + } +} diff --git a/Dnn.CommunityForums/Services/Controllers/ControllerBase.cs b/Dnn.CommunityForums/Services/Controllers/ControllerBase.cs index 39cc04fa6..2c5946976 100644 --- a/Dnn.CommunityForums/Services/Controllers/ControllerBase.cs +++ b/Dnn.CommunityForums/Services/Controllers/ControllerBase.cs @@ -32,7 +32,7 @@ namespace DotNetNuke.Modules.ActiveForums.Services /// /// /// - [SupportedModules(Globals.ModuleName + "," + Globals.ModuleName + " Viewer," + Globals.ModuleFriendlyName + "," + Globals.ModuleFriendlyName + " Viewer")] /* this MUST match DesktopModule.ModuleName so use new constant */ + [SupportedModules(Globals.ModuleName + "," + Globals.ModuleName + " Viewer")] /* this MUST match DesktopModule.ModuleName so use constant */ public class ControllerBase : DnnApiController { private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(T)); @@ -40,8 +40,8 @@ public class ControllerBase : DnnApiController /// provide a simple method for testing /// /// - [AllowAnonymous] [HttpGet] + [AllowAnonymous] public HttpResponseMessage HelloWorld() { try diff --git a/Dnn.CommunityForums/Services/Controllers/FeatureSettingsController.cs b/Dnn.CommunityForums/Services/Controllers/FeatureSettingsController.cs new file mode 100644 index 000000000..20bdc460b --- /dev/null +++ b/Dnn.CommunityForums/Services/Controllers/FeatureSettingsController.cs @@ -0,0 +1,182 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Services.Controllers +{ + using System; + using System.Collections; + using System.Reflection; + using System.Web.Http; + + using DotNetNuke.Web.Api; + + /// + /// Web API controller for managing feature settings. + /// + public class FeatureSettingsController : ControllerBase + { + /// + /// Gets all settings for a given settings key. + /// + /// settingsKey + /// settings + [HttpGet] + [DnnAuthorize] + public IHttpActionResult GetAllSettings(string settingsKey) + { + try + { + var settings = new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(this.ForumModuleId, settingsKey); + return this.Ok(settings.featureSettings); + } + catch (Exception ex) + { + return this.InternalServerError(ex); + } + } + + /// + /// Gets a single setting value by key. + /// + /// settingsKey + /// key + /// setting + [HttpGet] + [DnnAuthorize] + public IHttpActionResult GetSetting(string settingsKey, string key) + { + try + { + var settings = new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(this.ForumModuleId, settingsKey); + if (!settings.featureSettings.ContainsKey(key)) + { + return this.NotFound(); + } + return Ok(settings.featureSettings[key]); + } + catch (Exception ex) + { + return this.InternalServerError(ex); + } + } + + /// + /// Creates or updates a single setting. + /// + /// settingsKey + /// key + /// value + /// HTTP status + [HttpPost] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public IHttpActionResult SetSetting(string settingsKey, string key, [FromBody] string value) + { + try + { + var settings = new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(this.ForumModuleId, settingsKey); + settings.featureSettings[key] = value; + DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings.Save(this.ForumModuleId, settingsKey, settings); + return this.Ok(); + } + catch (Exception ex) + { + return this.InternalServerError(ex); + } + } + + /// + /// Deletes a single setting. + /// + /// settingsKey + /// key + /// HTTP status + [HttpDelete] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public IHttpActionResult DeleteSetting(string settingsKey, string key) + { + try + { + var settings = new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(this.ForumModuleId, settingsKey); + if (!settings.featureSettings.ContainsKey(key)) + { + return this.NotFound(); + } + settings.featureSettings.Remove(key); + DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings.Save(this.ForumModuleId, settingsKey, settings); + return this.Ok(); + } + catch (Exception ex) + { + return this.InternalServerError(ex); + } + } + + /// + /// Updates all settings for a given module and settings key. + /// + /// settingsKey + /// newSettings + /// HTTP status + [HttpPut] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public IHttpActionResult UpdateAllSettings(string settingsKey, [FromBody] Hashtable newSettings) + { + try + { + var settings = new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(newSettings); + DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings.Save(this.ForumModuleId, settingsKey, settings); + return this.Ok(); + } + catch (Exception ex) + { + return this.InternalServerError(ex); + } + } + + /// + /// Deletes all settings for a given settings key. + /// + /// settingsKey + /// HTTP status + [HttpDelete] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public IHttpActionResult DeleteAllSettings(string settingsKey) + { + try + { + var settings = new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(this.ForumModuleId, settingsKey); + foreach (DictionaryEntry entry in settings.featureSettings) + { + new DotNetNuke.Modules.ActiveForums.Controllers.SettingsController().DeleteForModuleIdSettingsKeySettingName(this.ForumModuleId, settingsKey, (string)entry.Key); + } + + return this.Ok(); + } + catch (Exception ex) + { + return this.InternalServerError(ex); + } + } + } +} diff --git a/Dnn.CommunityForums/Services/Controllers/ForumController.cs b/Dnn.CommunityForums/Services/Controllers/ForumController.cs index 87cf5ebaa..c3b111e29 100644 --- a/Dnn.CommunityForums/Services/Controllers/ForumController.cs +++ b/Dnn.CommunityForums/Services/Controllers/ForumController.cs @@ -21,16 +21,18 @@ namespace DotNetNuke.Modules.ActiveForums.Services.Controllers { using System; + using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Web.Http; + using System.Web.UI; using DotNetNuke.Web.Api; /// /// /// - public class ForumController : ControllerBase + public class ForumController : ControllerBase { public struct ForumDto { @@ -73,6 +75,7 @@ public HttpResponseMessage Subscribe(ForumDto dto) /// https://dnndev.me/API/ActiveForums/Forum/SubscriberCount?ForumId=xxx [HttpGet] [DnnAuthorize] + [ForumsAuthorize(SecureActions.View)] public HttpResponseMessage SubscriberCount(int forumId) { try @@ -91,12 +94,13 @@ public HttpResponseMessage SubscriberCount(int forumId) } /// - /// Gets Subscriber count string for a Forum + /// Gets Subscriber count string for a Forum. /// /// /// https://dnndev.me/API/ActiveForums/Forum/SubscriberCountString?ForumId=xxx [HttpGet] [DnnAuthorize] + [ForumsAuthorize(SecureActions.View)] public HttpResponseMessage SubscriberCountString(int forumId) { try @@ -115,7 +119,7 @@ public HttpResponseMessage SubscriberCountString(int forumId) } /// - /// Populates list of forums for an HTML control + /// Populates list of forums for an HTML control. /// /// /// @@ -137,5 +141,322 @@ public HttpResponseMessage ListForHtml(ForumDto dto) return this.Request.CreateResponse(HttpStatusCode.BadRequest); } + + /// + /// Gets a forum by ID. + /// + /// Forum ID + /// ForumInfo + /// https://dnndev.me/API/ActiveForums/Forum/Get?forumId=x + [HttpGet] + [DnnAuthorize] + [ForumsAuthorize(SecureActions.View)] + public HttpResponseMessage Get(int forumId) + { + try + { + if (forumId > 0) + { + var forum = new DotNetNuke.Modules.ActiveForums.Controllers.ForumController().GetById(forumId: forumId, moduleId: this.ForumModuleId); + if (forum != null) + { + return this.Request.CreateResponse(HttpStatusCode.OK, new DotNetNuke.Modules.ActiveForums.ViewModels.Forum(forum)); + } + + return this.Request.CreateResponse(HttpStatusCode.NotFound); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Creates a new forum. + /// + /// ForumInfo + /// Created forum + [HttpPost] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Create([FromBody] DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forum) + { + try + { + if (forum != null) + { + var fc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumController(); + forum.ForumID = DotNetNuke.Common.Utilities.Null.NullInteger; + forum.ModuleId = this.ForumModuleId; + forum.ParentForumId = 0; + var forumId = fc.Forums_Save(portalId: this.ActiveModule.PortalID, forumInfo: forum, isNew: true, useGroupFeatures: true, useGroupSecurity: true); + var forumCreated = fc.GetById(forumId: forumId, moduleId: this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.Created, forumCreated); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Creates a new forum. + /// + /// ForumInfo + /// + /// + /// Created forum + [HttpPost] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Create([FromBody] DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forum, bool useGroupFeatures, bool useGroupSecurity) + { + try + { + if (forum != null) + { + var fc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumController(); + forum.ForumID = DotNetNuke.Common.Utilities.Null.NullInteger; + forum.ModuleId = this.ForumModuleId; + forum.ParentForumId = 0; + var forumId = fc.Forums_Save(portalId: this.ActiveModule.PortalID, forumInfo: forum, isNew: true, useGroupFeatures: useGroupFeatures, useGroupSecurity: useGroupSecurity); + var forumCreated = fc.GetById(forumId: forumId, moduleId: this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.Created, forumCreated); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Updates an existing forum. + /// + /// ForumInfo + /// updated forum + [HttpPut] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Update([FromBody] DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forum) + { + try + { + if (forum != null && forum.ForumID > 0) + { + var fc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumController(); + var forumId = fc.Forums_Save(portalId: this.ActiveModule.PortalID, forumInfo: forum, isNew: false, useGroupFeatures: forum.InheritSettings, useGroupSecurity: forum.InheritSecurity); + var forumUpdated = fc.GetById(forumId: forum.ForumID, moduleId: this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.Created, forumUpdated); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Updates an existing forum. + /// + /// ForumInfo + /// + /// + /// Success status + [HttpPut] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Update([FromBody] DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forum, bool useGroupFeatures, bool useGroupSecurity) + { + try + { + if (forum != null && forum.ForumID > 0) + { + var fc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumController(); + var forumId = fc.Forums_Save(portalId: this.ActiveModule.PortalID, forumInfo: forum, isNew: false, useGroupFeatures: useGroupFeatures, useGroupSecurity: useGroupSecurity); + var forumUpdated = fc.GetById(forumId: forum.ForumID, moduleId: this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.Created, forumUpdated); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Deletes a forum by ID. + /// + /// Forum ID + /// Success status + [HttpDelete] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Delete(int forumId) + { + try + { + if (forumId > 0) + { + var fc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumController(); + var forum = fc.GetById(forumId: forumId, moduleId: this.ForumModuleId); + if (forum != null) + { + fc.Forums_Delete(forumId: forumId, moduleId: this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.OK, true); + } + + return this.Request.CreateResponse(HttpStatusCode.NotFound); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Lists all forums for the current module. + /// + [HttpGet] + [DnnAuthorize] + public HttpResponseMessage List() + { + try + { + var forumUser = new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ForumModuleId).GetByUserId(this.ActiveModule.PortalID, this.UserInfo.UserID); + var forums = new List(); + new DotNetNuke.Modules.ActiveForums.Controllers.ForumController().GetForums(moduleId: this.ForumModuleId).ForEach(f => + { + if (DotNetNuke.Modules.ActiveForums.Controllers.PermissionController.HasRequiredPerm(f.Security.ViewRoleIds, forumUser.UserRoleIds)) + { + forums.Add(new DotNetNuke.Modules.ActiveForums.ViewModels.Forum(f)); + } + }); + + return this.Request.CreateResponse(HttpStatusCode.OK, forums); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return this.Request.CreateResponse(HttpStatusCode.InternalServerError); + } + } + + /// + /// Lists moderators for a forum. + /// + [HttpGet] + [DnnAuthorize] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Moderators(int forumId) + { + try + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(new NotImplementedException("Forum moderators retrieval not implemented yet.")); + return this.Request.CreateResponse(HttpStatusCode.InternalServerError); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return this.Request.CreateResponse(HttpStatusCode.InternalServerError); + } + } + + /// + /// Lists all forums the current user is subscribed to. + /// + [HttpGet] + [DnnAuthorize] + public HttpResponseMessage Subscriptions(int userId) + { + try + { + if (userId > 0) + { + var subscriptions = new DotNetNuke.Modules.ActiveForums.Controllers.SubscriptionController().SubscribedForums(portalId: this.ActiveModule.PortalID, moduleId: this.ForumModuleId, userId: userId); + return this.Request.CreateResponse(HttpStatusCode.OK, subscriptions); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return this.Request.CreateResponse(HttpStatusCode.InternalServerError); + } + } + + /// + /// Gets forum settings. + /// + [HttpGet] + [DnnAuthorize] + public HttpResponseMessage Settings(int forumId) + { + try + { + if (forumId > 0) + { + var forum = new DotNetNuke.Modules.ActiveForums.Controllers.ForumController().GetById(forumId: forumId, moduleId: this.ForumModuleId); + if (forum != null) + { + return this.Request.CreateResponse(HttpStatusCode.OK, forum.FeatureSettings); + } + + return this.Request.CreateResponse(HttpStatusCode.NotFound); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return this.Request.CreateResponse(HttpStatusCode.InternalServerError); + } + } + + /// + /// Gets forum security. + /// + [HttpGet] + [DnnAuthorize] + public HttpResponseMessage Security(int forumId) + { + try + { + if (forumId > 0) + { + var forum = new DotNetNuke.Modules.ActiveForums.Controllers.ForumController().GetById(forumId: forumId, moduleId: this.ForumModuleId); + if (forum != null) + { + return this.Request.CreateResponse(HttpStatusCode.OK, forum.Security); + } + + return this.Request.CreateResponse(HttpStatusCode.NotFound); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return this.Request.CreateResponse(HttpStatusCode.InternalServerError); + } + } } } diff --git a/Dnn.CommunityForums/Services/Controllers/ForumGroupController.cs b/Dnn.CommunityForums/Services/Controllers/ForumGroupController.cs new file mode 100644 index 000000000..15fd7195a --- /dev/null +++ b/Dnn.CommunityForums/Services/Controllers/ForumGroupController.cs @@ -0,0 +1,301 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Services.Controllers +{ + using System; + using System.Net; + using System.Net.Http; + using System.Web.Http; + + using DotNetNuke.Web.Api; + + /// + /// + /// + public class ForumGroupController : ControllerBase + { + public struct ForumGroupDto + { + public int ForumGroupId { get; set; } + } + + /// + /// Gets a ForumGroup by ID. + /// + /// ForumGroup ID + /// ForumGroupInfo + /// https://dnndev.me/API/ActiveForums/ForumGroup/Get?ForumGroupId=x + [HttpGet] + [DnnAuthorize] + public HttpResponseMessage Get(int ForumGroupId) + { + try + { + if (ForumGroupId > 0) + { + var forumGroup = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController().GetById(ForumGroupId, this.ForumModuleId); + if (forumGroup != null) + { + return this.Request.CreateResponse(HttpStatusCode.OK, forumGroup); + } + + return this.Request.CreateResponse(HttpStatusCode.NotFound); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Creates a new ForumGroup. + /// + /// ForumGroupInfo + /// Created ForumGroup + [HttpPost] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Create([FromBody] DotNetNuke.Modules.ActiveForums.Entities.ForumGroupInfo forumGroup) + { + try + { + if (forumGroup != null) + { + var fgc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController(); + forumGroup.ForumGroupId = DotNetNuke.Common.Utilities.Null.NullInteger; + forumGroup.ModuleId = this.ForumModuleId; + var forumGroupId = fgc.Groups_Save(portalId: this.ActiveModule.PortalID, forumGroupInfo: forumGroup, isNew: true, useDefaultFeatures: true, useDefaultSecurity: true); + var forumGroupCreated = fgc.GetById(forumGroupId, this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.Created, forumGroupCreated); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Creates a new ForumGroup. + /// + /// ForumGroupInfo + /// + /// + /// Created ForumGroup + [HttpPost] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Create([FromBody] DotNetNuke.Modules.ActiveForums.Entities.ForumGroupInfo forumGroup, bool useDefaultFeatures, bool useDefaultSecurity) + { + try + { + if (forumGroup != null) + { + var fgc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController(); + forumGroup.ForumGroupId = DotNetNuke.Common.Utilities.Null.NullInteger; + forumGroup.ModuleId = this.ForumModuleId; + var forumGroupId = fgc.Groups_Save(portalId: this.ActiveModule.PortalID, forumGroupInfo: forumGroup, isNew: true, useDefaultFeatures: useDefaultFeatures, useDefaultSecurity: useDefaultSecurity); + var forumGroupCreated = fgc.GetById(forumGroupId, this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.Created, forumGroupCreated); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Updates an existing ForumGroup. + /// + /// ForumGroupInfo + /// updated ForumGroup + [HttpPut] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Update([FromBody] DotNetNuke.Modules.ActiveForums.Entities.ForumGroupInfo forumGroup) + { + try + { + if (forumGroup != null && forumGroup.ForumGroupId > 0) + { + var fgc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController(); + var forumGroupId = fgc.Groups_Save(portalId: this.ActiveModule.PortalID, forumGroupInfo: forumGroup, isNew: false, useDefaultFeatures: forumGroup.InheritSettings, useDefaultSecurity: forumGroup.InheritSecurity); + var forumGroupUpdated = fgc.GetById(forumGroup.ForumGroupId, this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.Created, forumGroupUpdated); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Updates an existing ForumGroup. + /// + /// ForumGroupInfo + /// + /// + /// Success status + [HttpPut] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Update([FromBody] DotNetNuke.Modules.ActiveForums.Entities.ForumGroupInfo forumGroup, bool useDefaultFeatures, bool useDefaultSecurity) + { + try + { + if (forumGroup != null && forumGroup.ForumGroupId > 0) + { + var fgc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController(); + var forumGroupId = fgc.Groups_Save(portalId: this.ActiveModule.PortalID, forumGroupInfo: forumGroup, isNew: false, useDefaultFeatures: useDefaultFeatures, useDefaultSecurity: useDefaultSecurity); + var forumGroupUpdated = fgc.GetById(forumGroupId: forumGroup.ForumGroupId, moduleId: this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.Created, forumGroupUpdated); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Deletes a ForumGroup by ID. + /// + /// ForumGroup ID + /// Success status + [HttpDelete] + [ValidateAntiForgeryToken] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Delete(int forumGroupId) + { + try + { + if (forumGroupId > 0) + { + var fgc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController(); + var forumGroup = fgc.GetById(forumGroupId: forumGroupId, moduleId: this.ForumModuleId); + if (forumGroup != null) + { + fgc.Groups_Delete(moduleId: this.ForumModuleId, forumGroupId: forumGroupId); + return this.Request.CreateResponse(HttpStatusCode.OK, true); + } + + return this.Request.CreateResponse(HttpStatusCode.NotFound); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + + /// + /// Lists all ForumGroups for the current module. + /// + [HttpGet] + [DnnAuthorize] + public HttpResponseMessage List() + { + try + { + var forumGroups = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController().Get(scopeValue: this.ForumModuleId); + return this.Request.CreateResponse(HttpStatusCode.OK, forumGroups); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return this.Request.CreateResponse(HttpStatusCode.InternalServerError); + } + } + + /// + /// Gets ForumGroup settings. + /// + [HttpGet] + [DnnAuthorize] + public HttpResponseMessage Settings(int ForumGroupId) + { + try + { + if (ForumGroupId > 0) + { + var forumGroup = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController().GetById(forumGroupId: ForumGroupId, moduleId: this.ForumModuleId); + if (forumGroup != null) + { + return this.Request.CreateResponse(HttpStatusCode.OK, forumGroup.FeatureSettings); + } + + return this.Request.CreateResponse(HttpStatusCode.NotFound); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return this.Request.CreateResponse(HttpStatusCode.InternalServerError); + } + } + + /// + /// Gets ForumGroup security. + /// + [HttpGet] + [DnnAuthorize] + public HttpResponseMessage Security(int ForumGroupId) + { + try + { + if (ForumGroupId > 0) + { + var forumGroup = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController().GetById(forumGroupId: ForumGroupId, moduleId: this.ForumModuleId); + if (forumGroup != null) + { + return this.Request.CreateResponse(HttpStatusCode.OK, forumGroup.Security); + } + + return this.Request.CreateResponse(HttpStatusCode.NotFound); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + return this.Request.CreateResponse(HttpStatusCode.InternalServerError); + } + } + } +} diff --git a/Dnn.CommunityForums/Services/Controllers/LikeController.cs b/Dnn.CommunityForums/Services/Controllers/LikeController.cs index 5ab1dbc26..270cda62e 100644 --- a/Dnn.CommunityForums/Services/Controllers/LikeController.cs +++ b/Dnn.CommunityForums/Services/Controllers/LikeController.cs @@ -87,6 +87,7 @@ public HttpResponseMessage Like(LikeDto dto) /// https://dnndev.me/API/ActiveForums/Like/Get/1/1 [HttpGet] [DnnAuthorize] + [ForumsAuthorize(SecureActions.View)] public HttpResponseMessage Get(int forumId, int contentId) { try diff --git a/Dnn.CommunityForums/Services/Controllers/TagController.cs b/Dnn.CommunityForums/Services/Controllers/TagController.cs index 6963fbf4c..ce14286f4 100644 --- a/Dnn.CommunityForums/Services/Controllers/TagController.cs +++ b/Dnn.CommunityForums/Services/Controllers/TagController.cs @@ -44,7 +44,7 @@ public class TagController : ControllerBase #pragma warning restore CS1570 [HttpGet] [DnnAuthorize] - [ForumsAuthorize(SecureActions.Tag)] + [ForumsAuthorize(SecureActions.Edit)] public HttpResponseMessage Matches(int forumId, string matchString) { return this.Match($"%{CleanAndChopString(matchString, 20)}%"); @@ -61,7 +61,7 @@ public HttpResponseMessage Matches(int forumId, string matchString) #pragma warning restore CS1570 [HttpGet] [DnnAuthorize] - [ForumsAuthorize(SecureActions.Tag)] + [ForumsAuthorize(SecureActions.Edit)] public HttpResponseMessage BeginsWith(int forumId, string matchString) { return this.Match($"{CleanAndChopString(matchString, 20)}%"); diff --git a/Dnn.CommunityForums/Services/Controllers/TopicController.cs b/Dnn.CommunityForums/Services/Controllers/TopicController.cs index 381f78545..5ddb115b2 100644 --- a/Dnn.CommunityForums/Services/Controllers/TopicController.cs +++ b/Dnn.CommunityForums/Services/Controllers/TopicController.cs @@ -88,6 +88,7 @@ public HttpResponseMessage Subscribe(TopicDto1 dto) #pragma warning restore CS1570 [HttpGet] [DnnAuthorize] + [ForumsAuthorize(SecureActions.View)] public HttpResponseMessage SubscriberCount(int forumId, int topicId) { try @@ -118,6 +119,7 @@ public HttpResponseMessage SubscriberCount(int forumId, int topicId) #pragma warning restore CS1570 [HttpGet] [DnnAuthorize] + [ForumsAuthorize(SecureActions.View)] public HttpResponseMessage SubscriberCountString(int forumId, int topicId) { try @@ -177,6 +179,7 @@ public HttpResponseMessage Pin(TopicDto1 dto) contentId: ti.ContentId, authorId: ti.Content.AuthorId, userId: this.UserInfo.UserID, + badgeId: DotNetNuke.Common.Utilities.Null.NullInteger, requestUrl: this.Request.RequestUri.ToString()); } diff --git a/Dnn.CommunityForums/Services/Controllers/UserBadgeController.cs b/Dnn.CommunityForums/Services/Controllers/UserBadgeController.cs new file mode 100644 index 000000000..65d2444ce --- /dev/null +++ b/Dnn.CommunityForums/Services/Controllers/UserBadgeController.cs @@ -0,0 +1,102 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.Services.Controllers +{ + using System; + using System.Linq; + using System.Net; + using System.Net.Http; + using System.Reflection; + using System.Web.Http; + + using DotNetNuke.Modules.ActiveForums.Services.ProcessQueue; + using DotNetNuke.UI.UserControls; + using DotNetNuke.Web.Api; + + /// + /// + /// + public class UserBadgeController : ControllerBase + { + public struct UserBadgeDto + { + public int BadgeId { get; set; } + + public int UserId { get; set; } + + public int UserBadgeId { get; set; } + + public bool Assign { get; set; } + } + + /// + /// Assign/unassigns a user badge to a user. + /// + /// + /// + /// https://dnndev.me/API/ActiveForums/UserBadge/Assign + [HttpPost] + [DnnAuthorize(StaticRoles = "Administrators")] + public HttpResponseMessage Assign(UserBadgeDto dto) + { + try + { + if (dto.BadgeId > 0 && dto.UserId > 0) + { + DotNetNuke.Modules.ActiveForums.Entities.UserBadgeInfo userBadge = null; + var userBadgeController = new DotNetNuke.Modules.ActiveForums.Controllers.UserBadgeController(this.PortalSettings.PortalId, this.ForumModuleId); + if (dto.UserBadgeId > 0) + { + userBadge = userBadgeController.GetById(dto.UserBadgeId); + } + else + { + userBadge = userBadgeController.GetLatestForUserAndBadge(portalId: this.PortalSettings.PortalId, userId: dto.UserId, badgeId: dto.BadgeId); + } + + if (userBadge == null && dto.Assign.Equals(true)) + { + DotNetNuke.Modules.ActiveForums.Controllers.UserBadgeController.AssignUserBadge(portalId: this.PortalSettings.PortalId, moduleId: this.ForumModuleId, userId: dto.UserId, badgeId: dto.BadgeId, requestUrl: this.Request.RequestUri.ToString()); + return this.Request.CreateResponse(HttpStatusCode.OK, true); + } + + if (dto.Assign.Equals(false)) + { + if (userBadge != null) + { + userBadgeController.UnassignUserBadge(portalId: userBadge.PortalId, userId: userBadge.UserId, badgeId: userBadge.BadgeId, dateAssigned: userBadge.DateAssigned); + } + + return this.Request.CreateResponse(HttpStatusCode.OK, false); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + } + catch (Exception ex) + { + DotNetNuke.Services.Exceptions.Exceptions.LogException(ex); + } + + return this.Request.CreateResponse(HttpStatusCode.BadRequest); + } + } +} diff --git a/Dnn.CommunityForums/Services/Controllers/UserController.cs b/Dnn.CommunityForums/Services/Controllers/UserController.cs index 248ab92ed..b011b28a4 100644 --- a/Dnn.CommunityForums/Services/Controllers/UserController.cs +++ b/Dnn.CommunityForums/Services/Controllers/UserController.cs @@ -31,6 +31,7 @@ namespace DotNetNuke.Modules.ActiveForums.Services.Controllers /// /// /// + /// public class UserController : ControllerBase { /// diff --git a/Dnn.CommunityForums/Services/ProcessQueue.cs b/Dnn.CommunityForums/Services/ProcessQueue.cs index d9a33e473..b99e698a9 100644 --- a/Dnn.CommunityForums/Services/ProcessQueue.cs +++ b/Dnn.CommunityForums/Services/ProcessQueue.cs @@ -84,6 +84,9 @@ private static int ProcessQueue() case ProcessType.UpdateForumTopicPointers: completed = DotNetNuke.Modules.ActiveForums.Controllers.ForumController.RecalculateTopicPointers(item.ForumId); break; + case ProcessType.BadgeAssigned: + completed = new DotNetNuke.Modules.ActiveForums.Controllers.UserBadgeController(item.PortalId, item.ModuleId).AssignUserBadgeAfterAction(item.PortalId, item.UserId, item.BadgeId, item.DateCreated, item.RequestUrl); + break; default: DotNetNuke.Services.Exceptions.Exceptions.LogException(new NotImplementedException("invalid ProcessType")); break; diff --git a/Dnn.CommunityForums/Services/ProcessType.cs b/Dnn.CommunityForums/Services/ProcessType.cs index d91cc2a7c..f5a97bfc3 100644 --- a/Dnn.CommunityForums/Services/ProcessType.cs +++ b/Dnn.CommunityForums/Services/ProcessType.cs @@ -30,5 +30,6 @@ public enum ProcessType UpdateForumTopicPointers = 6, PostLiked = 7, TopicPinned = 8, + BadgeAssigned = 9, } } diff --git a/Dnn.CommunityForums/Services/Tokens/ForumsModuleTokenReplacer.cs b/Dnn.CommunityForums/Services/Tokens/ForumsModuleTokenReplacer.cs index 31d3724cc..207b4d522 100644 --- a/Dnn.CommunityForums/Services/Tokens/ForumsModuleTokenReplacer.cs +++ b/Dnn.CommunityForums/Services/Tokens/ForumsModuleTokenReplacer.cs @@ -134,6 +134,7 @@ public string GetProperty(string propertyName, string format, System.Globalizati string.Empty; } + case "forumslink": case "toolbar-forums-onclick": return PropertyAccess.FormatString(Utilities.NavigateURL(this.TabId), format); case "toolbar-controlpanel-onclick": diff --git a/Dnn.CommunityForums/Services/Tokens/TokenReplacer.cs b/Dnn.CommunityForums/Services/Tokens/TokenReplacer.cs index 455891e9e..33337efa2 100644 --- a/Dnn.CommunityForums/Services/Tokens/TokenReplacer.cs +++ b/Dnn.CommunityForums/Services/Tokens/TokenReplacer.cs @@ -46,6 +46,7 @@ internal class TokenReplacer : BaseCustomTokenReplace private const string PropertySource_forumuser = "forumuser"; private const string PropertySource_like = "forumlike"; private const string PropertySource_user = "user"; + private const string PropertySource_badge = "badge"; private const string PropertySource_profile = "profile"; private const string PropertySource_membership = "membership"; private const string PropertySource_forumauthor = "forumauthor"; @@ -346,7 +347,32 @@ public TokenReplacer(PortalSettings portalSettings, int forumTabId, int forumMod this.CurrentAccessLevel = Scope.DefaultSettings; } + + public TokenReplacer(PortalSettings portalSettings, UserBadgeInfo userBadgeInfo, Uri requestUri, string rawUrl) + { + userBadgeInfo.ForumUser.RawUrl = rawUrl; + userBadgeInfo.ForumUser.RequestUri = requestUri; + this.PropertySource[PropertySource_resx] = new ResourceStringTokenReplacer(); + this.PropertySource[PropertySource_forumuser] = userBadgeInfo.ForumUser; + this.PropertySource[PropertySource_badge] = userBadgeInfo; + this.PropertySource[PropertySource_user] = userBadgeInfo.ForumUser.UserInfo; + this.PropertySource[PropertySource_profile] = new ProfilePropertyAccess(userBadgeInfo.ForumUser.UserInfo); + this.PropertySource[PropertySource_membership] = new MembershipPropertyAccess(userBadgeInfo.ForumUser.UserInfo); + this.PropertySource[PropertySource_tab] = portalSettings.ActiveTab; + this.PropertySource[PropertySource_module] = userBadgeInfo.ForumUser.ModuleInfo; + this.PropertySource[PropertySource_portal] = portalSettings; + try + { + this.PropertySource[PropertySource_host] = new HostPropertyAccess(); + } + + /* this allows unit tests to complete */ + catch (System.ArgumentNullException) + { + } + this.CurrentAccessLevel = Scope.DefaultSettings; + } public new string ReplaceTokens(string source) { return base.ReplaceTokens(source); @@ -362,7 +388,7 @@ internal static StringBuilder ReplaceForumControlTokens(StringBuilder template, return template; } - internal static StringBuilder ReplaceForumTokens(StringBuilder template, ForumInfo forum, PortalSettings portalSettings, SettingsInfo mainSettings, INavigationManager navigationManager, ForumUserInfo forumUser, int tabId, CurrentUserTypes currentUserType, Uri requestUri, string rawUrl) + internal static StringBuilder ReplaceForumTokens(StringBuilder template, ForumInfo forum, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, INavigationManager navigationManager, ForumUserInfo forumUser, int tabId, CurrentUserTypes currentUserType, Uri requestUri, string rawUrl) { /* if no last post or subject missing, remove associated last topic tokens */ if (forum.LastPostID == 0 || string.IsNullOrEmpty(System.Net.WebUtility.HtmlDecode(forum.LastPostSubject))) @@ -379,7 +405,7 @@ internal static StringBuilder ReplaceForumTokens(StringBuilder template, ForumIn if (template.ToString().Contains("[AF:CONTROL:ADDFAVORITE]")) { var forumUrl = new ControlUtils().BuildUrl(forum.PortalId, tabId, forum.ModuleId, forum.ForumGroup.PrefixURL, forum.PrefixURL, forum.ForumGroupId, forum.ForumID, -1, -1, string.Empty, 1, -1, forum.SocialGroupId); - template.Replace("[AF:CONTROL:ADDFAVORITE]", "\"[RESX:AddToFavorites]\""); + template.Replace("[AF:CONTROL:ADDFAVORITE]", "\"[RESX:AddToFavorites]\""); } template = ResourceStringTokenReplacer.ReplaceResourceTokens(template); @@ -389,7 +415,7 @@ internal static StringBuilder ReplaceForumTokens(StringBuilder template, ForumIn return template; } - internal static StringBuilder ReplaceForumGroupTokens(StringBuilder template, ForumGroupInfo forumGroup, PortalSettings portalSettings, SettingsInfo mainSettings, INavigationManager navigationManager, ForumUserInfo forumUser, int tabId, CurrentUserTypes currentUserType, Uri requestUri, string rawUrl) + internal static StringBuilder ReplaceForumGroupTokens(StringBuilder template, ForumGroupInfo forumGroup, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, INavigationManager navigationManager, ForumUserInfo forumUser, int tabId, CurrentUserTypes currentUserType, Uri requestUri, string rawUrl) { template = ResourceStringTokenReplacer.ReplaceResourceTokens(template); var tokenReplacer = new TokenReplacer(portalSettings, forumUser, forumGroup, requestUri, rawUrl) { CurrentAccessLevel = Scope.DefaultSettings, AccessingUser = forumUser.UserInfo, }; @@ -399,7 +425,7 @@ internal static StringBuilder ReplaceForumGroupTokens(StringBuilder template, Fo return template; } - internal static StringBuilder ReplaceAuthorTokens(StringBuilder template, PortalSettings portalSettings, SettingsInfo mainSettings, AuthorInfo author, ForumUserInfo accessingUser, Uri requestUri, string rawUrl, int forumModuleId) + internal static StringBuilder ReplaceAuthorTokens(StringBuilder template, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, AuthorInfo author, ForumUserInfo accessingUser, Uri requestUri, string rawUrl, int forumModuleId) { template = ResourceStringTokenReplacer.ReplaceResourceTokens(template); var tokenReplacer = new TokenReplacer(portalSettings, author, accessingUser, requestUri, rawUrl) { CurrentAccessLevel = Scope.DefaultSettings, AccessingUser = accessingUser?.UserInfo, }; @@ -409,7 +435,7 @@ internal static StringBuilder ReplaceAuthorTokens(StringBuilder template, Portal return template; } - internal static StringBuilder ReplaceUserTokens(StringBuilder template, PortalSettings portalSettings, SettingsInfo mainSettings, ForumUserInfo forumUser, ForumUserInfo accessingUser, Uri requestUri, string rawUrl, int forumModuleId) + internal static StringBuilder ReplaceUserTokens(StringBuilder template, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, ForumUserInfo forumUser, ForumUserInfo accessingUser, Uri requestUri, string rawUrl, int forumModuleId) { var language = accessingUser?.UserInfo?.Profile?.PreferredLocale ?? portalSettings?.DefaultLanguage; @@ -423,9 +449,9 @@ internal static StringBuilder ReplaceUserTokens(StringBuilder template, PortalSe return template; } - internal static StringBuilder ReplaceTopicTokens(StringBuilder template, TopicInfo topic, PortalSettings portalSettings, SettingsInfo mainSettings, INavigationManager navigationManager, ForumUserInfo forumUser, Uri requestUri, string rawUrl) + internal static StringBuilder ReplaceTopicTokens(StringBuilder template, TopicInfo topic, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, INavigationManager navigationManager, ForumUserInfo forumUser, Uri requestUri, string rawUrl) { - topic.Content.Body = ReplaceBody(topic.Content.Body, mainSettings, requestUri); + topic.Content.Body = ReplaceBody(topic.Content.Body, moduleSettings, requestUri); template = ResourceStringTokenReplacer.ReplaceResourceTokens(template); var tokenReplacer = new TokenReplacer(portalSettings, forumUser, topic, requestUri, rawUrl) { AccessingUser = forumUser.UserInfo, }; @@ -435,7 +461,7 @@ internal static StringBuilder ReplaceTopicTokens(StringBuilder template, TopicIn return template; } - private static string ReplaceBody(string body, SettingsInfo mainSettings, Uri uri) + private static string ReplaceBody(string body, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, Uri uri) { if (!string.IsNullOrEmpty(body)) { @@ -453,7 +479,7 @@ private static string ReplaceBody(string body, SettingsInfo mainSettings, Uri ur } body = Utilities.StripExecCode(body); - if (mainSettings.AutoLinkEnabled) + if (moduleSettings.AutoLinkEnabled) { body = Utilities.AutoLinks(body, uri.Host); } @@ -472,7 +498,7 @@ private static string ReplaceBody(string body, SettingsInfo mainSettings, Uri ur return body; } - internal static StringBuilder ReplacePostTokens(StringBuilder template, IPostInfo post, PortalSettings portalSettings, SettingsInfo mainSettings, INavigationManager navigationManager, ForumUserInfo forumUser, Uri requestUri, string rawUrl) + internal static StringBuilder ReplacePostTokens(StringBuilder template, IPostInfo post, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, INavigationManager navigationManager, ForumUserInfo forumUser, Uri requestUri, string rawUrl) { /* if likes not allowed for forum, remove like-related tokens */ if (!post.Forum.FeatureSettings.AllowLikes) @@ -490,7 +516,7 @@ internal static StringBuilder ReplacePostTokens(StringBuilder template, IPostInf template.Replace("[POSTINFO]", sPostInfo); } - post.Content.Body = ReplaceBody(post.Content.Body, mainSettings, requestUri); + post.Content.Body = ReplaceBody(post.Content.Body, moduleSettings, requestUri); template = ResourceStringTokenReplacer.ReplaceResourceTokens(template); var tokenReplacer = new TokenReplacer(portalSettings, forumUser, post, requestUri, rawUrl) { AccessingUser = forumUser.UserInfo, }; @@ -500,7 +526,7 @@ internal static StringBuilder ReplacePostTokens(StringBuilder template, IPostInf return template; } - internal static StringBuilder ReplaceLikeTokens(StringBuilder template, LikeInfo like, PortalSettings portalSettings, SettingsInfo mainSettings, INavigationManager navigationManager, ForumUserInfo forumUser, Uri requestUri, string rawUrl) + internal static StringBuilder ReplaceLikeTokens(StringBuilder template, LikeInfo like, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, INavigationManager navigationManager, ForumUserInfo forumUser, Uri requestUri, string rawUrl) { /* if likes not allowed for forum, remove like-related tokens */ if (!like.Forum.FeatureSettings.AllowLikes) @@ -516,6 +542,16 @@ internal static StringBuilder ReplaceLikeTokens(StringBuilder template, LikeInfo return template; } + internal static StringBuilder ReplaceBadgeTokens(StringBuilder template, UserBadgeInfo userBadge, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, INavigationManager navigationManager, ForumUserInfo forumUser, Uri requestUri, string rawUrl) + { + template = ResourceStringTokenReplacer.ReplaceResourceTokens(template); + var tokenReplacer = new TokenReplacer(portalSettings, userBadge, requestUri, rawUrl) { AccessingUser = forumUser.UserInfo, }; + template = new StringBuilder(tokenReplacer.ReplaceEmbeddedTokens(template.ToString())); + template = new StringBuilder(tokenReplacer.ReplaceTokens(template.ToString())); + + return template; + } + private static StringBuilder ExtractAndReplaceDateTokenWithOptionalFormatParameter(StringBuilder template, string tokenPrefix, DateTime? datetime, PortalSettings portalSettings, ForumUserInfo forumUser) { if (datetime == null || datetime == DateTime.MinValue || datetime == SqlDateTime.MinValue.Value || datetime == Utilities.NullDate()) @@ -781,7 +817,7 @@ internal static StringBuilder MapLegacyForumGroupTokenSynonyms(StringBuilder tem return template; } - internal static StringBuilder MapLegacyUserTokenSynonyms(StringBuilder template, PortalSettings portalSettings, SettingsInfo mainSettings, string language) + internal static StringBuilder MapLegacyUserTokenSynonyms(StringBuilder template, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, string language) { template = ReplaceTokenSynonym(template, "[SENDERUSERNAME]", "[USER:USERNAME]"); template = ReplaceTokenSynonym(template, "[SENDERFIRSTNAME]", "[USER:FIRSTNAME]"); @@ -851,12 +887,12 @@ internal static StringBuilder MapLegacyUserTokenSynonyms(StringBuilder template, template = ReplaceLegacyTokenWithFormatString(template, portalSettings, language, "[AF:BUTTON:EDITUSER]", "[FORUMUSER:EDITLINK", "[EDITUSERLINK]"); - if (mainSettings.PMType == PMTypes.Disabled) + if (moduleSettings.PMType == PMTypes.Disabled) { template.Replace("[AF:PROFILE:PMLINK]", string.Empty); template.Replace("[AF:PROFILE:PMURL]", string.Empty); } - else if (mainSettings.PMType == PMTypes.Core) + else if (moduleSettings.PMType == PMTypes.Core) { template = ReplaceLegacyTokenWithFormatString(template, portalSettings, language, "[AF:PROFILE:PMLINK]", "[FORUMUSER:PMLINK", "[USERPMLINK]"); template.Replace("[AF:PROFILE:PMURL]", string.Empty); @@ -865,7 +901,7 @@ internal static StringBuilder MapLegacyUserTokenSynonyms(StringBuilder template, return template; } - internal static StringBuilder MapLegacyAuthorTokenSynonyms(StringBuilder template, PortalSettings portalSettings, SettingsInfo mainSettings, string language) + internal static StringBuilder MapLegacyAuthorTokenSynonyms(StringBuilder template, PortalSettings portalSettings, DotNetNuke.Modules.ActiveForums.ModuleSettings moduleSettings, string language) { template = ReplaceTokenSynonym(template, "[SENDERUSERNAME]", "[FORUMAUTHOR:USERNAME]"); template = ReplaceTokenSynonym(template, "[SENDERFIRSTNAME]", "[FORUMAUTHOR:FIRSTNAME]"); @@ -935,12 +971,12 @@ internal static StringBuilder MapLegacyAuthorTokenSynonyms(StringBuilder templat template = ReplaceLegacyTokenWithFormatString(template, portalSettings, language, "[AF:BUTTON:EDITUSER]", "[FORUMAUTHOR:EDITLINK", "[EDITAUTHORLINK]"); - if (mainSettings.PMType == PMTypes.Disabled) + if (moduleSettings.PMType == PMTypes.Disabled) { template.Replace("[AF:PROFILE:PMLINK]", string.Empty); template.Replace("[AF:PROFILE:PMURL]", string.Empty); } - else if (mainSettings.PMType == PMTypes.Core) + else if (moduleSettings.PMType == PMTypes.Core) { template = ReplaceLegacyTokenWithFormatString(template, portalSettings, language, "[AF:PROFILE:PMLINK]", "[FORUMAUTHOR:PMLINK", "[AUTHORPMLINK]"); template.Replace("[AF:PROFILE:PMURL]", string.Empty); @@ -1264,14 +1300,19 @@ internal static string GetTokenFormatString(string key, PortalSettings portalSet internal string ReplaceEmbeddedTokens(string source) { + return this.ReplaceEmbeddedTokens(new StringBuilder(source)).ToString(); + } + + internal StringBuilder ReplaceEmbeddedTokens(StringBuilder source) + { + var sb = new StringBuilder(source.ToString()); const string Pattern = @"(?(?:(?\[\])|\[(?:(?[^{}\]\[:]+):(?[^\]\[\|]+))(?:\|(?:(?[^\]\[]+)\|(?[^\]\[]+))|\|(?:(?[^\|\]\[]+)))?\])|(?\[[^\]\[]+\])|(?[^\]\[]+){0}\1)"; try { - var matches = RegexUtils.GetCachedRegex(Pattern, RegexOptions.Compiled & RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace, 5).Matches(source); + var matches = RegexUtils.GetCachedRegex(Pattern, RegexOptions.Compiled & RegexOptions.IgnoreCase & RegexOptions.IgnorePatternWhitespace, 5).Matches(sb.ToString()); if (matches.Count > 0) { - var sb = new StringBuilder(source); foreach (Match match in matches) { if (!string.IsNullOrEmpty(match.Groups["token"]?.Value) && match.Groups["object"] != null && this.PropertySource.ContainsKey(match.Groups["object"].Value.ToLowerInvariant())) @@ -1280,13 +1321,13 @@ internal string ReplaceEmbeddedTokens(string source) } } - return sb.ToString(); + return sb; } } catch (RegexMatchTimeoutException ex) { Exceptions.LogException(ex); - return source; + return sb; } catch (Exception ex) { @@ -1294,7 +1335,7 @@ internal string ReplaceEmbeddedTokens(string source) throw; } - return source; + return sb; } } } diff --git a/Dnn.CommunityForums/ViewModels/Forum.cs b/Dnn.CommunityForums/ViewModels/Forum.cs index ce5379860..435f727d6 100644 --- a/Dnn.CommunityForums/ViewModels/Forum.cs +++ b/Dnn.CommunityForums/ViewModels/Forum.cs @@ -29,83 +29,89 @@ public class Forum public Forum(DotNetNuke.Modules.ActiveForums.Entities.ForumInfo forum) { this.forum = forum; - this.forum.Security = new DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo(); + if (this.forum.Security == null) + { + this.forum.Security = new DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo(); + } } - public int ForumId { get => this.forum.ForumID; set => this.forum.ForumID = value; } + public int Id { get => this.forum.ForumID; set => this.forum.ForumID = value; } - public string ForumName { get => this.forum.ForumName; set => this.forum.ForumName = value; } + public string Name { get => this.forum.ForumName; set => this.forum.ForumName = value; } - public string ForumDescription { get => this.forum.ForumDesc; set => this.forum.ForumDesc = value; } + public string Description { get => this.forum.ForumDesc; set => this.forum.ForumDesc = value; } public int PortalId { get => this.forum.PortalId; set => this.forum.PortalId = value; } public int ModuleId { get => this.forum.ModuleId; set => this.forum.ModuleId = value; } - public int ForumGroupId { get => this.forum.ForumGroupId; set => this.forum.ForumGroupId = value; } + public int GroupId { get => this.forum.ForumGroupId; set => this.forum.ForumGroupId = value; } - public string ForumGroupName => this.forum.GroupName; + public string GroupName => this.forum.GroupName; - public int ForumPermissionsId { get => this.forum.PermissionsId; set => this.forum.PermissionsId = value; } + public int PermissionsId { get => this.forum.PermissionsId; set => this.forum.PermissionsId = value; } - public int ForumLastTopicId => this.forum.LastTopicId; + public int LastTopicId => this.forum.LastTopicId; - public int ForumLastReplyId => this.forum.LastReplyId; + public int LastReplyId => this.forum.LastReplyId; - public int ForumLastPostID => this.forum.LastPostID; + public int LastPostID => this.forum.LastPostID; - public int ForumTotalTopics => this.forum.TotalTopics; + public int TotalTopics => this.forum.TotalTopics; public int TotalReplies => this.forum.TotalReplies; - public string ForumSettingsKey { get => this.forum.ForumSettingsKey; set => this.forum.ForumSettingsKey = value; } + public string SettingsKey { get => this.forum.ForumSettingsKey; set => this.forum.ForumSettingsKey = value; } - public bool ForumActive { get => this.forum.Active; set => this.forum.Active = value; } + public bool Active { get => this.forum.Active; set => this.forum.Active = value; } - public bool ForumHidden { get => this.forum.Hidden; set => this.forum.Hidden = value; } + public bool Hidden { get => this.forum.Hidden; set => this.forum.Hidden = value; } - public int ForumSubscriberCount => this.forum.SubscriberCount; + public int SubscriberCount => this.forum.SubscriberCount; - public string ForumURL => this.forum.ForumURL; + public string URL => this.forum.ForumURL; - public string ForumGroupPrefixURL => this.forum.GroupPrefixURL; + public string GroupPrefixURL => this.forum.GroupPrefixURL; - public DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo ForumSecurity => this.forum.Security; + public DotNetNuke.Modules.ActiveForums.ViewModels.Permissions Security => new DotNetNuke.Modules.ActiveForums.ViewModels.Permissions(this.forum.Security); - public string ForumSecurityCreate => this.forum.Security.Create; - - public string ForumSecurityEdit => this.forum.Security.Edit; - - public string ForumSecurityDelete => this.forum.Security.Delete; - - public string ForumSecurityView => this.forum.Security.View; - - public string ForumSecurityAnnounce => this.forum.Security.Announce; - - public string ForumSecurityModerate => this.forum.Security.Moderate; - - public string ForumSecurityMove => this.forum.Security.Move; - - public string ForumSecuritySplit => this.forum.Security.Split; - - public string ForumSecurityTrust => this.forum.Security.Trust; - - public string ForumSecurityAttach => this.forum.Security.Attach; - - public string ForumSecurityAuthRolesCreate => this.forum.Security.Ban; - - public string ForumSecurityTag => this.forum.Security.Tag; - - public string ForumSecuritySubscribe => this.forum.Security.Subscribe; - - public string ForumPrefixURL => this.forum.PrefixURL; + public string PrefixURL => this.forum.PrefixURL; public int ParentForumId => this.forum.ParentForumId; public string ParentForumName => this.forum.ParentForumName; - public bool ForumHasProperties => this.forum.HasProperties; + public bool HasProperties => this.forum.HasProperties; + + public IEnumerable Properties => this.forum.Properties; - public IEnumerable ForumProperties => this.forum.Properties; + /// + /// Maps the current Forum view model to a ForumInfo entity. + /// + /// A new instance of ForumInfo with properties set from this view model. + public DotNetNuke.Modules.ActiveForums.Entities.ForumInfo ToForumInfo() + { + var forumInfo = new DotNetNuke.Modules.ActiveForums.Entities.ForumInfo(); + forumInfo.ForumID = this.Id; + forumInfo.ForumName = this.Name; + forumInfo.ForumDesc = this.Description; + forumInfo.PortalId = this.PortalId; + forumInfo.ModuleId = this.ModuleId; + forumInfo.ForumGroupId = this.GroupId; + forumInfo.PermissionsId = this.PermissionsId; + forumInfo.LastTopicId = this.LastTopicId; + forumInfo.LastReplyId = this.LastReplyId; + forumInfo.TotalTopics = this.TotalTopics; + forumInfo.TotalReplies = this.TotalReplies; + forumInfo.ForumSettingsKey = this.SettingsKey; + forumInfo.Active = this.Active; + forumInfo.Hidden = this.Hidden; + forumInfo.PrefixURL = this.PrefixURL; + forumInfo.ParentForumId = this.ParentForumId; + forumInfo.HasProperties = this.HasProperties; + forumInfo.Properties = this.Properties != null ? new List(this.Properties) : null; + + return forumInfo; + } } } diff --git a/Dnn.CommunityForums/ViewModels/Permissions.cs b/Dnn.CommunityForums/ViewModels/Permissions.cs new file mode 100644 index 000000000..34d62469c --- /dev/null +++ b/Dnn.CommunityForums/ViewModels/Permissions.cs @@ -0,0 +1,153 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums.ViewModels +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web.Security; + + public class Permissions + { + private readonly DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo permissions; + + public Permissions() + { + this.permissions = new DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo(); + } + + public Permissions(DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo permissions) + { + this.permissions = permissions; + } + + public int PermissionsId => this.permissions.PermissionsId; + + public HashSet ViewRoleIds => this.permissions.ViewRoleIds; + + public HashSet ReadRoleIds => this.permissions.ReadRoleIds; + + public HashSet CreateRoleIds => this.permissions.CreateRoleIds; + + public HashSet ReplyRoleIds => this.permissions.ReplyRoleIds; + + public HashSet EditRoleIds => this.permissions.EditRoleIds; + + public HashSet DeleteRoleIds => this.permissions.DeleteRoleIds; + + public HashSet LockRoleIds => this.permissions.LockRoleIds; + + public HashSet PinRoleIds => this.permissions.PinRoleIds; + + public HashSet AttachRoleIds => this.permissions.AttachRoleIds; + + public HashSet PollRoleIds => this.permissions.PollRoleIds; + + public HashSet BlockRoleIds => this.permissions.BlockRoleIds; + + public HashSet TrustRoleIds => this.permissions.TrustRoleIds; + + public HashSet SubscribeRoleIds => this.permissions.SubscribeRoleIds; + + public HashSet AnnounceRoleIds => this.permissions.AnnounceRoleIds; + + public HashSet TagRoleIds => this.permissions.TagRoleIds; + + public HashSet CategorizeRoleIds => this.permissions.CategorizeRoleIds; + + public HashSet PrioritizeRoleIds => this.permissions.PrioritizeRoleIds; + + public HashSet ModerateRoleIds => this.permissions.ModerateRoleIds; + + public HashSet MoveRoleIds => this.permissions.MoveRoleIds; + + public HashSet SplitRoleIds => this.permissions.SplitRoleIds; + + public HashSet BanRoleIds => this.permissions.BanRoleIds; + + public bool EqualPermissions(Permissions other) + { + return !(other is null) && + this.EqualPermissionMembers(this.AnnounceRoleIds, other.AnnounceRoleIds) && + this.EqualPermissionMembers(this.AttachRoleIds, other.AttachRoleIds) && + this.EqualPermissionMembers(this.BanRoleIds, other.BanRoleIds) && + // EqualPermissionMembers(this.BlockRoleIds, other.BlockRoleIds) && + this.EqualPermissionMembers(this.CategorizeRoleIds, other.CategorizeRoleIds) && + this.EqualPermissionMembers(this.CreateRoleIds, other.CreateRoleIds) && + this.EqualPermissionMembers(this.DeleteRoleIds, other.DeleteRoleIds) && + this.EqualPermissionMembers(this.EditRoleIds, other.EditRoleIds) && + this.EqualPermissionMembers(this.LockRoleIds, other.LockRoleIds) && + this.EqualPermissionMembers(this.ModerateRoleIds, other.ModerateRoleIds) && + this.EqualPermissionMembers(this.ModerateRoleIds, other.ModerateRoleIds) && + this.EqualPermissionMembers(this.MoveRoleIds, other.MoveRoleIds) && + this.EqualPermissionMembers(this.PinRoleIds, other.PinRoleIds) && + this.EqualPermissionMembers(this.PollRoleIds, other.PollRoleIds) && + this.EqualPermissionMembers(this.PrioritizeRoleIds, other.PrioritizeRoleIds) && + this.EqualPermissionMembers(this.ReadRoleIds, other.ReadRoleIds) && + this.EqualPermissionMembers(this.ReplyRoleIds, other.ReplyRoleIds) && + this.EqualPermissionMembers(this.SplitRoleIds, other.SplitRoleIds) && + this.EqualPermissionMembers(this.SubscribeRoleIds, other.SubscribeRoleIds) && + this.EqualPermissionMembers(this.TagRoleIds, other.TagRoleIds) && + this.EqualPermissionMembers(this.TrustRoleIds, other.TrustRoleIds) && + this.EqualPermissionMembers(this.ViewRoleIds, other.ViewRoleIds); + } + + public bool EqualPermissionMembers(HashSet thisPermissions, HashSet otherPermissions) + { + return thisPermissions.SetEquals(otherPermissions); + } + + /// + /// Maps this view model to a entity. + /// + /// A new entity with values from this view model. + public DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo ToPermissionInfo() + { + var entity = new DotNetNuke.Modules.ActiveForums.Entities.PermissionInfo + { + PermissionsId = this.PermissionsId, + View = string.Join(";", this.ViewRoleIds.Distinct().OrderBy(r => r)), + Read = string.Join(";", this.ReadRoleIds.Distinct().OrderBy(r => r)), + Create = string.Join(";", this.CreateRoleIds.Distinct().OrderBy(r => r)), + Reply = string.Join(";", this.ReplyRoleIds.Distinct().OrderBy(r => r)), + Edit = string.Join(";", this.EditRoleIds.Distinct().OrderBy(r => r)), + Delete = string.Join(";", this.DeleteRoleIds.Distinct().OrderBy(r => r)), + Lock = string.Join(";", this.LockRoleIds.Distinct().OrderBy(r => r)), + Pin = string.Join(";", this.PinRoleIds.Distinct().OrderBy(r => r)), + Attach = string.Join(";", this.AttachRoleIds.Distinct().OrderBy(r => r)), + Poll = string.Join(";", this.PollRoleIds.Distinct().OrderBy(r => r)), + Block = string.Join(";", this.BlockRoleIds.Distinct().OrderBy(r => r)), + Trust = string.Join(";", this.TrustRoleIds.Distinct().OrderBy(r => r)), + Subscribe = string.Join(";", this.SubscribeRoleIds.Distinct().OrderBy(r => r)), + Announce = string.Join(";", this.AnnounceRoleIds.Distinct().OrderBy(r => r)), + Tag = string.Join(";", this.TagRoleIds.Distinct().OrderBy(r => r)), + Categorize = string.Join(";", this.CategorizeRoleIds.Distinct().OrderBy(r => r)), + Prioritize = string.Join(";", this.PrioritizeRoleIds.Distinct().OrderBy(r => r)), + Moderate = string.Join(";", this.ModerateRoleIds.Distinct().OrderBy(r => r)), + Move = string.Join(";", this.MoveRoleIds.Distinct().OrderBy(r => r)), + Split = string.Join(";", this.SplitRoleIds.Distinct().OrderBy(r => r)), + Ban = string.Join(";", this.BanRoleIds.Distinct().OrderBy(r => r)), + }; + + return entity; + } + } +} diff --git a/Dnn.CommunityForums/class/ActiveAdminBase.cs b/Dnn.CommunityForums/class/ActiveAdminBase.cs index ed67882fc..34f78a734 100644 --- a/Dnn.CommunityForums/class/ActiveAdminBase.cs +++ b/Dnn.CommunityForums/class/ActiveAdminBase.cs @@ -73,11 +73,11 @@ protected string GetSharedResource(string key) return Utilities.GetSharedResource(key, true); } - public SettingsInfo MainSettings + public ModuleSettings MainSettings { get { - return new SettingsInfo { ModuleId = this.ModuleId, MainSettings = new ModuleController().GetModule(moduleID: this.ModuleId).ModuleSettings }; + return new ModuleSettings { ModuleId = this.ModuleId, MainSettings = new ModuleController().GetModule(moduleID: this.ModuleId).ModuleSettings }; } } diff --git a/Dnn.CommunityForums/class/Cache.cs b/Dnn.CommunityForums/class/Cache.cs index 86533faba..8d8370cee 100644 --- a/Dnn.CommunityForums/class/Cache.cs +++ b/Dnn.CommunityForums/class/Cache.cs @@ -366,42 +366,16 @@ internal static Hashtable GetSettings(int moduleId, string settingsKey, string c var ht = new Hashtable(); if (useCache) { - object obj = SettingsCacheRetrieve(moduleId, cacheKey); - if (obj == null) + ht = (Hashtable)SettingsCacheRetrieve(moduleId, cacheKey); + if (ht == null) { - IDataReader dr = DataProvider.Instance().Settings_List(moduleId, settingsKey); - while (dr.Read()) - { - if (!ht.ContainsKey(dr["SettingName"].ToString())) - { - ht.Add(dr["SettingName"].ToString(), string.Empty); - } - - ht[dr["SettingName"].ToString()] = dr["SettingValue"].ToString(); - } - - dr.Close(); + ht = new DotNetNuke.Modules.ActiveForums.Controllers.SettingsController().GetSettingsHashTableForModuleIdSettingsKey(moduleId, settingsKey); SettingsCacheStore(moduleId, cacheKey, ht); } - else - { - ht = (Hashtable)obj; - } } else { - IDataReader dr = DataProvider.Instance().Settings_List(moduleId, settingsKey); - while (dr.Read()) - { - if (!ht.ContainsKey(dr["SettingName"].ToString())) - { - ht.Add(dr["SettingName"].ToString(), string.Empty); - } - - ht[dr["SettingName"].ToString()] = dr["SettingValue"].ToString(); - } - - dr.Close(); + ht = new DotNetNuke.Modules.ActiveForums.Controllers.SettingsController().GetSettingsHashTableForModuleIdSettingsKey(moduleId, settingsKey); } return ht; diff --git a/Dnn.CommunityForums/class/DataProvider.cs b/Dnn.CommunityForums/class/DataProvider.cs index 6917411e1..740c86c02 100644 --- a/Dnn.CommunityForums/class/DataProvider.cs +++ b/Dnn.CommunityForums/class/DataProvider.cs @@ -45,6 +45,10 @@ private static void CreateProvider() return objProvider; } + #region Badges + public abstract IDataReader Badges_List(int moduleId); + #endregion + #region Filters public abstract int Filters_Save(int portalId, int moduleId, int filterId, string find, string replace, string filterType); @@ -210,14 +214,19 @@ private static void CreateProvider() #endregion #region Settings + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public abstract IDataReader Settings_List(int moduleId, string groupKey); + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public abstract IDataReader Settings_ListAll(int moduleId); + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public abstract string Settings_Get(int moduleId, string groupKey, string settingName); + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public abstract void Settings_Delete(int moduleId, string groupKey, string settingName); + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No Longer Used.")] public abstract void Settings_Save(int moduleId, string groupKey, string settingName, string settingValue); #endregion diff --git a/Dnn.CommunityForums/class/ForumBase.cs b/Dnn.CommunityForums/class/ForumBase.cs index ca03831fa..13b598c61 100644 --- a/Dnn.CommunityForums/class/ForumBase.cs +++ b/Dnn.CommunityForums/class/ForumBase.cs @@ -56,7 +56,7 @@ public XmlDocument ForumData public ControlsConfig ControlConfig { get; set; } - public string ThemePath => this.Page.ResolveUrl(this.MainSettings.ThemeLocation); + public string ThemePath => this.Page.ResolveUrl(this.ModuleSettings.ThemeLocation); public string ForumIds { get; set; } = string.Empty; diff --git a/Dnn.CommunityForums/class/ForumsConfig.cs b/Dnn.CommunityForums/class/ForumsConfig.cs index 4fb5a0056..493e0bc6f 100644 --- a/Dnn.CommunityForums/class/ForumsConfig.cs +++ b/Dnn.CommunityForums/class/ForumsConfig.cs @@ -25,7 +25,9 @@ namespace DotNetNuke.Modules.ActiveForums using System; using System.Collections.Generic; using System.Data; + using System.IO; using System.Linq; + using System.Reflection; using System.Text; using System.Web.UI.WebControls; @@ -69,6 +71,11 @@ public bool ForumsInit(int portalId, int moduleId) // Create "Pin notification" core messaging notification type new in 08.02.00 ForumsConfig.Install_PinNotificationType_080200(); + // Create "badge notification" core messaging notification type new in 09.02.00 + ForumsConfig.Install_BadgeNotificationType_090200(); + + // Create default badges new in 09.02.00 + new ForumsConfig().Install_DefaultBadges_090200(); return true; } catch (Exception ex) @@ -172,7 +179,7 @@ private void LoadDefaultForums(int portalId, int moduleId) Active = xNodeList[i].Attributes["active"].Value == "1", Hidden = xNodeList[i].Attributes["hidden"].Value == "1", SortOrder = i, - GroupSettingsKey = $"M:{moduleId}", + GroupSettingsKey = $"M{moduleId}", PermissionsId = SettingsBase.GetModuleSettings(moduleId).DefaultPermissionId, }; var gc = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController(); @@ -197,7 +204,7 @@ private void LoadDefaultForums(int portalId, int moduleId) Active = cNodes[c].Attributes["active"].Value == "1", Hidden = cNodes[c].Attributes["hidden"].Value == "1", SortOrder = c, - ForumSettingsKey = $"G:{groupId}", + ForumSettingsKey = $"G{groupId}", PermissionsId = SettingsBase.GetModuleSettings(moduleId).DefaultPermissionId, }; new DotNetNuke.Modules.ActiveForums.Controllers.ForumController().Forums_Save(portalId, fi, true, true, true); @@ -565,7 +572,7 @@ internal static void Upgrade_EmailNotificationSubjectTokens_080200() } templateInfo.Subject = DotNetNuke.Modules.ActiveForums.Services.Tokens.TokenReplacer.MapLegacyEmailNotificationTokenSynonyms(new StringBuilder(templateInfo.Subject), portalSettings, portalSettings.DefaultLanguage).ToString(); - Settings.SaveSetting(module.ModuleID, $"M:{module.ModuleID}", ForumSettingKeys.EmailNotificationSubjectTemplate, templateInfo.Subject); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(module.ModuleID, $"M{module.ModuleID}", ForumSettingKeys.EmailNotificationSubjectTemplate, templateInfo.Subject); DotNetNuke.Modules.ActiveForums.DataCache.ClearAllCache(module.ModuleID); } catch (Exception ex) @@ -662,49 +669,49 @@ internal static void Install_Upgrade_ForumDefaultSettingsAndSecurity(int portalI var permissions = new DotNetNuke.Modules.ActiveForums.Controllers.PermissionController().CreateDefaultPermissions(portalSettings, moduleId); DotNetNuke.Entities.Modules.ModuleController.Instance.UpdateModuleSetting(moduleId, SettingKeys.DefaultPermissionId, permissions.PermissionsId.ToString()); - string sKey = $"M:{moduleId}"; + string sKey = $"M{moduleId}"; DotNetNuke.Entities.Modules.ModuleController.Instance.UpdateModuleSetting(moduleId, SettingKeys.DefaultSettingsKey, sKey); - if (string.IsNullOrEmpty(SettingsBase.GetModuleSettings(moduleId).ForumFeatureSettings.EmailNotificationSubjectTemplate)) + if (string.IsNullOrEmpty(SettingsBase.GetModuleSettings(moduleId).DefaultFeatureSettings.EmailNotificationSubjectTemplate)) { - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.EmailNotificationSubjectTemplate, "[FORUMAUTHOR:DISPLAYNAME] [POSTEDORREPLIEDTO] [SUBSCRIBEDFORUMORTOPICSUBJECTFORUMNAME] on [PORTAL:PORTALNAME]"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.EmailNotificationSubjectTemplate, "[FORUMAUTHOR:DISPLAYNAME] [POSTEDORREPLIEDTO] [SUBSCRIBEDFORUMORTOPICSUBJECTFORUMNAME] on [PORTAL:PORTALNAME]"); } - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.EmailAddress, string.Empty); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.UseFilter, "true"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowPostIcon, "false"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowLikes, "true"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowEmoticons, "false"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowScript, "false"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.IndexContent, "true"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowRSS, "true"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowAttach, "true"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachCount, "3"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachMaxSize, "1000"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachTypeAllowed, "txt,tiff,pdf,xls,xlsx,doc,docx,ppt,pptx"); - - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachMaxHeight, "450"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachMaxWidth, "450"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachAllowBrowseSite, "true"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.MaxAttachHeight, "800"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.MaxAttachWidth, "800"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachInsertAllowed, "false"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.ConvertingToJpegAllowed, "false"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowHTML, "true"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorType, ((int)EditorTypes.HTMLEDITORPROVIDER).ToString()); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorMobile, ((int)EditorTypes.HTMLEDITORPROVIDER).ToString()); - - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorHeight, "350"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorWidth, "99%"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorToolbar, "bold,italic,underline,quote"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorStyle, "2"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.IsModerated, "false"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.DefaultTrustLevel, "0"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.AutoTrustLevel, "0"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.ModApproveNotify, "0"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.ModRejectNotify, "0"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.ModMoveNotify, "0"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.ModDeleteNotify, "0"); - Settings.SaveSetting(moduleId, sKey, ForumSettingKeys.ModAlertNotify, "0"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.EmailAddress, string.Empty); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.UseFilter, "true"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowPostIcon, "false"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowLikes, "true"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowEmoticons, "false"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowScript, "false"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.IndexContent, "true"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowRSS, "true"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowAttach, "true"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachCount, "3"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachMaxSize, "1000"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachTypeAllowed, "txt,tiff,pdf,xls,xlsx,doc,docx,ppt,pptx"); + + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachMaxHeight, "450"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachMaxWidth, "450"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachAllowBrowseSite, "true"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.MaxAttachHeight, "800"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.MaxAttachWidth, "800"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AttachInsertAllowed, "false"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.ConvertingToJpegAllowed, "false"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AllowHTML, "true"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorType, ((int)EditorTypes.HTMLEDITORPROVIDER).ToString()); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorMobile, ((int)EditorTypes.HTMLEDITORPROVIDER).ToString()); + + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorHeight, "350"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorWidth, "99%"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorToolbar, "bold,italic,underline,quote"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.EditorStyle, "2"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.IsModerated, "false"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.DefaultTrustLevel, "0"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.AutoTrustLevel, "0"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.ModApproveNotify, "0"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.ModRejectNotify, "0"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.ModMoveNotify, "0"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.ModDeleteNotify, "0"); + DotNetNuke.Modules.ActiveForums.Controllers.SettingsController.SaveSetting(moduleId, sKey, ForumSettingKeys.ModAlertNotify, "0"); DotNetNuke.Modules.ActiveForums.DataCache.ClearAllCache(moduleId); } @@ -766,7 +773,98 @@ internal static void Upgrade_PermissionSets_090000() perms.Trust = DotNetNuke.Modules.ActiveForums.Controllers.PermissionController.GetRoleIds(DotNetNuke.Modules.ActiveForums.Controllers.PermissionController.GetRoleIdsFromPermSet(string.IsNullOrEmpty(perms.Trust) ? string.Empty : perms.Trust.Replace(":", ";"))); perms.View = DotNetNuke.Modules.ActiveForums.Controllers.PermissionController.GetRoleIds(DotNetNuke.Modules.ActiveForums.Controllers.PermissionController.GetRoleIdsFromPermSet(string.IsNullOrEmpty(perms.View) ? string.Empty : perms.View.Replace(":", ";"))); new DotNetNuke.Modules.ActiveForums.Controllers.PermissionController().Update(perms); + } + } + + internal static void Install_BadgeNotificationType_090200() + { + string notificationTypeName = Globals.BadgeNotificationType; + string notificationTypeDescription = Globals.BadgeNotificationTypeDescription; + int deskModuleId = DesktopModuleController.GetDesktopModuleByFriendlyName(Globals.ModuleFriendlyName).DesktopModuleID; + + NotificationType type = new NotificationType { Name = notificationTypeName, Description = notificationTypeDescription, DesktopModuleId = deskModuleId }; + if (NotificationsController.Instance.GetNotificationType(notificationTypeName) == null) + { + NotificationsController.Instance.CreateNotificationType(type); + } + } + internal void Install_DefaultBadges_090200() + { + try + { + foreach (DotNetNuke.Abstractions.Portals.IPortalInfo portal in DotNetNuke.Entities.Portals.PortalController.Instance.GetPortals()) + { + foreach (ModuleInfo module in DotNetNuke.Entities.Modules.ModuleController.Instance.GetModules(portal.PortalId)) + { + if (module.DesktopModule.ModuleName.Trim().Equals(Globals.ModuleName, StringComparison.InvariantCultureIgnoreCase)) + { + if (new DotNetNuke.Modules.ActiveForums.Controllers.BadgeController().Get(module.ModuleID).Count().Equals(0)) + { + var defaultBadgesFolder = DotNetNuke.Services.FileSystem.FolderManager.Instance.GetFolder(portal.PortalId, Globals.DefaultBadgesFolderName) ?? DotNetNuke.Services.FileSystem.FolderManager.Instance.AddFolder(portal.PortalId, Globals.DefaultBadgesFolderName); + var xDoc = new System.Xml.XmlDocument(); + xDoc.Load(this.sPath); + if (xDoc != null) + { + System.Xml.XmlNode xRoot = xDoc.DocumentElement; + System.Xml.XmlNodeList xNodeList = xRoot.SelectNodes("//badges/badge"); + if (xNodeList.Count > 0) + { + int i; + for (i = 0; i < xNodeList.Count; i++) + { + var fileId = -1; + try + { + var imageFile = DotNetNuke.Modules.ActiveForums.Utilities.MapPath(xNodeList[i].Attributes["image"].Value); + if (System.IO.File.Exists(imageFile)) + { + var fileName = System.IO.Path.GetFileName(imageFile); + using (var fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read)) + { + fileId = DotNetNuke.Services.FileSystem.FileManager.Instance.AddFile(defaultBadgesFolder, fileName, fileStream, true).FileId; + } + } + } + catch (Exception ex) + { + DotNetNuke.Modules.ActiveForums.Exceptions.LogException(ex); + } + + try + { + var badge = new DotNetNuke.Modules.ActiveForums.Entities.BadgeInfo + { + Name = xNodeList[i].Attributes["name"].Value, + Description = xNodeList[i].Attributes["description"].Value, + BadgeMetric = (DotNetNuke.Modules.ActiveForums.Enums.BadgeMetric)Utilities.SafeConvertInt(xNodeList[i].Attributes["badgemetric"].Value), + ModuleId = module.ModuleID, + OneTimeAward = Utilities.SafeConvertBool(xNodeList[i].Attributes["onetimeaward"].Value, true), + SortOrder = Utilities.SafeConvertInt(xNodeList[i].Attributes["sortorder"].Value), + Threshold = Utilities.SafeConvertInt(xNodeList[i].Attributes["threshold"].Value), + IntervalDays = Utilities.SafeConvertInt(xNodeList[i].Attributes["intervaldays"].Value), + SendAwardNotification = true, + ImageMarkup = xNodeList[i].Attributes["imagemarkup"].Value, + FileId = fileId, + }; + badge.SuppresssAwardNotificationOnBackfill = !badge.OneTimeAward && !badge.BadgeMetric.Equals(DotNetNuke.Modules.ActiveForums.Enums.BadgeMetric.BadgeMetricManual); + new DotNetNuke.Modules.ActiveForums.Controllers.BadgeController().Insert(badge); + } + catch (Exception ex) + { + DotNetNuke.Modules.ActiveForums.Exceptions.LogException(ex); + } + } + } + } + } + } + } + } + } + catch (Exception ex) + { + DotNetNuke.Modules.ActiveForums.Exceptions.LogException(ex); } } } diff --git a/Dnn.CommunityForums/class/Globals.cs b/Dnn.CommunityForums/class/Globals.cs index 6c810782f..30b8d9b69 100644 --- a/Dnn.CommunityForums/class/Globals.cs +++ b/Dnn.CommunityForums/class/Globals.cs @@ -153,6 +153,8 @@ public static string DefaultAnonRoles public const string AvatarRefreshGravatar = "GRAVATAR"; + public const string DefaultBadgesFolderName = "DNNCommunityForums/Badges"; + public const string AdminResourceFile = Globals.ModulePath + "App_LocalResources/AdminResources.resx"; public const string SharedResourceFile = Globals.ModulePath + "App_LocalResources/SharedResources.resx"; public const string ControlPanelResourceFile = Globals.ModulePath + "App_LocalResources/ControlPanel.ascx.resx"; @@ -179,6 +181,8 @@ public static string DefaultAnonRoles public const string LikeNotificationTypeDescription = Globals.ModuleFriendlyName + " Like Notification"; public const string PinNotificationType = "DCF-PinNotification"; public const string PinNotificationTypeDescription = Globals.ModuleFriendlyName + " Pin Notification"; + public const string BadgeNotificationType = "DCF-BadgeNotification"; + public const string BadgeNotificationTypeDescription = Globals.ModuleFriendlyName + " Badge Notification"; public static Version ModuleVersion => new Version(DesktopModuleController.GetDesktopModuleByFriendlyName(Globals.ModuleFriendlyName).Version); } @@ -384,6 +388,7 @@ public class ParamKeys public const string Action = "action"; public const string TimeSpan = "ts"; public const string Mode = "mode"; + public const string BadgeId = "badgeid"; } public class Modes @@ -429,6 +434,8 @@ public class Views public const string ModerateReport = "modreport"; public const string Likes = "likes"; public const string RecycleBin = "recyclebin"; + public const string BadgeUsers = "badgeusers"; + public const string UserBadges = "userbadges"; } internal static class GridTypes @@ -445,6 +452,8 @@ internal static class GridTypes public const string Announcements = "announcements"; public const string Tags = "tags"; public const string RecycleBin = "recyclebin"; + public const string BadgeUsers = "badgeusers"; + public const string UserBadges = "userbadges"; } public class PostActions @@ -499,6 +508,11 @@ public class CacheKeys public const string ForumGroupInfo = "AF-{0}-fgi-{1}"; public const string ForumGroupSettings = "AF-{0}-fgs-{1}"; public const string PermissionsInfo = "AF-{0}-perms-{1}"; + public const string BadgeInfo = "AF-{0}-badge-{1}"; + public const string UserBadgeInfo = "AF-{0}-userbadge-{1}"; + public const string UserBadges = "AF-{0}-userbadges-{1}"; + public const string BadgeUsers = "AF-{0}-badgeusers-{1}"; + public const string BadgeUserCount = "AF-{0}-badgeusercount-{1}-{2}"; public const string ContentInfo = "AF-{0}-ci-{1}"; public const string TopicInfo = "AF-{0}-ti-{1}"; diff --git a/Dnn.CommunityForums/class/ModuleSettings.cs b/Dnn.CommunityForums/class/ModuleSettings.cs new file mode 100644 index 000000000..c265aee64 --- /dev/null +++ b/Dnn.CommunityForums/class/ModuleSettings.cs @@ -0,0 +1,209 @@ +// Copyright (c) by DNN Community +// +// DNN Community licenses this file to you under the MIT license. +// +// See the LICENSE file in the project root for more information. +// +// 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.ActiveForums +{ + using System; + using System.Collections; + using System.Reflection; + + using DotNetNuke.Modules.ActiveForums.Entities; + + public class ModuleSettings + { + private DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings defaultFeatureSettings; + + public int ModuleId { get; set; } + + public Hashtable MainSettings { get; set; } + + public ModuleSettings() + { + this.MainSettings = new Hashtable(); + } + + public ModuleSettings(int moduleId) + { + this.MainSettings = new Hashtable(); + this.ModuleId = moduleId; + } + + public int PageSize => this.MainSettings.GetInt(SettingKeys.PageSize, 20); + + public string UserNameDisplay => this.MainSettings.GetString(SettingKeys.UserNameDisplay, "USERNAME"); + + public bool EnablePoints => this.MainSettings.GetBoolean(SettingKeys.EnablePoints); + + public int TopicPointValue => this.MainSettings.GetInt(SettingKeys.TopicPointValue, 1); + + public int ReplyPointValue => this.MainSettings.GetInt(SettingKeys.ReplyPointValue, 1); + + public int AnswerPointValue => this.MainSettings.GetInt(SettingKeys.AnswerPointValue, 1); + + public int MarkAsAnswerPointValue => this.MainSettings.GetInt(SettingKeys.MarkAnswerPointValue, 1); + + public int ModPointValue => this.MainSettings.GetInt(SettingKeys.ModPointValue, 1); + + public int AvatarHeight => this.MainSettings.GetInt(SettingKeys.AvatarHeight, 80); + + public int AvatarWidth => this.MainSettings.GetInt(SettingKeys.AvatarWidth, 80); + + public bool AvatarRefreshEnabled => this.MainSettings.GetString(SettingKeys.AvatarRefresh) == Globals.AvatarRefreshGravatar; + + public string AvatarRefreshType => this.MainSettings.GetString(SettingKeys.AvatarRefresh); + + public int AllowSignatures => this.MainSettings.GetInt(SettingKeys.AllowSignatures); + + public string DateFormatString => this.MainSettings.GetString(SettingKeys.DateFormatString, "M/d/yyyy"); + + public string TimeFormatString => this.MainSettings.GetString(SettingKeys.TimeFormatString, "h:mm tt"); + + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] + public int TimeZoneOffset => this.MainSettings.GetInt(SettingKeys.TimeZoneOffset); + + public bool UsersOnlineEnabled => this.MainSettings.GetBoolean(SettingKeys.UsersOnlineEnabled); + + public string MemberListMode => "Enabled"; + + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] + public int ForumTemplateID => throw new NotImplementedException(); + + public DateTime InstallDate => Utilities.SafeConvertDateTime(this.MainSettings[SettingKeys.InstallDate], Utilities.NullDate()); + + public bool IsInstalled => this.MainSettings.GetBoolean(SettingKeys.IsInstalled); + + public PMTypes PMType + { + get + { + PMTypes parsedValue; + return Enum.TryParse(this.MainSettings.GetString(SettingKeys.PMType), true, out parsedValue) + ? parsedValue + : PMTypes.Disabled; + } + } + + public int PMTabId => this.MainSettings.GetInt(SettingKeys.PMTabId, -1); + + public bool DisableAccountTab => this.MainSettings.GetBoolean(SettingKeys.DisableAccountTab); + + public string Theme + { + get + { + var result = this.MainSettings.GetString(SettingKeys.Theme); + return string.IsNullOrWhiteSpace(result) ? "_legacy" : result; + } + } + + public string ThemeLocation => string.Concat(Globals.ThemesPath, this.Theme, "/"); + + public string TemplatePath => string.Concat(this.ThemeLocation, "templates/"); + + public bool FullText => this.MainSettings.GetBoolean(SettingKeys.FullText); + + public string AllowSubTypes => this.MainSettings.GetString(SettingKeys.AllowSubTypes, string.Empty); + + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] + public bool MailQueue => true; + + public bool CacheTemplates => this.MainSettings.GetBoolean(SettingKeys.CacheTemplates, defaultValue: true); + + public int FloodInterval => this.MainSettings.GetInt(SettingKeys.FloodInterval, 5); + + public int EditInterval => this.MainSettings.GetInt(SettingKeys.EditInterval); + + public DotNetNuke.Modules.ActiveForums.Enums.DeleteBehavior DeleteBehavior + { + get + { + DotNetNuke.Modules.ActiveForums.Enums.DeleteBehavior parsedValue; + + return Enum.TryParse(this.MainSettings.GetString(SettingKeys.DeleteBehavior), true, out parsedValue) + ? parsedValue + : DotNetNuke.Modules.ActiveForums.Enums.DeleteBehavior.Recycle; + } + } + + public ProfileVisibilities ProfileVisibility + { + get + { + ProfileVisibilities parsedValue; + + return Enum.TryParse(this.MainSettings.GetString(SettingKeys.ProfileVisibility), true, + out parsedValue) + ? parsedValue + : ProfileVisibilities.Disabled; + } + } + + public bool UseShortUrls => this.MainSettings.GetBoolean(SettingKeys.UseShortUrls); + + public bool UseSkinBreadCrumb => this.MainSettings.GetBoolean(SettingKeys.UseSkinBreadCrumb); + + public bool AutoLinkEnabled => this.MainSettings.GetBoolean(SettingKeys.EnableAutoLink, true); + + public bool URLRewriteEnabled => this.MainSettings.GetBoolean(SettingKeys.EnableURLRewriter); + + public string PrefixURLBase => this.MainSettings.GetString(SettingKeys.PrefixURLBase, string.Empty); + + public string PrefixURLOther => !this.URLRewriteEnabled + ? string.Empty + : this.MainSettings.GetString(SettingKeys.PrefixURLOther, "other"); + + public string PrefixURLTag => !this.URLRewriteEnabled + ? string.Empty + : this.MainSettings.GetString(SettingKeys.PrefixURLTags, "tag"); + + public string PrefixURLCategory => !this.URLRewriteEnabled + ? string.Empty + : this.MainSettings.GetString(SettingKeys.PrefixURLCategories, "category"); + + public string PrefixURLLikes => !this.URLRewriteEnabled + ? string.Empty + : this.MainSettings.GetString(SettingKeys.PrefixURLLikes, Views.Likes); + + public int DefaultPermissionId => this.MainSettings.GetInt(SettingKeys.DefaultPermissionId); + + public string DefaultSettingsKey => this.MainSettings.GetString(SettingKeys.DefaultSettingsKey) ?? $"M{this.ModuleId}"; + + public FeatureSettings DefaultFeatureSettings + { + get => this.defaultFeatureSettings ?? (this.defaultFeatureSettings = new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(moduleId: this.ModuleId, settingsKey: this.DefaultSettingsKey)); + set => this.defaultFeatureSettings = value; + } + } + + public class SettingsInfo + { + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] + public static Hashtable GeneralSettings(int moduleId, string groupKey) => throw new NotImplementedException(); + + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] + public static string GetSetting(int moduleId, string groupKey, string settingName) => throw new NotImplementedException(); + + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] + public static bool SaveSetting(int moduleId, string settingKey, string settingName, string settingValue) => throw new NotImplementedException(); + + [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] + public static bool DeleteSetting(int moduleId, string groupKey, string settingName) => throw new NotImplementedException(); + } +} diff --git a/Dnn.CommunityForums/class/Settings.cs b/Dnn.CommunityForums/class/Settings.cs deleted file mode 100644 index 33dc1ff6e..000000000 --- a/Dnn.CommunityForums/class/Settings.cs +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright (c) by DNN Community -// -// DNN Community licenses this file to you under the MIT license. -// -// See the LICENSE file in the project root for more information. -// -// 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.ActiveForums -{ - using System; - using System.Collections; - - using DotNetNuke.Modules.ActiveForums.Entities; - - #region SettingsInfo - - public class SettingsInfo - { - public int ModuleId { get; set; } - - private DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings featureSettings; - - public Hashtable MainSettings { get; set; } - - public SettingsInfo() - { - this.MainSettings = new Hashtable(); - } - - public SettingsInfo(int moduleId) - { - this.MainSettings = new Hashtable(); - this.ModuleId = moduleId; - } - - public int PageSize - { - get { return this.MainSettings.GetInt(SettingKeys.PageSize, 20); } - } - - public string UserNameDisplay - { - get { return this.MainSettings.GetString(SettingKeys.UserNameDisplay, "USERNAME"); } - } - - public bool EnablePoints - { - get { return this.MainSettings.GetBoolean(SettingKeys.EnablePoints); } - } - - public int TopicPointValue - { - get { return this.MainSettings.GetInt(SettingKeys.TopicPointValue, 1); } - } - - public int ReplyPointValue - { - get { return this.MainSettings.GetInt(SettingKeys.ReplyPointValue, 1); } - } - - public int AnswerPointValue - { - get { return this.MainSettings.GetInt(SettingKeys.AnswerPointValue, 1); } - } - - public int MarkAsAnswerPointValue - { - get { return this.MainSettings.GetInt(SettingKeys.MarkAnswerPointValue, 1); } - } - - public int ModPointValue - { - get { return this.MainSettings.GetInt(SettingKeys.ModPointValue, 1); } - } - - public int AvatarHeight - { - get { return this.MainSettings.GetInt(SettingKeys.AvatarHeight, 80); } - } - - public int AvatarWidth - { - get { return this.MainSettings.GetInt(SettingKeys.AvatarWidth, 80); } - } - - public bool AvatarRefreshEnabled - { - get { return this.MainSettings.GetString(SettingKeys.AvatarRefresh) == Globals.AvatarRefreshGravatar; } - } - - public string AvatarRefreshType - { - get { return this.MainSettings.GetString(SettingKeys.AvatarRefresh); } - } - - public int AllowSignatures - { - get { return this.MainSettings.GetInt(SettingKeys.AllowSignatures); } - } - - public string DateFormatString - { - get { return this.MainSettings.GetString(SettingKeys.DateFormatString, "M/d/yyyy"); } - } - - public string TimeFormatString - { - get { return this.MainSettings.GetString(SettingKeys.TimeFormatString, "h:mm tt"); } - } - - [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] - public int TimeZoneOffset - { - get { return this.MainSettings.GetInt(SettingKeys.TimeZoneOffset); } - } - - public bool UsersOnlineEnabled - { - get { return this.MainSettings.GetBoolean(SettingKeys.UsersOnlineEnabled); } - } - - public string MemberListMode - { - get - { - return "Enabled"; - } - } - - [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] - public int ForumTemplateID => throw new NotImplementedException(); - - public DateTime InstallDate - { - get { return Utilities.SafeConvertDateTime(this.MainSettings[SettingKeys.InstallDate], Utilities.NullDate()); } - } - - public bool IsInstalled - { - get { return this.MainSettings.GetBoolean(SettingKeys.IsInstalled); } - } - - public PMTypes PMType - { - get - { - PMTypes parsedValue; - return Enum.TryParse(this.MainSettings.GetString(SettingKeys.PMType), true, out parsedValue) - ? parsedValue - : PMTypes.Disabled; - } - } - - public int PMTabId - { - get { return this.MainSettings.GetInt(SettingKeys.PMTabId, -1); } - } - - public bool DisableAccountTab - { - get { return this.MainSettings.GetBoolean(SettingKeys.DisableAccountTab); } - } - - public string Theme - { - get - { - var result = this.MainSettings.GetString(SettingKeys.Theme); - return string.IsNullOrWhiteSpace(result) ? "_legacy" : result; - } - } - - public string ThemeLocation => string.Concat(Globals.ThemesPath, this.Theme, "/"); - - public string TemplatePath => string.Concat(this.ThemeLocation, "templates/"); - - public bool FullText - { - get { return this.MainSettings.GetBoolean(SettingKeys.FullText); } - } - - public string AllowSubTypes - { - get { return this.MainSettings.GetString(SettingKeys.AllowSubTypes, string.Empty); } - } - - [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] - public bool MailQueue => true; - - public bool CacheTemplates - { - get { return this.MainSettings.GetBoolean(SettingKeys.CacheTemplates, defaultValue: true); } - } - - public int FloodInterval - { - get { return this.MainSettings.GetInt(SettingKeys.FloodInterval, 5); } - } - - public int EditInterval - { - get { return this.MainSettings.GetInt(SettingKeys.EditInterval); } - } - - public DotNetNuke.Modules.ActiveForums.Enums.DeleteBehavior DeleteBehavior - { - get - { - DotNetNuke.Modules.ActiveForums.Enums.DeleteBehavior parsedValue; - - return Enum.TryParse(this.MainSettings.GetString(SettingKeys.DeleteBehavior), true, out parsedValue) - ? parsedValue - : DotNetNuke.Modules.ActiveForums.Enums.DeleteBehavior.Recycle; - } - } - - public ProfileVisibilities ProfileVisibility - { - get - { - ProfileVisibilities parsedValue; - - return Enum.TryParse(this.MainSettings.GetString(SettingKeys.ProfileVisibility), true, - out parsedValue) - ? parsedValue - : ProfileVisibilities.Disabled; - } - } - - public bool UseShortUrls - { - get { return this.MainSettings.GetBoolean(SettingKeys.UseShortUrls); } - } - - public bool UseSkinBreadCrumb - { - get { return this.MainSettings.GetBoolean(SettingKeys.UseSkinBreadCrumb); } - } - - public bool AutoLinkEnabled - { - get { return this.MainSettings.GetBoolean(SettingKeys.EnableAutoLink, true); } - } - - public bool URLRewriteEnabled - { - get { return this.MainSettings.GetBoolean(SettingKeys.EnableURLRewriter); } - } - - public string PrefixURLBase - { - get { return this.MainSettings.GetString(SettingKeys.PrefixURLBase, string.Empty); } - } - - public string PrefixURLOther - { - get - { - return !this.URLRewriteEnabled - ? string.Empty - : this.MainSettings.GetString(SettingKeys.PrefixURLOther, "other"); - } - } - - public string PrefixURLTag - { - get - { - return !this.URLRewriteEnabled - ? string.Empty - : this.MainSettings.GetString(SettingKeys.PrefixURLTags, "tag"); - } - } - - public string PrefixURLCategory - { - get - { - return !this.URLRewriteEnabled - ? string.Empty - : this.MainSettings.GetString(SettingKeys.PrefixURLCategories, "category"); - } - } - - public string PrefixURLLikes - { - get - { - return !this.URLRewriteEnabled - ? string.Empty - : this.MainSettings.GetString(SettingKeys.PrefixURLLikes, Views.Likes); - } - } - - public int DefaultPermissionId - { - get { return this.MainSettings.GetInt(SettingKeys.DefaultPermissionId); } - } - - public string DefaultSettingsKey - { - get - { - return this.MainSettings.GetString(SettingKeys.DefaultSettingsKey) ?? $"M:{this.ModuleId}"; - } - } - - public FeatureSettings ForumFeatureSettings - { - get => this.featureSettings ?? (this.featureSettings = this.LoadFeatureSettings()); - set => this.featureSettings = value; - } - - internal FeatureSettings LoadFeatureSettings() - { - return new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(moduleId: this.ModuleId, settingsKey: this.DefaultSettingsKey); - } - } - - #endregion - - public class Settings - { - public static Hashtable GeneralSettings(int moduleId, string groupKey) - { - var ht = new Hashtable(); - var dr = DataProvider.Instance().Settings_List(moduleId, groupKey); - while (dr.Read()) - { - ht.Add(dr.GetString("SettingName"), dr.GetString("SettingValue")); - } - - dr.Close(); - return ht; - } - - public static string GetSetting(int moduleId, string groupKey, string settingName) - { - try - { - return DataProvider.Instance().Settings_Get(moduleId, groupKey, settingName); - } - catch (Exception) - { - return string.Empty; - } - } - - public static bool SaveSetting(int moduleId, string groupKey, string settingName, string settingValue) - { - try - { - DataProvider.Instance().Settings_Save(moduleId, groupKey, settingName, settingValue); - return true; - } - catch (Exception ex) - { - return false; - } - } - } -} diff --git a/Dnn.CommunityForums/class/SettingsBase.cs b/Dnn.CommunityForums/class/SettingsBase.cs index 9c86fe124..32cc68118 100644 --- a/Dnn.CommunityForums/class/SettingsBase.cs +++ b/Dnn.CommunityForums/class/SettingsBase.cs @@ -28,15 +28,8 @@ namespace DotNetNuke.Modules.ActiveForums public class SettingsBase : PortalModuleBase { - #region Private Members private int forumModuleId = -1; - private string loadView = string.Empty; - private string imagePath = string.Empty; - private string @params = string.Empty; - private int forumTabId = -1; - #endregion - #region Public Properties internal DotNetNuke.Modules.ActiveForums.Entities.ForumUserInfo ForumUser => new DotNetNuke.Modules.ActiveForums.Controllers.ForumUserController(this.ForumModuleId).GetByUserId(this.PortalId, this.UserId); internal string UserForumsList => DotNetNuke.Modules.ActiveForums.Controllers.ForumController.GetForumsForUser(this.PortalId, this.ForumModuleId, this.ForumUser); @@ -45,12 +38,9 @@ public int ForumModuleId { get { - if (this.forumModuleId > 0) - { - return this.forumModuleId; - } - - return DotNetNuke.Modules.ActiveForums.Utilities.GetForumModuleId(this.ModuleId, this.TabId); + return this.forumModuleId > 0 + ? this.forumModuleId + : DotNetNuke.Modules.ActiveForums.Utilities.GetForumModuleId(this.ModuleId, this.TabId); } set @@ -59,31 +49,9 @@ public int ForumModuleId } } - public int ForumTabId - { - get - { - return this.forumTabId; - } - - set - { - this.forumTabId = value; - } - } - - public string Params - { - get - { - return this.@params; - } + public int ForumTabId { get; set; } = -1; - set - { - this.@params = value; - } - } + public string Params { get; set; } = string.Empty; public int PageId { @@ -119,15 +87,12 @@ public int PageId public bool ShowToolbar { get; set; } = true; - #endregion [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No longer used.")] public UserController UserController => throw new NotImplementedException(); [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No longer used.")] public ForumsDB ForumsDB => throw new NotImplementedException(); - #region Public Properties - User Preferences - [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No longer used.")] public CurrentUserTypes CurrentUserType => this.ForumUser.CurrentUserType; @@ -135,31 +100,9 @@ public int PageId public bool UserIsMod => this.ForumUser.GetIsMod(this.ForumModuleId); [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No longer used.")] - public string UserDefaultSort - { - get - { - if (this.UserId != -1) - { - return this.ForumUser.PrefDefaultSort; - } + public string UserDefaultSort => this.UserId != -1 ? this.ForumUser.PrefDefaultSort : "ASC"; - return "ASC"; - } - } - - public int UserDefaultPageSize - { - get - { - if (this.UserId != -1) - { - return this.ForumUser.PrefPageSize; - } - - return this.MainSettings.PageSize; - } - } + public int UserDefaultPageSize => this.UserId != -1 ? this.ForumUser.PrefPageSize : this.ModuleSettings.PageSize; [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No longer used.")] public bool UserPrefHideSigs @@ -183,83 +126,31 @@ public bool UserPrefHideSigs } [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No longer used.")] - public bool UserPrefHideAvatars - { - get - { - if (this.UserId != -1) - { - return this.ForumUser.PrefBlockAvatars; - } - - return false; - } - } + public bool UserPrefHideAvatars => this.UserId != -1 ? this.ForumUser.PrefBlockAvatars : false; [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No longer used.")] - public bool UserPrefJumpLastPost - { - get - { - if (this.UserId != -1) - { - return this.ForumUser.PrefJumpLastPost; - } - - return false; - } - } + public bool UserPrefJumpLastPost => this.UserId != -1 ? this.ForumUser.PrefJumpLastPost : false; [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. No longer used.")] - public bool UserPrefShowReplies - { - get - { - if (this.UserId != -1) - { - return this.ForumUser.PrefDefaultShowReplies; - } - - return false; - } - } + public bool UserPrefShowReplies => this.UserId != -1 ? this.ForumUser.PrefDefaultShowReplies : false; - public bool UserPrefTopicSubscribe - { - get - { - if (this.UserId != -1) - { - return this.ForumUser.PrefTopicSubscribe; - } + public bool UserPrefTopicSubscribe => this.UserId != -1 ? this.ForumUser.PrefTopicSubscribe : false; - return false; - } - } - #endregion + public Framework.CDefault BasePage => (Framework.CDefault)this.Page; - #region Public ReadOnly Properties - public Framework.CDefault BasePage + public static DotNetNuke.Modules.ActiveForums.ModuleSettings GetModuleSettings(int moduleId) { - get - { - return (Framework.CDefault)this.Page; - } - } - - public static SettingsInfo GetModuleSettings(int moduleId) - { - SettingsInfo objSettings = (SettingsInfo)DataCache.SettingsCacheRetrieve(moduleId, string.Format(CacheKeys.MainSettings, moduleId)); + DotNetNuke.Modules.ActiveForums.ModuleSettings objSettings = (ModuleSettings)DataCache.SettingsCacheRetrieve(moduleId, string.Format(CacheKeys.MainSettings, moduleId)); if (objSettings == null && moduleId > 0) { - objSettings = new SettingsInfo { ModuleId = moduleId, MainSettings = new DotNetNuke.Entities.Modules.ModuleController().GetModule(moduleId).ModuleSettings }; + objSettings = new DotNetNuke.Modules.ActiveForums.ModuleSettings { ModuleId = moduleId, MainSettings = new DotNetNuke.Entities.Modules.ModuleController().GetModule(moduleId).ModuleSettings }; DataCache.SettingsCacheStore(moduleId, string.Format(CacheKeys.MainSettings, moduleId), objSettings); } return objSettings; } - public SettingsInfo MainSettings + public DotNetNuke.Modules.ActiveForums.ModuleSettings ModuleSettings { get { @@ -268,13 +159,7 @@ public SettingsInfo MainSettings } } - public string ImagePath - { - get - { - return this.Page.ResolveUrl(string.Concat(this.MainSettings.ThemeLocation, "/images")); - } - } + public string ImagePath => this.Page.ResolveUrl(string.Concat(this.ModuleSettings.ThemeLocation, "/images")); public string GetViewType { @@ -285,55 +170,23 @@ public string GetViewType return this.Request.Params[ParamKeys.ViewType].ToUpperInvariant(); } - if (this.Request.Params["view"] != null) - { - return this.Request.Params["view"].ToUpperInvariant(); - } - - return null; + return this.Request.Params["view"] != null ? this.Request.Params["view"].ToUpperInvariant() : null; } } - public TimeSpan TimeZoneOffset - { - /* AF now stores datetime in UTC, so this method returns timezoneoffset for current user if available or from portal settings as fallback */ - get - { - return Utilities.GetTimeZoneOffsetForUser(this.UserInfo); - } - } - - #endregion + // Forums stores datetime in UTC, so this method returns timezoneoffset for current user if available or from portal settings as fallback + public TimeSpan TimeZoneOffset => Utilities.GetTimeZoneOffsetForUser(this.UserInfo); - #region Protected Methods [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used.")] - protected DateTime GetUserDate(DateTime displayDate) - { - return displayDate.AddMinutes(this.TimeZoneOffset.TotalMinutes); - } + protected DateTime GetUserDate(DateTime displayDate) => displayDate.AddMinutes(this.TimeZoneOffset.TotalMinutes); - #endregion + public string NavigateUrl(int tabId) => Utilities.NavigateURL(tabId); - #region Public Methods - public string NavigateUrl(int tabId) - { - return Utilities.NavigateURL(tabId); - } + public string NavigateUrl(int tabId, string controlKey, params string[] additionalParameters) => Utilities.NavigateURL(tabId, controlKey, additionalParameters); - public string NavigateUrl(int tabId, string controlKey, params string[] additionalParameters) - { - return Utilities.NavigateURL(tabId, controlKey, additionalParameters); - } - - public void RenderMessage(string title, string message) - { - this.RenderMessage(Utilities.GetSharedResource(title), message, string.Empty, null); - } + public void RenderMessage(string title, string message) => this.RenderMessage(Utilities.GetSharedResource(title), message, string.Empty, null); - public void RenderMessage(string message, string errorMsg, Exception ex) - { - this.RenderMessage(Utilities.GetSharedResource("[RESX:Error]"), message, errorMsg, ex); - } + public void RenderMessage(string message, string errorMsg, Exception ex) => this.RenderMessage(Utilities.GetSharedResource("[RESX:Error]"), message, errorMsg, ex); public void RenderMessage(string title, string message, string errorMsg, Exception ex) { @@ -383,6 +236,5 @@ protected override void OnLoad(EventArgs e) ServicesFramework.Instance.RequestAjaxAntiForgerySupport(); } - #endregion } } diff --git a/Dnn.CommunityForums/class/TemplateUtils.cs b/Dnn.CommunityForums/class/TemplateUtils.cs index d38aa9624..43d052a5a 100644 --- a/Dnn.CommunityForums/class/TemplateUtils.cs +++ b/Dnn.CommunityForums/class/TemplateUtils.cs @@ -241,7 +241,7 @@ private static string ParseProfileInfo(int moduleId, DotNetNuke.Modules.ActiveFo var myTemplate = Convert.ToString(DataCache.SettingsCacheRetrieve(moduleId, cacheKey)); if (string.IsNullOrEmpty(myTemplate)) { - myTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(moduleId, Enums.TemplateType.ProfileInfo, SettingsBase.GetModuleSettings(moduleId).ForumFeatureSettings.TemplateFileNameSuffix); + myTemplate = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(moduleId, Enums.TemplateType.ProfileInfo, SettingsBase.GetModuleSettings(moduleId).DefaultFeatureSettings.TemplateFileNameSuffix); if (cacheKey != string.Empty) { DataCache.SettingsCacheStore(moduleId, cacheKey, myTemplate); diff --git a/Dnn.CommunityForums/class/Utilities.cs b/Dnn.CommunityForums/class/Utilities.cs index 3bdb0bfee..1d03d783f 100644 --- a/Dnn.CommunityForums/class/Utilities.cs +++ b/Dnn.CommunityForums/class/Utilities.cs @@ -28,6 +28,7 @@ namespace DotNetNuke.Modules.ActiveForums using System.Linq; using System.Reflection; using System.Security.Cryptography; + using System.Security.Principal; using System.Text; using System.Text.RegularExpressions; using System.Web; @@ -115,7 +116,7 @@ internal static string BuildToolbar(int portalId, int forumModuleId, int forumTa string sToolbar = SettingsBase.GetModuleSettings(moduleId).CacheTemplates ? Convert.ToString(DataCache.SettingsCacheRetrieve(moduleId, cacheKey)) : string.Empty; if (string.IsNullOrEmpty(sToolbar)) { - sToolbar = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(forumModuleId, Enums.TemplateType.ToolBar, SettingsBase.GetModuleSettings(moduleId).ForumFeatureSettings.TemplateFileNameSuffix); + sToolbar = DotNetNuke.Modules.ActiveForums.Controllers.TemplateController.Template_Get(forumModuleId, Enums.TemplateType.ToolBar, SettingsBase.GetModuleSettings(moduleId).DefaultFeatureSettings.TemplateFileNameSuffix); sToolbar = Utilities.ParseToolBar(template: sToolbar, portalId: portalId, forumTabId: forumTabId, forumModuleId: forumModuleId, tabId: tabId, moduleId: moduleId, forumUser: forumUser, requestUri: requestUri, rawUrl: rawUrl); if (SettingsBase.GetModuleSettings(moduleId).CacheTemplates) { @@ -487,6 +488,7 @@ public static string CleanString(int portalId, string text, bool allowHTML, Edit if (!allowScript) { + sClean = RemoveScriptTags(sClean); sClean = DecodeBrackets(sClean); sClean = XSSFilter(sClean); } @@ -533,10 +535,7 @@ private static string CleanTextBox(int portalId, string text, bool allowHTML, bo else { strMessage = EncodeFormTags(strMessage); - if (!allowHTML) - { - strMessage = System.Net.WebUtility.HtmlEncode(strMessage); - } + strMessage = System.Net.WebUtility.HtmlEncode(strMessage); if (useFilter) { @@ -739,6 +738,38 @@ public static string XSSFilter(string sText = "", bool removeHTML = false) return sText; } + internal static string RemoveScriptTags(string body = "") + { + if (!string.IsNullOrEmpty(body)) + { + var tryEncoded = false; + for (var i = 0; i < 2; i++) + { + var codeTagStartEndPositions = new List<(int Start, int End)>(); + + const string codeTagPattern = @"<(?:code|pre)\b[^>]*>(.*?)"; + foreach (Match m in RegexUtils.GetCachedRegex(tryEncoded ? System.Net.WebUtility.HtmlEncode(codeTagPattern) : codeTagPattern, RegexOptions.IgnoreCase).Matches(body)) + { + codeTagStartEndPositions.Add((m.Index, m.Index + m.Length)); + } + + const string scriptTagPattern = @"]*>(.*?)"; + foreach (Match m in RegexUtils.GetCachedRegex(tryEncoded ? System.Net.WebUtility.HtmlEncode(scriptTagPattern) : scriptTagPattern, RegexOptions.IgnoreCase).Matches(body)) + { + bool insideCodeTag = m.Index >= 0 && codeTagStartEndPositions.Any(t => m.Index >= t.Start && m.Index < t.End); + if (!insideCodeTag) + { + body = body.Replace(m.Value, string.Empty); + } + } + + tryEncoded = true; + } + } + + return body; + } + public static string StripExecCode(string sText) { var i = 0; @@ -1044,6 +1075,11 @@ internal static string GetUserFormattedDateTime(DateTime? dateTime, CultureInfo return GetUserFormattedDateTime(dateTime, userCultureInfo, timeZoneOffset, "g"); } + public static string GetUserFormattedDateTime(DateTime dateTime, CultureInfo userCultureInfo, TimeSpan timeZoneOffset) + { + return GetUserFormattedDateTime((DateTime?)dateTime, userCultureInfo, timeZoneOffset, "g"); + } + internal static string GetUserFormattedDateTime(DateTime? dateTime, CultureInfo userCultureInfo, TimeSpan timeZoneOffset, string format) { if (dateTime != null) @@ -1074,11 +1110,6 @@ public static string GetUserFormattedDateTime(DateTime dateTime, int portalId, i return GetUserFormattedDateTime((DateTime?)dateTime, portalId, userId); } - [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used")] - public static string GetUserFormattedDateTime(DateTime dateTime, CultureInfo userCultureInfo, TimeSpan timeZoneOffset) - { - return GetUserFormattedDateTime((DateTime?)dateTime, userCultureInfo, timeZoneOffset, "g"); - } [Obsolete("Deprecated in Community Forums. Removed in 10.00.00. Not Used")] public static string GetUserFormattedDate(DateTime date, CultureInfo userCultureInfo, TimeSpan timeZoneOffset) diff --git a/Dnn.CommunityForums/components/Common/HandlerBase.cs b/Dnn.CommunityForums/components/Common/HandlerBase.cs index b6328a550..3ba9e5578 100644 --- a/Dnn.CommunityForums/components/Common/HandlerBase.cs +++ b/Dnn.CommunityForums/components/Common/HandlerBase.cs @@ -44,7 +44,7 @@ internal enum OutputCodes : int private int _groupid = -1; private int _upid = -1; private DotNetNuke.Entities.Portals.PortalSettings _ps; - private SettingsInfo _mainSettings; + private ModuleSettings _mainSettings; private bool _AdminRequired = false; public bool AdminRequired @@ -137,7 +137,7 @@ public bool IsDebug } } - public SettingsInfo MainSettings + public ModuleSettings MainSettings { get { diff --git a/Dnn.CommunityForums/components/Data/Common.cs b/Dnn.CommunityForums/components/Data/Common.cs index 5fbfd8860..eed0b26e9 100644 --- a/Dnn.CommunityForums/components/Data/Common.cs +++ b/Dnn.CommunityForums/components/Data/Common.cs @@ -174,7 +174,7 @@ public bool CheckForumURL(int portalId, int moduleId, string vanityName, int for { try { - SettingsInfo _mainSettings = SettingsBase.GetModuleSettings(moduleId); + ModuleSettings _mainSettings = SettingsBase.GetModuleSettings(moduleId); DotNetNuke.Modules.ActiveForums.Entities.ForumGroupInfo fg = new DotNetNuke.Modules.ActiveForums.Controllers.ForumGroupController().GetById(forumGroupId, moduleId); if (!string.IsNullOrEmpty(fg.PrefixURL)) { @@ -213,7 +213,7 @@ public bool CheckGroupURL(int portalId, int moduleId, string vanityName, int for { try { - SettingsInfo _mainSettings = SettingsBase.GetModuleSettings(moduleId); + ModuleSettings _mainSettings = SettingsBase.GetModuleSettings(moduleId); if (!string.IsNullOrEmpty(_mainSettings.PrefixURLBase)) { vanityName = _mainSettings.PrefixURLBase + "/" + vanityName; diff --git a/Dnn.CommunityForums/components/Extensions/ReWriter.cs b/Dnn.CommunityForums/components/Extensions/ReWriter.cs index 07281a08b..c46b830db 100644 --- a/Dnn.CommunityForums/components/Extensions/ReWriter.cs +++ b/Dnn.CommunityForums/components/Extensions/ReWriter.cs @@ -40,7 +40,7 @@ public class ForumsReWriter : IHttpModule private int contentId = -1; private int userId = -1; private int archived = 0; - private SettingsInfo mainSettings = null; + private ModuleSettings mainSettings = null; private int urlType = 0; // 0=default, 1= views, 2 = category, 3 = tag private int otherId = -1; private int categoryId = -1; @@ -307,7 +307,7 @@ public void OnBeginRequest(object s, EventArgs e) if (this.moduleId > 0) { - this.mainSettings = new SettingsInfo { ModuleId = this.moduleId, MainSettings = DotNetNuke.Entities.Modules.ModuleController.Instance.GetModule(moduleId: this.moduleId, tabId: DotNetNuke.Common.Utilities.Null.NullInteger, ignoreCache: false).ModuleSettings }; + this.mainSettings = new ModuleSettings { ModuleId = this.moduleId, MainSettings = DotNetNuke.Entities.Modules.ModuleController.Instance.GetModule(moduleId: this.moduleId, tabId: DotNetNuke.Common.Utilities.Null.NullInteger, ignoreCache: false).ModuleSettings }; } if (this.mainSettings == null) @@ -511,6 +511,12 @@ public void OnBeginRequest(object s, EventArgs e) case 10: v = GridTypes.Unresolved; break; + case 11: + v = GridTypes.BadgeUsers; + break; + case 12: + v = GridTypes.UserBadges; + break; case 13: v = GridTypes.RecycleBin; break; diff --git a/Dnn.CommunityForums/components/Helpers/UpgradeModuleSettings.cs b/Dnn.CommunityForums/components/Helpers/UpgradeModuleSettings.cs index 7b520ea91..5624e2ce0 100644 --- a/Dnn.CommunityForums/components/Helpers/UpgradeModuleSettings.cs +++ b/Dnn.CommunityForums/components/Helpers/UpgradeModuleSettings.cs @@ -21,8 +21,10 @@ namespace DotNetNuke.Modules.ActiveForums.Helpers { using System; + using System.Collections; using System.Xml; + using DotNetNuke.Collections; using DotNetNuke.Common.Utilities; using DotNetNuke.Data; using DotNetNuke.Entities.Modules; @@ -47,16 +49,18 @@ internal static void MoveSettings_070011() { if (!SettingsBase.GetModuleSettings(module.ModuleID).IsInstalled) { - MoveSettingsForModuleInstanceToTabModuleInstance(module.ModuleID, tabModuleId: module.TabModuleID); + MoveSettingsForModuleInstanceToTabModuleInstance_070011(module.ModuleID, tabModuleId: module.TabModuleID); } } } } } - internal static void MoveSettingsForModuleInstanceToTabModuleInstance(int forumModuleId, int tabModuleId) + internal static void MoveSettingsForModuleInstanceToTabModuleInstance_070011(int forumModuleId, int tabModuleId) { - var currSettings = new SettingsInfo { ModuleId = forumModuleId, MainSettings = Settings.GeneralSettings(forumModuleId, "GEN") }; + var ht = new Hashtable(); + new DotNetNuke.Modules.ActiveForums.Controllers.SettingsController().GetSettingsForModuleIdSettingsKey(forumModuleId, "GEN").ForEach(s => ht.Add(s.SettingName, s.SettingValue)); + var currSettings = new ModuleSettings { ModuleId = forumModuleId, MainSettings = ht }; DotNetNuke.Entities.Modules.ModuleController.Instance.UpdateModuleSetting(tabModuleId, SettingKeys.PageSize, currSettings.PageSize.ToString()); DotNetNuke.Entities.Modules.ModuleController.Instance.UpdateModuleSetting(tabModuleId, SettingKeys.UserNameDisplay, currSettings.UserNameDisplay); diff --git a/Dnn.CommunityForums/components/Topics/TopicsController.cs b/Dnn.CommunityForums/components/Topics/TopicsController.cs index b0f38a840..5fcd1c8c5 100644 --- a/Dnn.CommunityForums/components/Topics/TopicsController.cs +++ b/Dnn.CommunityForums/components/Topics/TopicsController.cs @@ -84,7 +84,7 @@ public int Topics_SaveToForum(int forumId, int topicId, int portalId, int module public override IList GetModifiedSearchDocuments(ModuleInfo moduleInfo, DateTime beginDateUtc) { - var ms = new SettingsInfo { ModuleId = moduleInfo.ModuleID, MainSettings = moduleInfo.ModuleSettings }; + var ms = new ModuleSettings { ModuleId = moduleInfo.ModuleID, MainSettings = moduleInfo.ModuleSettings }; /* if not using soft deletes, remove and rebuild entire index; note that this "internals" method is suggested by blog post (https://www.dnnsoftware.com/community-blog/cid/154913/integrating-with-search-introducing-modulesearchbase#Comment106) and also is used by the Community Links module (https://github.com/DNNCommunity/DNN.Links/blob/development/Components/FeatureController.cs) @@ -325,6 +325,20 @@ public string UpgradeModule(string Version) return "Failed"; } + break; + case "09.02.00": + try + { + ForumsConfig.Install_BadgeNotificationType_090200(); + new ForumsConfig().Install_DefaultBadges_090200(); + } + catch (Exception ex) + { + LogError(ex.Message, ex); + Exceptions.LogException(ex); + return "Failed"; + } + break; default: break; diff --git a/Dnn.CommunityForums/config/defaultsetup.config b/Dnn.CommunityForums/config/defaultsetup.config index 09ddf467b..ef20fcdf0 100644 --- a/Dnn.CommunityForums/config/defaultsetup.config +++ b/Dnn.CommunityForums/config/defaultsetup.config @@ -16,6 +16,8 @@ + + @@ -34,7 +36,7 @@ - + @@ -47,6 +49,19 @@ + + + + + + + + + + + + +