Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
bdd76c7
ENH: Change phrasing of "Subscribe to Topics" to "Auto-Subscribe to M…
johnhenley Sep 18, 2025
5587e2e
Merge pull request #1581 from johnhenley/dev92/subscribe-my-topics-la…
johnhenley Sep 30, 2025
8ebe572
TASK: settings table revamp
johnhenley Sep 23, 2025
18b095c
Merge pull request #1588 from johnhenley/dev92/settings-revamp-1582
johnhenley Sep 30, 2025
7c064c3
FIX: Error moving topic to another forum
johnhenley Oct 8, 2025
a0af7a7
FIX: Error moving topic to another forum
johnhenley Oct 8, 2025
f806635
FIX: Error moving topic to another forum
johnhenley Oct 8, 2025
ba7ffb9
Merge pull request #1595 from johnhenley/dev92/issues/lastpostid-erro…
johnhenley Oct 8, 2025
bc25a89
Fix bad SQL merge in #1595
johnhenley Oct 8, 2025
e82c697
Merge pull request #1596 from johnhenley/dev
johnhenley Oct 8, 2025
ca82261
add some minimal web api endpoint tests (still an issue with POST aut…
johnhenley Sep 23, 2025
9ef8e50
add view models for permissions and forums
johnhenley Sep 23, 2025
ec3428d
settings table revamp
johnhenley Sep 23, 2025
6462694
TASK: Updates for Web API
johnhenley Oct 8, 2025
73f3a0f
Merge pull request #1597 from johnhenley/dev92/webapi/forums-webapi-1548
johnhenley Oct 8, 2025
f1f1f52
Fix typo
johnhenley Oct 8, 2025
6db97d3
resync
johnhenley Oct 8, 2025
b069627
TASK: Correct/standardize user's TopicCount/ReplyCount #1599
johnhenley Oct 9, 2025
8eee7c7
Merge pull request #1600 from johnhenley/dev92/1-topic-reply-counts-1599
johnhenley Oct 10, 2025
866ec27
ENH: Implements user badge feature
johnhenley Jul 8, 2025
d567dde
sync
johnhenley Oct 10, 2025
53b643d
sync
johnhenley Oct 10, 2025
c3d2ebc
Merge branch 'dev92/2-badges-48-427-1479-1480-1481-1482-1483-1484-148…
johnhenley Oct 10, 2025
e3a0549
Merge pull request #1601 from johnhenley/dev92/2-badges-48-427-1479-1…
johnhenley Oct 10, 2025
400c9ba
TASK: Remove colon ":" from SettingsKey
johnhenley Oct 10, 2025
1c4f1f5
TASK: Remove colon ":" from SettingsKey
johnhenley Oct 10, 2025
bf6c4a4
resync
johnhenley Oct 10, 2025
b27ee9e
Merge pull request #1602 from johnhenley/dev92/3-remove-colon-setting…
johnhenley Oct 10, 2025
b4527ea
Encode non-latin characters in content-disposition
LxLasso Oct 12, 2025
88255cb
FIX: Datatables.NET paging
johnhenley Oct 14, 2025
8dd050d
Merge pull request #1609 from johnhenley/dev92/subscriptions-datatabl…
johnhenley Oct 14, 2025
ec58034
Merge pull request #1605 from LxLasso/1604-truncated-filenames
johnhenley Oct 14, 2025
cebe552
FIX: HTML Decode Email notification subject
johnhenley Oct 15, 2025
a9da657
Merge pull request #1611 from johnhenley/dev92/html-topic-email-subje…
johnhenley Oct 15, 2025
207ac12
FIX: Improve script removal
johnhenley Oct 16, 2025
e1907db
Merge branch 'dev' into dev92/forumgroup-permissions-reset-module-set…
johnhenley Oct 17, 2025
6154575
FIX: When saving module settings, only apply social group settings wh…
johnhenley Oct 17, 2025
d1c14fb
Merge pull request #1613 from johnhenley/dev92/social-group-module-se…
johnhenley Oct 17, 2025
ca39a15
FIX: Correct resource key
johnhenley Oct 17, 2025
66884fb
Merge pull request #1614 from johnhenley/dev92/missing-resource-text-…
johnhenley Oct 17, 2025
3fb7756
Merge branch 'dev' into dev92/release-prep-1612
johnhenley Oct 17, 2025
6df4054
TASK: Release Prep
johnhenley Oct 17, 2025
54ef53b
Merge pull request #1615 from johnhenley/dev92/release-prep-1612
johnhenley Oct 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@

<!-- modeled on https://github.com/FritzAndFriends/SharpSite/pull/333 -->

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.
Original file line number Diff line number Diff line change
Expand Up @@ -1483,4 +1483,61 @@ Votre méthode de suppression est actuellement définie sur {0}. Vos sujets ser
<data name="[RESX:Tips:TemplateFileNameSuffix].Text" xml:space="preserve">
<value>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é.</value>
</data>
<data name="[RESX:Description].Text" xml:space="preserve">
<value>Description</value>
</data>
<data name="[RESX:BadgeName].Text" xml:space="preserve">
<value>Insigne</value>
</data>
<data name="[RESX:SortOrder].Text" xml:space="preserve">
<value>Ordre de tri</value>
</data>
<data name="[RESX:Badges].Text" xml:space="preserve">
<value>Badges</value>
</data>
<data name="[RESX:Badge].Text" xml:space="preserve">
<value>Insigne</value>
</data>
<data name="[RESX:BadgeNew].Text" xml:space="preserve">
<value>Nouveau badge</value>
</data>
<data name="[RESX:BadgeThreshold].Text" xml:space="preserve">
<value>Seuil</value>
</data>
<data name="[RESX:BadgeMetric].Text" xml:space="preserve">
<value>Métrique</value>
</data>
<data name="[RESX:BadgeImage].Text" xml:space="preserve">
<value>Image</value>
</data>
<data name="[RESX:BadgeMetricNewUser].Text" xml:space="preserve">
<value>Nouvel utilisateur</value>
</data>
<data name="[RESX:BadgeMetricTopicsCreated].Text" xml:space="preserve">
<value>Sujets créés</value>
</data>
<data name="[RESX:BadgeMetricRepliesCreated].Text" xml:space="preserve">
<value>Réponses aux rubriques</value>
</data>
<data name="[RESX:BadgeMetricLikesReceived].Text" xml:space="preserve">
<value>J’aime reçus</value>
</data>
<data name="[RESX:BadgeMetricTopicsRead].Text" xml:space="preserve">
<value>Sujets lus</value>
</data>
<data name="[RESX:Button:UpdateBadgeUsers].Text" xml:space="preserve">
<value>Mettre à jour les utilisateurs</value>
</data>
<data name="[RESX:BadgeImageMarkup].Text" xml:space="preserve">
<value>Balisage HTML pour badge (par exemple, font-awesome)</value>
</data>
<data name="[RESX:BadgeOneTimeAward].Text" xml:space="preserve">
<value>L’utilisateur ne peut gagner un badge qu’une seule fois</value>
</data>
<data name="[RESX:BadgeIntervalDays].Text" xml:space="preserve">
<value># de jours entre l’obtention de ce badge</value>
</data>
<data name="[RESX:BadgeMetricManual].Text" xml:space="preserve">
<value>Prix du manuel</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -1480,4 +1480,61 @@ Il metodo di rimozione è attualmente impostato su {0}. I tuoi argomenti verran
<data name="[RESX:Tips:TemplateFileNameSuffix].Text" xml:space="preserve">
<value>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.</value>
</data>
<data name="[RESX:Description].Text" xml:space="preserve">
<value>Descrizione</value>
</data>
<data name="[RESX:BadgeName].Text" xml:space="preserve">
<value>Distintivo</value>
</data>
<data name="[RESX:SortOrder].Text" xml:space="preserve">
<value>Ordinamento</value>
</data>
<data name="[RESX:Badges].Text" xml:space="preserve">
<value>Distintivi</value>
</data>
<data name="[RESX:Badge].Text" xml:space="preserve">
<value>Distintivo</value>
</data>
<data name="[RESX:BadgeNew].Text" xml:space="preserve">
<value>Nuovo distintivo</value>
</data>
<data name="[RESX:BadgeThreshold].Text" xml:space="preserve">
<value>Soglia</value>
</data>
<data name="[RESX:BadgeMetric].Text" xml:space="preserve">
<value>Metrico</value>
</data>
<data name="[RESX:BadgeImage].Text" xml:space="preserve">
<value>Immagine</value>
</data>
<data name="[RESX:BadgeMetricNewUser].Text" xml:space="preserve">
<value>Nuovo utente</value>
</data>
<data name="[RESX:BadgeMetricTopicsCreated].Text" xml:space="preserve">
<value>Argomenti creati</value>
</data>
<data name="[RESX:BadgeMetricRepliesCreated].Text" xml:space="preserve">
<value>Risposta agli argomenti</value>
</data>
<data name="[RESX:BadgeMetricLikesReceived].Text" xml:space="preserve">
<value>Mi piace ricevuti</value>
</data>
<data name="[RESX:BadgeMetricTopicsRead].Text" xml:space="preserve">
<value>Argomenti Leggi</value>
</data>
<data name="[RESX:Button:UpdateBadgeUsers].Text" xml:space="preserve">
<value>Aggiorna utenti</value>
</data>
<data name="[RESX:BadgeImageMarkup].Text" xml:space="preserve">
<value>Markup HTML per badge (ad esempio, font-awesome)</value>
</data>
<data name="[RESX:BadgeOneTimeAward].Text" xml:space="preserve">
<value>L'utente può guadagnare il badge una sola volta</value>
</data>
<data name="[RESX:BadgeIntervalDays].Text" xml:space="preserve">
<value># di giorni tra l'ottenimento di questo distintivo</value>
</data>
<data name="[RESX:BadgeMetricManual].Text" xml:space="preserve">
<value>Premio Manuale</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -1630,4 +1630,61 @@ De verwijder-methode is momenteel ingesteld op "{0}". Uw onderwerpen worden {1}
<data name="[RESX:Tips:TemplateFileNameSuffix].Text" xml:space="preserve">
<value>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.</value>
</data>
<data name="[RESX:Description].Text" xml:space="preserve">
<value>Beschrijving</value>
</data>
<data name="[RESX:BadgeName].Text" xml:space="preserve">
<value>Insigne</value>
</data>
<data name="[RESX:SortOrder].Text" xml:space="preserve">
<value>Sorteervolgorde</value>
</data>
<data name="[RESX:Badges].Text" xml:space="preserve">
<value>Badges</value>
</data>
<data name="[RESX:Badge].Text" xml:space="preserve">
<value>Insigne</value>
</data>
<data name="[RESX:BadgeNew].Text" xml:space="preserve">
<value>Nieuwe badge</value>
</data>
<data name="[RESX:BadgeThreshold].Text" xml:space="preserve">
<value>Drempel</value>
</data>
<data name="[RESX:BadgeMetric].Text" xml:space="preserve">
<value>Metriek</value>
</data>
<data name="[RESX:BadgeImage].Text" xml:space="preserve">
<value>Beeld</value>
</data>
<data name="[RESX:BadgeMetricNewUser].Text" xml:space="preserve">
<value>Nieuwe gebruiker</value>
</data>
<data name="[RESX:BadgeMetricTopicsCreated].Text" xml:space="preserve">
<value>Onderwerpen gemaakt</value>
</data>
<data name="[RESX:BadgeMetricRepliesCreated].Text" xml:space="preserve">
<value>Gereageerd op onderwerpen</value>
</data>
<data name="[RESX:BadgeMetricLikesReceived].Text" xml:space="preserve">
<value>Likes ontvangen</value>
</data>
<data name="[RESX:BadgeMetricTopicsRead].Text" xml:space="preserve">
<value>Onderwerpen Lezen</value>
</data>
<data name="[RESX:Button:UpdateBadgeUsers].Text" xml:space="preserve">
<value>Gebruikers bijwerken</value>
</data>
<data name="[RESX:BadgeImageMarkup].Text" xml:space="preserve">
<value>HTML-opmaak voor badge (bijv. lettertype-geweldig)</value>
</data>
<data name="[RESX:BadgeOneTimeAward].Text" xml:space="preserve">
<value>De gebruiker kan slechts één keer een badge verdienen</value>
</data>
<data name="[RESX:BadgeIntervalDays].Text" xml:space="preserve">
<value># dagen tussen het verdienen van deze badge</value>
</data>
<data name="[RESX:BadgeMetricManual].Text" xml:space="preserve">
<value>Handleiding Award</value>
</data>
</root>
57 changes: 57 additions & 0 deletions Dnn.CommunityForums/App_LocalResources/ControlPanel.ascx.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1585,4 +1585,61 @@ Your removal method is currently set to {0}. Your topics will be {1} based upon
<data name="[RESX:Tips:TemplateFileNameSuffix].Text" xml:space="preserve">
<value>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.</value>
</data>
<data name="[RESX:BadgeName].Text" xml:space="preserve">
<value>Badge</value>
</data>
<data name="[RESX:SortOrder].Text" xml:space="preserve">
<value>Sort Order</value>
</data>
<data name="[RESX:Badges].Text" xml:space="preserve">
<value>Badges</value>
</data>
<data name="[RESX:Badge].Text" xml:space="preserve">
<value>Badge</value>
</data>
<data name="[RESX:BadgeNew].Text" xml:space="preserve">
<value>New Badge</value>
</data>
<data name="[RESX:BadgeThreshold].Text" xml:space="preserve">
<value>Threshold</value>
</data>
<data name="[RESX:BadgeMetric].Text" xml:space="preserve">
<value>Metric</value>
</data>
<data name="[RESX:BadgeImage].Text" xml:space="preserve">
<value>Image</value>
</data>
<data name="[RESX:BadgeMetricManual].Text" xml:space="preserve">
<value>Manual Award</value>
</data>
<data name="[RESX:Description].Text" xml:space="preserve">
<value>Description</value>
</data>
<data name="[RESX:BadgeMetricNewUser].Text" xml:space="preserve">
<value>New User</value>
</data>
<data name="[RESX:BadgeMetricTopicsCreated].Text" xml:space="preserve">
<value>Topics Created</value>
</data>
<data name="[RESX:BadgeMetricRepliesCreated].Text" xml:space="preserve">
<value>Replied to Topics</value>
</data>
<data name="[RESX:BadgeMetricLikesReceived].Text" xml:space="preserve">
<value>Likes Received</value>
</data>
<data name="[RESX:BadgeMetricTopicsRead].Text" xml:space="preserve">
<value>Topics Read</value>
</data>
<data name="[RESX:Button:UpdateBadgeUsers].Text" xml:space="preserve">
<value>Update Users</value>
</data>
<data name="[RESX:BadgeImageMarkup].Text" xml:space="preserve">
<value>HTML markup for badge (e.g., font-awesome)</value>
</data>
<data name="[RESX:BadgeOneTimeAward].Text" xml:space="preserve">
<value>User can only earn badge one time</value>
</data>
<data name="[RESX:BadgeIntervalDays].Text" xml:space="preserve">
<value># of days between earning this badge</value>
</data>
</root>
Loading
Loading