diff --git a/README.md b/README.md index c3d2f0d1..e06492fd 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,12 @@ POP Forums A forum and Q&A application with real-time updating, image uploading and private message chat in multiple languages. -The main branch is now the work-in-progress for future versions running on .NET 8+. The v20.x branch is v20.x, running on .NET 7. The v19.x branch is v19.x, running on .NET 6. If you're looking for the version that works on .NET Framework 4.5+ with MVC 5, check out v13.0.2. +The main branch is now the work-in-progress for future versions running on .NET 9+. The v21.x branch is v21.x, running on .NET 9. If you're looking for the version that works on .NET Framework 4.5+ with MVC 5, check out v13.0.2. Roadmap: -The v20 release has a new OAuth-Only mode that allows the forum to run privately with an external identity provider. Much of the rest of the release includes refactoring and more subtle improvements. +v21 is another iterative release, leaning hard into refactoring and a few performance improvements. I've observed fast page rendering, average 20ms on Azure App Service P0v3 and SQL elastic pool at 50 eDTUs and 900k posts. Future versions will consider issues in the backlog. -For the latest information and documentation, and how to get started, check the pages (also in markdown in /docs of source): +For the latest information and documentation, and how to get started, check the pages (also in markdown in `/docs` of source): https://popworldmedia.github.io/POPForums/ Try it out and make test posts here: @@ -32,10 +32,10 @@ Sample app using only the packages: https://github.com/POPWorldMedia/POPForums.Sample ## Prerequisites: -* .NET v8. +* .NET v9. * npm and Node.js to build the front-end. * AzureKit optionally requires Redis for two-level cache, Azure Search for Search. -* AzureKit optionally requires an Azure Storage account for queues and Azure Functions. +* AzureKit optionally requires an Azure Storage account for image storage, queues and Azure Functions. * ElasticKit optionally requires ElasticSearch for search. -* Works great on Windows and Linux. +* Works great on Windows, Mac and Linux. * Build with Visual Studio or JetBrains Rider. diff --git a/docs/_config.yml b/docs/_config.yml index 7635ffde..1e2c40b6 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -2,5 +2,5 @@ remote_theme: just-the-docs/just-the-docs@v0.7.0 aux_links: "POP Forums on GitHub": - "https://github.com/POPWorldMedia/POPForums" -footer_content: "©2024, POP World Media, LLC" +footer_content: "©2025, POP World Media, LLC" title: "POP Forums" diff --git a/docs/customization.md b/docs/customization.md index b57ec578..44d57c2a 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -81,13 +81,14 @@ The MVC project has an interface called `IForumAdapter`, which allows you to gen ``` public class TestAdapter : IForumAdapter { - public void AdaptForum(Controller controller, ForumTopicContainer forumTopicContainer) + public Task AdaptForum(Controller controller, ForumTopicContainer forumTopicContainer) { // not changing anything in the forum (topic list), just set the model as the existing container Model = forumTopicContainer; + return Task.CompletedTask; } - public void AdaptTopic(Controller controller, TopicContainer topicContainer) + public async Task AdaptTopic(Controller controller, TopicContainer topicContainer) { // for the topic (thread) view, let's use the existing model, but add something to the `ViewBag` for the view Model = topicContainer; diff --git a/docs/elastickitlibrary.md b/docs/elastickitlibrary.md index 9aa5ec5d..0593bd3d 100644 --- a/docs/elastickitlibrary.md +++ b/docs/elastickitlibrary.md @@ -5,7 +5,7 @@ nav_order: 7 --- # Using ElasticKit Library The `PopForums.ElasticKit` library makes it possible to wire up the following scenarios: -* Use ElasticSearch for search instead of the built-in search indexing. _Important: The client library referenced in v15.x is designed to work against v6.x of ElasticSearch, while v16.x,v17.x and v18.x, v19.x uses v7.x of ElasticSearch. v20.x uses v8.x of ElasticSearch._ +* Use ElasticSearch for search instead of the built-in search indexing. _Important: The client library referenced in v15.x is designed to work against v6.x of ElasticSearch, while v16.x,v17.x and v18.x, v19.x uses v7.x of ElasticSearch. v20.x and v21.x uses v8.x of ElasticSearch._ ElasticSearch can run quite literally anywhere in a docker container or straight up in a VM, if that's your thing. Also keep in mind that the implementation that AWS uses is actually a fork, so there are some differences about how the managed service is, uh, managed. In the commercial hosted version of POP Forums, we use Elastic's managed service running in Azure. Elastic runs in _all_ of the major clouds and is generally reasonably priced. diff --git a/docs/externalloginconfig.md b/docs/externalloginconfig.md index df2d7d4d..25e941bd 100644 --- a/docs/externalloginconfig.md +++ b/docs/externalloginconfig.md @@ -5,7 +5,7 @@ nav_order: 5 --- # External Login Configuration ->Important: External logins are not the same as OAuth-Only Mode. These are simply a shortcut so your users don't need to remember their forum-specific credentials. They still create an account in the forum. [OAuth-Only Mode](oauthonly.md) relies entirely on an external identity provider and provisions accounts through it. +>Important: External logins are not the same as OAuth-Only Mode. Sometimes referred to as "social logins," these are simply a shortcut so your users don't need to remember their forum-specific credentials. They still create an account in the forum. [OAuth-Only Mode](oauthonly.md) relies entirely on an external identity provider and provisions accounts through it. > > External logins are great for public forums. For corporate or private forums coupled exclusively to an external identity platform, use OAuth-Only Mode. diff --git a/docs/faq.md b/docs/faq.md index 7363ea09..55e836b8 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -8,7 +8,7 @@ nav_order: 3 These are a few of the questions people ask me about the project. Feel free to ask other questions in the [GitHub discussions](https://github.com/POPWorldMedia/POPForums/discussions). If you're thinking it, you're probably not the only one! If you find a defect or want to request a feature, use the issue tracker on GitHub for that, please. ## Do I have to pay for this or not? -Not. POP Forums is an open source software project hosted on GitHub and for use under the MIT license. There is a commercially hosted version available at [PopForums.com](https://popforums.com/), yes, for people who don't write code or don't want to mess with managing their own software. Everything on GitHub continues to be open source. +Not. POP Forums is an open source software project hosted on GitHub for use under the MIT license. There is a commercially hosted version available at [PopForums.com](https://popforums.com/), yes, for people who don't write code or don't want to mess with managing their own software. Everything on GitHub continues to be open source. ## Another forum app? For real? Yeah, I know. I'd like to think that this one is a little different, because it doesn't exist to fit some generalized needs, it exists to fit the needs of real communities, like [CoasterBuzz](https://coasterbuzz.com/). The design goal of the app, from its early days in 1999, has always been to design for users, and not be a science project. This app lives because it has been required for sites like CoasterBuzz for more than two decades, and it will continue to evolve because those sites will evolve. It just makes sense to share it with others. @@ -26,7 +26,7 @@ Currently we have English, Spanish (es), Dutch (nl), Ukrainian (uk), Taiwanese M Not at all. That app served a great many different functions and was integrated with Microsoft ID's, a centralized profiling system, etc. It was/is huge. This app has its roots in the web sites I've been running for fun and profit for years, to the extent that you can find old posts on those sites from the turn of the century with all kinds of formatting failures. Those were the ASP.old days. ## I noticed you're not using [some ORM framework]. Why not? -One of the requirements back in the day was to simply work with the existing data structures of v8.x, a Webforms app. In that sense, the data plumbing was already pretty well established and known to work, and it has followed all the way up through the Core version. My opinion is that ORM's tend to be leaky abstractions that never work in the black box way that you would hope. I have adopted Dapper though, which covers the core use case that you're really after anyway: Mapping parameters to queries and results to objects. One doesn't have to write actual SQL all that often. +One of the requirements back in the day was to simply work with the existing data structures of v8.x, a Webforms app. In that sense, the data plumbing was already pretty well established and known to work, and it has followed all the way up through the Core version. My opinion is that ORM's tend to be leaky abstractions that never work in the black box way that you would hope. I have adopted Dapper though, which covers the core use case that you're really after anyway: Mapping parameters to queries and results to objects. One doesn't have to write actual SQL all that often, so using an ORM doesn't provide a ton of value. ## You don't name your async methods with the `Async` suffix. Just who do you think you are? Look, when almost all of your methods are async with no synchronous version what's the point? The only place I use it is when there are both synchronous and asynchronous methods. Your fancy IDE knows what the return type is, and the compiler lets you know when you're not awaiting. You'll be fine. @@ -38,10 +38,10 @@ I wanted to keep external binaries to a minimum, but I'm using MailKit for email Here's the thing about a forum... it's mostly walls of text. I can tell you from the 60,000+ topics I have indexed on a couple of sites that it's super SEO friendly. To that end, the functionality of a forum is mostly making posts, which doesn't require a big library to do. That's why there are little web components spread around on little islands, and not an all-in effort to React. Heck, the admin area uses Vue.js, but even that works by way of a simple script reference, and no transpiling or bundling. ## The unit tests suck. -That's not a question. In porting to Core, much of the controller-level unit testing didn't come along, and it needs a lot of refactoring. Ideally, there shouldn't be so much logic in the controllers, but there is still a lot there. +That's not a question. In porting to Core, much of the controller-level unit testing didn't come along, and it needs a lot of refactoring. Ideally, there shouldn't be so much logic in the controllers, but there is still some there. ## What's the release roadmap? -It has generally been my intention to keep up with the latest .NET framework versions, which are now reliably annual. You can check the issue tracker for stuff currently in flight. I expect refinement after all of the new features of v19 get some reasonable use, and fewer big bang features. +It has generally been my intention to keep up with the latest .NET framework versions, which are now reliably annual and released later in the year. You can check the issue tracker for stuff currently in flight. While v19 had a lot of big bang features with a large blast radius, that seems less likely going forward. ## Can I contribute? I very much welcome translations of the `.resx` files, so send a pull request for those immediately! If someone really digs into the source code and understands it in a non-trivial way, then yes, I'll happily accept pull requests. If you can find a bug to squish from the issue log, that would be a great PR to see! \ No newline at end of file diff --git a/docs/features.md b/docs/features.md index 1e1bf009..d052b8d4 100644 --- a/docs/features.md +++ b/docs/features.md @@ -28,6 +28,7 @@ nav_order: 1.5 * Restrict posts to certain roles by forum * Edit posts * Localized for English, Spanish, German, Dutch, Ukranian and Taiwanese Mandarin +* Fast page rendering, average 20ms on Azure App Service P0v3 and SQL elastic pool at 50 eDTUs and 900k posts. ## Administration * Your own terms of service diff --git a/docs/index.md b/docs/index.md index 3171213d..8560701a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,11 +5,11 @@ nav_order: 1 --- ![POP Forums logo](https://avatars2.githubusercontent.com/u/8217691?s=200&v=4) -POP Forums v20 is a forum app for ASP.NET (formerly known as Core), used as the base for several sites maintained by the author, as well as a commercial, cloud hosted product. It's a long-term commitment to great community. If you're looking for the commercial hosted product and support for it, go to [popforums.com](https://popforums.com/). +POP Forums v21 is a forum app for ASP.NET (formerly known as Core), used as the base for several sites maintained by the author, as well as a commercial, cloud hosted product. It's a long-term commitment to great community. If you're looking for the commercial hosted product and support for it, go to [popforums.com](https://popforums.com/). _This documentation is for the open source POP Forums project. For documentation about the commercial hosted product, visit [support.popforums.com](https://support.popforums.com/)._ -_If you're working with a version that isn't v20, check the `/docs` folder in the source branch that matches the version you're using._ +_If you're working with a version that isn't v21, check the `/docs` folder in the source branch that matches the version you're using._ Get a load of [all the features](features.md). diff --git a/docs/starthere.md b/docs/starthere.md index 0046bcfe..4c41f897 100644 --- a/docs/starthere.md +++ b/docs/starthere.md @@ -11,9 +11,9 @@ How to use [The Scoring Game](scoringgame.md) in your own application. ## Upgrading? -v20 does not have substantial architectural changes compared to v19. +v21 has breaking changes for using `IForumAdapter`. See [Cusstomization](customization.md) for more information. -This version has data changes. From v19.x, run the `PopForums19to20.sql` script included in the `PopForums.Sql` project. If you need to upgrade from v16.x, v.17x or v18.x, _first_ run the `PopForums16to19.sql` script against your database, which is found in the `PopForums.Sql` project. It's safe to run this script more than once. IMPORTANT: Because of the changes to private messages, you must first also delete all of the existing history by running `DELETE FROM pf_PrivateMessage` against your database. The reason that this isn't included in the upgrade script is because you should know it's necessary and do it on your own. +This version has data changes. From v20.x, run the `PopForums20to21.sql` script included in the `PopForums.Sql` project. If you need to upgrade from v16.x to v20.x, _first_ run the `PopForums16to20.sql` script against your database, which is found in the `PopForums.Sql` project. It's safe to run this script more than once. IMPORTANT: Going from v18 forward, because of the changes to private messages, you must first also delete all of the existing history by running `DELETE FROM pf_PrivateMessage` against your database. The reason that this isn't included in the upgrade script is because you should know it's necessary and do it on your own. Updating your app from the legacy ASP.NET MVC world to ASP.NET Core is non-trivial, and well beyond the scope of this documentation. @@ -45,9 +45,9 @@ For the bleeding edge, latest build from `main`, the CI build packages can be ob ## Build -* Download the latest source code from GitHub, or use the production packages as described above. Build it. +* Clone the latest source code from GitHub, or use the production packages as described above. Build it. * The project files require an up-to-date version of Visual Studio 2022 or later. It also works great with Jetbrains' Rider on Mac or Windows. -* This project is built on ASP.NET v8. Make sure you have the required SDK installed (v8.0.100). +* This project is built on ASP.NET v9. Make sure you have the required SDK installed (v9.0.101). * The `PopForums.Web` project is the template to use to include the forum in your app. It references `PopForums.Mvc`, which contains all of the web app-specific code, including script and CSS. `PopForums.Sql` concerns itself only with data, while `PopForums` works entirely with business logic and defines interfaces used in the upstream projects. `PopForums.AzureKit` contains a number of items to facilitate using various Azure services. `PopForums.ElasticKit` contains an ElasticSearch implementation. `PopForums.AzureKit.Functions` is an implementation of functions, used if you're not using in-app context background services (see below). * The `main` branch is using Azure Functions by default to run background processes. Run the [Azurite](https://github.com/azure/azurite) container in Docker (works on Windows and Mac). If not, you can run the background things in-process by uncommenting `services.AddPopForumsBackgroundServices()` in `Program.cs` and commenting out or removing `services.AddPopForumsAzureFunctionsAndQueues()`. This causes all of the background things to run in the context of the web app itself. @@ -69,7 +69,7 @@ For the bleeding edge, latest build from `main`, the CI build packages can be ob "ConnectionString": "UseDevelopmentStorage=true" // if using AzureKit to host images, typically the same as the Queue:ConnectionString, but the place where images are uploaded to blob storage }, "Database": { - "ConnectionString": "server=localhost;Database=popforums20;Trusted_Connection=True;TrustServerCertificate=True;" + "ConnectionString": "server=localhost;Database=popforums21;Trusted_Connection=True;TrustServerCertificate=True;" }, "Cache": { "Seconds": 180, diff --git a/docs/versionhistory.md b/docs/versionhistory.md index 15ed0ee7..2bc8651e 100644 --- a/docs/versionhistory.md +++ b/docs/versionhistory.md @@ -7,6 +7,22 @@ nav_order: 4 Here's a partial version history that shows how POP Forums has evolved over the years. It's fun to look back at some of the things we now take for granted in a forum app. +## Version v21.0.0 (12/x/24) +* Update IForumAdapter to use async methods (breaking change) #361 +* Clean up naming and organization of Authorization and Authentication bits #377 +* Remove Twitter from profiles #372 +* Migrate to .Net 9 and new libraries #371 +* Refactor in-process background services to run on IHostedService #357 +* Use streams when reading image data from SQL #359 +* Refactor settings caching to make it simple #370 +* BUG: Valid emails are being rejected #367 +* BUG: PopForumsAuthorizationIgnoreAttribute doesn't actually cause middleware to skip user hydration #376 +* BUG: GetUsersByPointTotals won't serialize for caching #358 +* BUG: New PM incorrectly shows as "user not found" #360 +* BUG: URL ending in closing parentheses breaks links #375 +* BUG: Duplicate ForumsUserIDType claim being added to identity in SignalR hub #378 +* BUG: Sequence contains no elements exception thrown in middleware #379 + ## Version v20.0.0 (12/8/23) * Allow option to rely entirely on 3rd-party OAuth2 and OIDC for sign-in #183 * Vote up buttons need an interim state during call #334 diff --git a/src/PopForums.AzureKit.Functions/PopForums.AzureKit.Functions.csproj b/src/PopForums.AzureKit.Functions/PopForums.AzureKit.Functions.csproj index 3ce4a11d..f4ffbdac 100644 --- a/src/PopForums.AzureKit.Functions/PopForums.AzureKit.Functions.csproj +++ b/src/PopForums.AzureKit.Functions/PopForums.AzureKit.Functions.csproj @@ -1,7 +1,7 @@  PopForums AzureKit Functions - 21.0.0-alpha1 + 21.0.0 Jeff Putz net9.0 PopForums.AzureKit.Functions diff --git a/src/PopForums.AzureKit.Functions/local.settings.json b/src/PopForums.AzureKit.Functions/local.settings.json index fd2846a1..b778af5d 100644 --- a/src/PopForums.AzureKit.Functions/local.settings.json +++ b/src/PopForums.AzureKit.Functions/local.settings.json @@ -7,7 +7,7 @@ "PopForums": { "WebAppUrlAndArea": "https://localhost:5091/Forums", "Database": { - "ConnectionString": "server=localhost;Database=popforums20;Trusted_Connection=True;TrustServerCertificate=True;" + "ConnectionString": "server=localhost;Database=popforums21;Trusted_Connection=True;TrustServerCertificate=True;" }, "Search": { "Url": "https://localhost:9200", diff --git a/src/PopForums.AzureKit/PopForums.AzureKit.csproj b/src/PopForums.AzureKit/PopForums.AzureKit.csproj index db8bc3ea..9cd82fe4 100644 --- a/src/PopForums.AzureKit/PopForums.AzureKit.csproj +++ b/src/PopForums.AzureKit/PopForums.AzureKit.csproj @@ -2,7 +2,7 @@ PopForums AzureKit Class Library - 21.0.0-alpha1 + 21.0.0 Jeff Putz net9.0 PopForums.AzureKit diff --git a/src/PopForums.ElasticKit/PopForums.ElasticKit.csproj b/src/PopForums.ElasticKit/PopForums.ElasticKit.csproj index cb1a22ce..e91ef9ca 100644 --- a/src/PopForums.ElasticKit/PopForums.ElasticKit.csproj +++ b/src/PopForums.ElasticKit/PopForums.ElasticKit.csproj @@ -2,7 +2,7 @@ PopForums ElasticKit Class Library - 21.0.0-alpha1 + 21.0.0 Jeff Putz net9.0 PopForums.ElasticKit diff --git a/src/PopForums.Mvc/PopForums.Mvc.csproj b/src/PopForums.Mvc/PopForums.Mvc.csproj index cfc019c8..31140edf 100644 --- a/src/PopForums.Mvc/PopForums.Mvc.csproj +++ b/src/PopForums.Mvc/PopForums.Mvc.csproj @@ -2,7 +2,7 @@ PopForums Mvc Class Library - 21.0.0-alpha1 + 21.0.0 Jeff Putz net9.0 PopForums.Mvc diff --git a/src/PopForums.Sql/PopForums.Sql.csproj b/src/PopForums.Sql/PopForums.Sql.csproj index 403c97bc..deacce8a 100644 --- a/src/PopForums.Sql/PopForums.Sql.csproj +++ b/src/PopForums.Sql/PopForums.Sql.csproj @@ -2,7 +2,7 @@ PopForums.Data.Sql Class Library - 21.0.0-alpha1 + 21.0.0 Jeff Putz net9.0 PopForums.Sql diff --git a/src/PopForums.Sql/PopForums16to19.sql b/src/PopForums.Sql/PopForums16to21.sql similarity index 90% rename from src/PopForums.Sql/PopForums16to19.sql rename to src/PopForums.Sql/PopForums16to21.sql index f94427b5..0f668372 100644 --- a/src/PopForums.Sql/PopForums16to19.sql +++ b/src/PopForums.Sql/PopForums16to21.sql @@ -169,4 +169,23 @@ END IF COL_LENGTH('dbo.pf_QueuedEmailMessage', 'FromEmail') IS NOT NULL BEGIN ALTER TABLE pf_QueuedEmailMessage DROP COLUMN FromEmail; -END \ No newline at end of file +END + + + +IF COL_LENGTH('dbo.pf_PopForumsUser', 'TokenExpiration') IS NULL + BEGIN + ALTER TABLE pf_PopForumsUser ADD [TokenExpiration] [datetime] NULL; + END + +IF COL_LENGTH('dbo.pf_UserActivity', 'RefreshToken') IS NULL + BEGIN + ALTER TABLE pf_UserActivity ADD [RefreshToken] [nvarchar](MAX) NULL; + END + + + +IF COL_LENGTH('dbo.pf_Profile', 'Twitter') IS NOT NULL + BEGIN + ALTER TABLE pf_Profile DROP COLUMN [Twitter]; + END diff --git a/src/PopForums.Test/PopForums.Test.csproj b/src/PopForums.Test/PopForums.Test.csproj index 6c219cc1..917e3425 100644 --- a/src/PopForums.Test/PopForums.Test.csproj +++ b/src/PopForums.Test/PopForums.Test.csproj @@ -1,7 +1,7 @@  - 21.0.0-alpha1 + 21.0.0 net9.0 PopForums.Test PopForums.Test diff --git a/src/PopForums.Web/PopForums.Web.csproj b/src/PopForums.Web/PopForums.Web.csproj index d37cfc8b..cf1fda79 100644 --- a/src/PopForums.Web/PopForums.Web.csproj +++ b/src/PopForums.Web/PopForums.Web.csproj @@ -2,7 +2,7 @@ net9.0 - 21.0.0-alpha1 + 21.0.0 PopForums.Web PopForums.Web diff --git a/src/PopForums.Web/appsettings.json b/src/PopForums.Web/appsettings.json index 28f859cf..580d64c3 100644 --- a/src/PopForums.Web/appsettings.json +++ b/src/PopForums.Web/appsettings.json @@ -13,7 +13,7 @@ "ConnectionString": "UseDevelopmentStorage=true" }, "Database": { - "ConnectionString": "server=localhost;Database=popforums20;Trusted_Connection=True;TrustServerCertificate=True;" + "ConnectionString": "server=localhost;Database=popforums21;Trusted_Connection=True;TrustServerCertificate=True;" }, "Cache": { "Seconds": 180, diff --git a/src/PopForums/PopForums.csproj b/src/PopForums/PopForums.csproj index 1b456025..0dc46243 100644 --- a/src/PopForums/PopForums.csproj +++ b/src/PopForums/PopForums.csproj @@ -2,7 +2,7 @@ PopForums Class Library - 21.0.0-alpha1 + 21.0.0 Jeff Putz net9.0 PopForums