Showing preview only (2,138K chars total). Download the full file or copy to clipboard to get everything.
Repository: POPWorldMedia/POPForums
Branch: main
Commit: 64c16a52cb15
Files: 575
Total size: 1.9 MB
Directory structure:
gitextract_3gvf_42o/
├── .github/
│ └── workflows/
│ └── codeql.yml
├── .gitignore
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── LICENSE.txt
├── NuGet.config
├── PopForums.sln
├── PopForums.sln.DotSettings
├── README.md
├── SECURITY.md
├── docs/
│ ├── _config.yml
│ ├── architecture.md
│ ├── azurekitlibrary.md
│ ├── customization.md
│ ├── elastickitlibrary.md
│ ├── externalloginconfig.md
│ ├── faq.md
│ ├── features.md
│ ├── index.md
│ ├── multitenant.md
│ ├── oauthonly.md
│ ├── scoringgame.md
│ ├── starthere.md
│ └── versionhistory.md
└── src/
├── .editorconfig
├── PopForums/
│ ├── Composers/
│ │ ├── ForumStateComposer.cs
│ │ ├── PrivateMessageStateComposer.cs
│ │ ├── ResourceComposer.cs
│ │ └── TopicStateComposer.cs
│ ├── Configuration/
│ │ ├── Config.cs
│ │ ├── ConfigContainer.cs
│ │ ├── ConfigLoader.cs
│ │ ├── ErrorLog.cs
│ │ ├── ErrorLogException.cs
│ │ ├── ErrorSeverity.cs
│ │ ├── ICacheHelper.cs
│ │ ├── Settings.cs
│ │ └── SettingsManager.cs
│ ├── Email/
│ │ ├── EmailQueuePayload.cs
│ │ ├── EmailQueuePayloadType.cs
│ │ ├── EmailWorker.cs
│ │ ├── ForgotPasswordMailer.cs
│ │ ├── MailingListComposer.cs
│ │ ├── NewAccountMailer.cs
│ │ ├── SmtpStatusCode.cs
│ │ └── SmtpWrapper.cs
│ ├── Extensions/
│ │ ├── ServiceCollections.cs
│ │ ├── Streams.cs
│ │ ├── Strings.cs
│ │ └── Users.cs
│ ├── ExternalLogin/
│ │ ├── ExternalAuthenticationResult.cs
│ │ ├── ExternalLoginInfo.cs
│ │ ├── ExternalUserAssociation.cs
│ │ ├── ExternalUserAssociationManager.cs
│ │ └── ExternalUserAssociationMatchResult.cs
│ ├── Feeds/
│ │ └── FeedService.cs
│ ├── Global.cs
│ ├── Messaging/
│ │ ├── IBroker.cs
│ │ ├── Models/
│ │ │ ├── AwardData.cs
│ │ │ ├── AwardPayload.cs
│ │ │ ├── QuestionData.cs
│ │ │ ├── ReplyData.cs
│ │ │ ├── ReplyPayload.cs
│ │ │ └── VoteData.cs
│ │ ├── Notification.cs
│ │ ├── NotificationAdapter.cs
│ │ ├── NotificationManager.cs
│ │ ├── NotificationTunnel.cs
│ │ └── NotificationType.cs
│ ├── Models/
│ │ ├── AwardCalculationPayload.cs
│ │ ├── BasicJsonMessage.cs
│ │ ├── BasicServiceResponse.cs
│ │ ├── CategorizedForumContainer.cs
│ │ ├── Category.cs
│ │ ├── CategoryContainerWithForums.cs
│ │ ├── ClientPrivateMessagePost.cs
│ │ ├── DisplayProfile.cs
│ │ ├── EmailMessage.cs
│ │ ├── ErrorLogEntry.cs
│ │ ├── ExpiredUserSession.cs
│ │ ├── FeedEvent.cs
│ │ ├── Forum.cs
│ │ ├── ForumPermissionContainer.cs
│ │ ├── ForumPermissionContext.cs
│ │ ├── ForumState.cs
│ │ ├── ForumTopicContainer.cs
│ │ ├── IPHistoryEvent.cs
│ │ ├── IStreamResponse.cs
│ │ ├── Ignore.cs
│ │ ├── ModerationLogEntry.cs
│ │ ├── ModerationType.cs
│ │ ├── ModifyForumRolesContainer.cs
│ │ ├── ModifyForumRolesType.cs
│ │ ├── NewPost.cs
│ │ ├── PagedListOfT.cs
│ │ ├── PagedTopicContainer.cs
│ │ ├── PagerContext.cs
│ │ ├── PasswordResetContainer.cs
│ │ ├── PermanentRoles.cs
│ │ ├── Post.cs
│ │ ├── PostEdit.cs
│ │ ├── PostImage.cs
│ │ ├── PostImagePersistPayload.cs
│ │ ├── PostItemContainer.cs
│ │ ├── PostWithChildren.cs
│ │ ├── PrivateMessage.cs
│ │ ├── PrivateMessageBoxType.cs
│ │ ├── PrivateMessagePost.cs
│ │ ├── PrivateMessageState.cs
│ │ ├── PrivateMessageUser.cs
│ │ ├── PrivateMessageView.cs
│ │ ├── Profile.cs
│ │ ├── QAPostItemContainer.cs
│ │ ├── QueuedEmailMessage.cs
│ │ ├── ReadStatus.cs
│ │ ├── ResponseOfT.cs
│ │ ├── SearchIndexPayload.cs
│ │ ├── SearchType.cs
│ │ ├── SearchWord.cs
│ │ ├── SecurityLogEntry.cs
│ │ ├── SecurityLogType.cs
│ │ ├── ServiceHeartbeat.cs
│ │ ├── SetupVariables.cs
│ │ ├── SignupData.cs
│ │ ├── SingleString.cs
│ │ ├── SubscribeNotificationPayload.cs
│ │ ├── TimeFormats.cs
│ │ ├── Topic.cs
│ │ ├── TopicContainer.cs
│ │ ├── TopicContainerForQA.cs
│ │ ├── TopicState.cs
│ │ ├── TopicUnsubscribeContainer.cs
│ │ ├── User.cs
│ │ ├── UserEdit.cs
│ │ ├── UserEditProfile.cs
│ │ ├── UserEditSecurity.cs
│ │ ├── UserImage.cs
│ │ ├── UserImageApprovalContainer.cs
│ │ ├── UserResult.cs
│ │ ├── UserSearch.cs
│ │ └── VotePostContainer.cs
│ ├── PopForums.csproj
│ ├── Repositories/
│ │ ├── IAwardCalculationQueueRepository.cs
│ │ ├── IAwardConditionRepository.cs
│ │ ├── IAwardDefinitionRepository.cs
│ │ ├── IBanRepository.cs
│ │ ├── ICategoryRepository.cs
│ │ ├── IEmailQueueRepository.cs
│ │ ├── IErrorLogRepository.cs
│ │ ├── IEventDefinitionRepository.cs
│ │ ├── IExternalUserAssociationRepository.cs
│ │ ├── IFavoriteTopicsRepository.cs
│ │ ├── IFeedRepository.cs
│ │ ├── IForumRepository.cs
│ │ ├── IIgnoreRepository.cs
│ │ ├── ILastReadRepository.cs
│ │ ├── IModerationLogRepository.cs
│ │ ├── INotificationRepository.cs
│ │ ├── IPointLedgerRepository.cs
│ │ ├── IPostImageRepository.cs
│ │ ├── IPostImageTempRepository.cs
│ │ ├── IPostRepository.cs
│ │ ├── IPrivateMessageRepository.cs
│ │ ├── IProfileRepository.cs
│ │ ├── IQueuedEmailMessageRepository.cs
│ │ ├── IRoleRepository.cs
│ │ ├── ISearchIndexQueueRepository.cs
│ │ ├── ISearchRepository.cs
│ │ ├── ISecurityLogRepository.cs
│ │ ├── IServiceHeartbeatRepository.cs
│ │ ├── ISettingsRepository.cs
│ │ ├── ISetupRepository.cs
│ │ ├── ISubscribeNotificationRepository.cs
│ │ ├── ISubscribedTopicsRepository.cs
│ │ ├── ITopicRepository.cs
│ │ ├── ITopicViewLogRepository.cs
│ │ ├── IUserAvatarRepository.cs
│ │ ├── IUserAwardRepository.cs
│ │ ├── IUserImageRepository.cs
│ │ ├── IUserRepository.cs
│ │ └── IUserSessionRepository.cs
│ ├── Resources/
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.de.resx
│ │ ├── Resources.es.resx
│ │ ├── Resources.fr.resx
│ │ ├── Resources.nl.resx
│ │ ├── Resources.resx
│ │ ├── Resources.uk.resx
│ │ └── Resources.zh-TW.resx
│ ├── ScoringGame/
│ │ ├── AwardCalculator.cs
│ │ ├── AwardCalculatorWorker.cs
│ │ ├── AwardCondition.cs
│ │ ├── AwardDefinition.cs
│ │ ├── AwardDefinitionService.cs
│ │ ├── EventDefinition.cs
│ │ ├── EventDefinitionService.cs
│ │ ├── EventPublisher.cs
│ │ ├── PointLedgerEntry.cs
│ │ ├── UserAward.cs
│ │ └── UserAwardService.cs
│ └── Services/
│ ├── BanService.cs
│ ├── CategoryService.cs
│ ├── ClaimsToRoleMapper.cs
│ ├── CloseAgedTopicsWorker.cs
│ ├── FavoriteTopicService.cs
│ ├── ForumPermissionService.cs
│ ├── ForumService.cs
│ ├── IPHistoryService.cs
│ ├── ITopicViewCountService.cs
│ ├── IUserRetrievalShim.cs
│ ├── IgnoreService.cs
│ ├── ImageService.cs
│ ├── LastReadService.cs
│ ├── MailingListService.cs
│ ├── ModerationLogService.cs
│ ├── PostImageCleanupWorker.cs
│ ├── PostImageService.cs
│ ├── PostMasterService.cs
│ ├── PostService.cs
│ ├── PrivateMessageService.cs
│ ├── ProfileService.cs
│ ├── QueuedEmailService.cs
│ ├── ReCaptchaService.cs
│ ├── SearchIndexSubsystem.cs
│ ├── SearchIndexWorker.cs
│ ├── SearchService.cs
│ ├── SecurityLogService.cs
│ ├── ServiceHeartbeatService.cs
│ ├── SetupService.cs
│ ├── SitemapService.cs
│ ├── SubscribeNotificationWorker.cs
│ ├── SubscribedTopicsService.cs
│ ├── TenantService.cs
│ ├── TextParsingService.cs
│ ├── TimeFormatStringService.cs
│ ├── TopicService.cs
│ ├── TopicViewLogService.cs
│ ├── UserEmailReconciler.cs
│ ├── UserNameReconciler.cs
│ ├── UserService.cs
│ ├── UserSessionService.cs
│ └── UserSessionWorker.cs
├── PopForums.AzureKit/
│ ├── Logging/
│ │ └── ErrorLogRepository.cs
│ ├── PopForums.AzureKit.csproj
│ ├── PostImage/
│ │ └── PostImageRepository.cs
│ ├── Queue/
│ │ ├── AwardCalculationQueueRepository.cs
│ │ ├── EmailQueueRepository.cs
│ │ ├── SearchIndexQueueRepository.cs
│ │ └── SubscribeNotificationRepository.cs
│ ├── Redis/
│ │ ├── CacheHelper.cs
│ │ ├── CacheTelemetrySink.cs
│ │ └── ICacheTelemetry.cs
│ ├── Search/
│ │ ├── SearchIndexSubsystem.cs
│ │ ├── SearchRepository.cs
│ │ └── SearchTopic.cs
│ └── ServiceCollectionExtensions.cs
├── PopForums.AzureKit.Functions/
│ ├── .gitignore
│ ├── AwardCalculationProcessor.cs
│ ├── BrokerSink.cs
│ ├── CacheHelper.cs
│ ├── CloseAgedTopicsProcessor.cs
│ ├── EmailProcessor.cs
│ ├── NotificationTunnel.cs
│ ├── PopForums.AzureKit.Functions.csproj
│ ├── PostImageCleanupProcessor.cs
│ ├── Program.cs
│ ├── SearchIndexProcessor.cs
│ ├── SubscribeNotificationProcessor.cs
│ ├── UserSessionProcessor.cs
│ └── host.json
├── PopForums.ElasticKit/
│ ├── PopForums.ElasticKit.csproj
│ ├── Search/
│ │ ├── ElasticSearchClientWrapper.cs
│ │ ├── SearchIndexSubsystem.cs
│ │ ├── SearchRepository.cs
│ │ └── SearchTopic.cs
│ └── ServiceCollectionExtensions.cs
├── PopForums.Mvc/
│ ├── Areas/
│ │ └── Forums/
│ │ ├── Authentication/
│ │ │ ├── PopForumsAuthenticationDefaults.cs
│ │ │ ├── PopForumsAuthenticationIgnoreAttribute.cs
│ │ │ └── PopForumsAuthenticationMiddleware.cs
│ │ ├── Authorization/
│ │ │ ├── OAuthOnlyForbidAttribute.cs
│ │ │ ├── PopForumsPrivateForumsFilter.cs
│ │ │ └── PopForumsUserAttribute.cs
│ │ ├── BackgroundJobs/
│ │ │ ├── AwardCalculatorJob.cs
│ │ │ ├── CloseAgedTopicsJob.cs
│ │ │ ├── EmailJob.cs
│ │ │ ├── PostImageCleanupJob.cs
│ │ │ ├── SearchIndexJob.cs
│ │ │ ├── SubscribeNotificationJob.cs
│ │ │ └── UserSessionJob.cs
│ │ ├── Controllers/
│ │ │ ├── AccountController.cs
│ │ │ ├── AdminApiController.cs
│ │ │ ├── AdminController.cs
│ │ │ ├── ApiController.cs
│ │ │ ├── FavoritesController.cs
│ │ │ ├── ForumController.cs
│ │ │ ├── HomeController.cs
│ │ │ ├── IdentityController.cs
│ │ │ ├── IgnoreController.cs
│ │ │ ├── ImageController.cs
│ │ │ ├── ModeratorController.cs
│ │ │ ├── PrivateMessagesController.cs
│ │ │ ├── ResourcesController.cs
│ │ │ ├── SearchController.cs
│ │ │ ├── SetupController.cs
│ │ │ ├── SitemapController.cs
│ │ │ └── SubscriptionController.cs
│ │ ├── Extensions/
│ │ │ ├── ApplicationBuilders.cs
│ │ │ ├── AuthorizationOptionsExtensions.cs
│ │ │ ├── Logger.cs
│ │ │ ├── LoggerFactories.cs
│ │ │ ├── LoggerProvider.cs
│ │ │ ├── ServiceCollections.cs
│ │ │ └── WebApplications.cs
│ │ ├── ForumRouteConstraint.cs
│ │ ├── Messaging/
│ │ │ ├── Broker.cs
│ │ │ ├── PopForumsHub.cs
│ │ │ └── PopForumsUserIdProvider.cs
│ │ ├── Models/
│ │ │ ├── AwardConditionDeleteContainer.cs
│ │ │ ├── EmailUsersContainer.cs
│ │ │ ├── ExternalLoginState.cs
│ │ │ ├── ExternalLoginTypeMetadata.cs
│ │ │ ├── IPHistoryQuery.cs
│ │ │ ├── ManualEvent.cs
│ │ │ ├── SecurityLogQuery.cs
│ │ │ ├── UserEditPhoto.cs
│ │ │ ├── UserEditWithFiles.cs
│ │ │ └── UserState.cs
│ │ ├── Services/
│ │ │ ├── ExternalLoginRoutingService.cs
│ │ │ ├── ExternalLoginTempService.cs
│ │ │ ├── ForumAdapterFactory.cs
│ │ │ ├── IForumAdapter.cs
│ │ │ ├── OAuthOnlyService.cs
│ │ │ ├── TopicViewCountService.cs
│ │ │ ├── UserRetrievalShim.cs
│ │ │ └── UserStateComposer.cs
│ │ ├── TagHelpers/
│ │ │ ├── ForumReadIndicatorTagHelper.cs
│ │ │ ├── PMReadIndicatorTagHelper.cs
│ │ │ ├── PagerLinksTagHelper.cs
│ │ │ ├── TopicReadIndicatorTagHelper.cs
│ │ │ └── ValidationClassTagHelper.cs
│ │ ├── ViewComponents/
│ │ │ ├── UserNavigationViewComponent.cs
│ │ │ └── UserStateViewComponent.cs
│ │ └── Views/
│ │ ├── Account/
│ │ │ ├── AccountCreated.cshtml
│ │ │ ├── Create.cshtml
│ │ │ ├── EditAccountNoUser.cshtml
│ │ │ ├── EditProfile.cshtml
│ │ │ ├── ExternalLogins.cshtml
│ │ │ ├── Forgot.cshtml
│ │ │ ├── Login.cshtml
│ │ │ ├── ManagePhotos.cshtml
│ │ │ ├── MiniProfile.cshtml
│ │ │ ├── MiniUserNotFound.cshtml
│ │ │ ├── OAuthLogin.cshtml
│ │ │ ├── Posts.cshtml
│ │ │ ├── ResetPassword.cshtml
│ │ │ ├── ResetPasswordSuccess.cshtml
│ │ │ ├── Security.cshtml
│ │ │ ├── Unsubscribe.cshtml
│ │ │ ├── UnsubscribeFailure.cshtml
│ │ │ ├── Verify.cshtml
│ │ │ ├── VerifyFail.cshtml
│ │ │ └── ViewProfile.cshtml
│ │ ├── Admin/
│ │ │ └── App.cshtml
│ │ ├── Favorites/
│ │ │ └── Topics.cshtml
│ │ ├── Forum/
│ │ │ ├── Edit.cshtml
│ │ │ ├── Index.cshtml
│ │ │ ├── IndexQA.cshtml
│ │ │ ├── ModeratorPanel.cshtml
│ │ │ ├── NewComment.cshtml
│ │ │ ├── NewReply.cshtml
│ │ │ ├── NewTopic.cshtml
│ │ │ ├── PostItem.cshtml
│ │ │ ├── QAPost.cshtml
│ │ │ ├── Recent.cshtml
│ │ │ ├── Topic.cshtml
│ │ │ ├── TopicPage.cshtml
│ │ │ ├── TopicQA.cshtml
│ │ │ └── Voters.cshtml
│ │ ├── Home/
│ │ │ └── Index.cshtml
│ │ ├── Identity/
│ │ │ ├── ExternalError.cshtml
│ │ │ └── ExternalLoginCallback.cshtml
│ │ ├── Ignore/
│ │ │ └── List.cshtml
│ │ ├── Moderator/
│ │ │ ├── PostModerationLog.cshtml
│ │ │ └── TopicModerationLog.cshtml
│ │ ├── PrivateMessages/
│ │ │ ├── Archive.cshtml
│ │ │ ├── Create.cshtml
│ │ │ ├── Index.cshtml
│ │ │ └── View.cshtml
│ │ ├── Search/
│ │ │ └── Index.cshtml
│ │ ├── Setup/
│ │ │ ├── Exception.cshtml
│ │ │ ├── Index.cshtml
│ │ │ ├── NoConnection.cshtml
│ │ │ └── Success.cshtml
│ │ ├── Shared/
│ │ │ ├── Components/
│ │ │ │ ├── UserNavigation/
│ │ │ │ │ └── Default.cshtml
│ │ │ │ └── UserState/
│ │ │ │ └── Default.cshtml
│ │ │ ├── Forbidden.cshtml
│ │ │ ├── NotFound.cshtml
│ │ │ └── PopForumsMaster.cshtml
│ │ ├── Subscription/
│ │ │ └── Topics.cshtml
│ │ └── _ViewImports.cshtml
│ ├── Client/
│ │ ├── Components/
│ │ │ ├── AnswerButton.ts
│ │ │ ├── CommentButton.ts
│ │ │ ├── FavoriteButton.ts
│ │ │ ├── FormattedTime.ts
│ │ │ ├── FullText.ts
│ │ │ ├── HomeUpdater.ts
│ │ │ ├── LoginForm.ts
│ │ │ ├── MorePostsBeforeReplyButton.ts
│ │ │ ├── MorePostsButton.ts
│ │ │ ├── NotificationItem.ts
│ │ │ ├── NotificationList.ts
│ │ │ ├── NotificationMarkAllButton.ts
│ │ │ ├── NotificationToggle.ts
│ │ │ ├── PMCount.ts
│ │ │ ├── PMForm.ts
│ │ │ ├── PostMiniProfile.ts
│ │ │ ├── PostModerationLogButton.ts
│ │ │ ├── PreviewButton.ts
│ │ │ ├── PreviousPostsButton.ts
│ │ │ ├── QuoteButton.ts
│ │ │ ├── ReplyButton.ts
│ │ │ ├── ReplyForm.ts
│ │ │ ├── SearchNavForm.ts
│ │ │ ├── SubscribeButton.ts
│ │ │ ├── TopicButton.ts
│ │ │ ├── TopicForm.ts
│ │ │ ├── TopicModerationLogButton.ts
│ │ │ └── VoteCount.ts
│ │ ├── Declarations.ts
│ │ ├── ElementBase.ts
│ │ ├── Models/
│ │ │ ├── Notification.ts
│ │ │ ├── PrivateMessage.ts
│ │ │ └── PrivateMessageUser.ts
│ │ ├── Services/
│ │ │ ├── LocalizationService.ts
│ │ │ ├── MessagingService.ts
│ │ │ └── NotificationService.ts
│ │ ├── State/
│ │ │ ├── ForumState.ts
│ │ │ ├── Localizations.ts
│ │ │ ├── PrivateMessageState.ts
│ │ │ ├── TopicState.ts
│ │ │ └── UserState.ts
│ │ ├── StateBase.ts
│ │ ├── WatchPropertyAttribute.ts
│ │ └── tsconfig.json
│ ├── Global.cs
│ ├── PopForums.Mvc.csproj
│ ├── gulpfile.js
│ ├── package.json
│ └── wwwroot/
│ ├── Admin.js
│ ├── Editor.css
│ └── PopForums.css
├── PopForums.Sql/
│ ├── CacheHelper.cs
│ ├── Extensions.cs
│ ├── Global.cs
│ ├── ISqlObjectFactory.cs
│ ├── JsonElementTypeHandler.cs
│ ├── PopForums.Sql.csproj
│ ├── PopForums.sql
│ ├── PopForums13to14.sql
│ ├── PopForums14to15.sql
│ ├── PopForums15to16.sql
│ ├── PopForums16to21.sql
│ ├── PopForums19to20.sql
│ ├── PopForums20to21.sql
│ ├── PopForums21to22.sql
│ ├── Repositories/
│ │ ├── AwardCalculationQueueRepository.cs
│ │ ├── AwardConditionRepository.cs
│ │ ├── AwardDefinitionRepository.cs
│ │ ├── BanRepository.cs
│ │ ├── CategoryRepository.cs
│ │ ├── EmailQueueRepository.cs
│ │ ├── ErrorLogRepository.cs
│ │ ├── EventDefinitionRepository.cs
│ │ ├── ExternalUserAssociationRepository.cs
│ │ ├── FavoriteTopicsRepository.cs
│ │ ├── FeedRepository.cs
│ │ ├── ForumRepository.cs
│ │ ├── IgnoreRepository.cs
│ │ ├── LastReadRepository.cs
│ │ ├── ModerationLogRepository.cs
│ │ ├── NotificationRepository.cs
│ │ ├── PointLedgerRepository.cs
│ │ ├── PostImageRepository.cs
│ │ ├── PostImageTempRepository.cs
│ │ ├── PostRepository.cs
│ │ ├── PrivateMessageRepository.cs
│ │ ├── ProfileRepository.cs
│ │ ├── QueuedEmailMessageRepository.cs
│ │ ├── RoleRepository.cs
│ │ ├── SearchIndexQueueRepository.cs
│ │ ├── SearchRepository.cs
│ │ ├── SecurityLogRepository.cs
│ │ ├── ServiceHeartbeatRepository.cs
│ │ ├── SettingsRepository.cs
│ │ ├── SetupRepository.cs
│ │ ├── SubscribeNotificationRepository.cs
│ │ ├── SubscribedTopicsRepository.cs
│ │ ├── TopicRepository.cs
│ │ ├── TopicViewLogRepository.cs
│ │ ├── UserAvatarRepository.cs
│ │ ├── UserAwardRepository.cs
│ │ ├── UserImageRepository.cs
│ │ ├── UserRepository.cs
│ │ └── UserSessionRepository.cs
│ ├── SqlObjectFactory.cs
│ └── StreamResponse.cs
├── PopForums.Test/
│ ├── Composers/
│ │ ├── ForumStateComposerTests.cs
│ │ ├── PrivateMessageStateComposerTests.cs
│ │ └── TopicStateComposerTests.cs
│ ├── Configuration/
│ │ └── SettingsTests.cs
│ ├── Email/
│ │ ├── EmailWorkerTests.cs
│ │ └── NewAccountMailerTests.cs
│ ├── Extensions/
│ │ └── StringTests.cs
│ ├── ExternalLogin/
│ │ └── ExternalUserAssociationManagerTests.cs
│ ├── Global.cs
│ ├── Messaging/
│ │ ├── NotificationAdapterTests.cs
│ │ └── NotificationManagerTests.cs
│ ├── Models/
│ │ ├── ForumHomeContainerTests.cs
│ │ ├── UserEditSecurityTests.cs
│ │ └── UserTest.cs
│ ├── Mvc/
│ │ ├── Authorization/
│ │ │ └── PopForumsPrivateForumsFilterTests.cs
│ │ ├── Controllers/
│ │ │ ├── AccountControllerTests.cs
│ │ │ └── AdminApiControllerTests.cs
│ │ └── Services/
│ │ └── OAuthOnlyServiceTests.cs
│ ├── PopForums.Test.csproj
│ ├── ScoringGame/
│ │ ├── AwardCalculatorTests.cs
│ │ ├── AwardCalculatorWorkerTests.cs
│ │ ├── AwardDefinitionServiceTests.cs
│ │ ├── EventDefintionServiceTests.cs
│ │ ├── EventPublisherTests.cs
│ │ ├── FeedServiceTests.cs
│ │ └── UserAwardServiceTests.cs
│ └── Services/
│ ├── BanServiceTests.cs
│ ├── CategoryServiceTests.cs
│ ├── ClaimsToRoleMapperTests.cs
│ ├── CloseAgedTopicsWorkerTests.cs
│ ├── FavoriteTopicServiceTests.cs
│ ├── ForumPermissionServiceTests.cs
│ ├── ForumServiceTests.cs
│ ├── ImageServiceTests.cs
│ ├── LastReadServiceTests.cs
│ ├── PostImageCleanupWorkerTests.cs
│ ├── PostImageServiceTests.cs
│ ├── PostMasterServiceTests.cs
│ ├── PostServiceTests.cs
│ ├── PrivateMessageServiceTests.cs
│ ├── ProfileServiceTests.cs
│ ├── QueuedEmailServiceTests.cs
│ ├── SearchIndexWorkerTests.cs
│ ├── SearchServiceTests.cs
│ ├── SecurityLogServiceTests.cs
│ ├── SetupServiceTests.cs
│ ├── SitemapServiceTests.cs
│ ├── SubscribeNotificationWorkerTests.cs
│ ├── SubscribedTopicsServiceTests.cs
│ ├── TextParsingServiceCleanForumCodeTests.cs
│ ├── TextParsingServiceClientHtmlToForumCodeTests.cs
│ ├── TextParsingServiceForumCodeToHtmlTests.cs
│ ├── TextParsingServiceOtherTests.cs
│ ├── TopicServiceTests.cs
│ ├── TopicViewLogServiceTests.cs
│ ├── UserEmailReconcilerTests.cs
│ ├── UserNameReconcilerTests.cs
│ ├── UserServiceTests.cs
│ ├── UserSessionServiceTests.cs
│ └── UserSessionWorkerTests.cs
└── PopForums.Web/
├── Controllers/
│ └── HomeController.cs
├── PopForums.Web.csproj
├── Program.cs
├── Properties/
│ └── launchSettings.json
├── Views/
│ ├── Home/
│ │ └── Index.cshtml
│ ├── Shared/
│ │ └── _Layout.cshtml
│ ├── _ViewImports.cshtml
│ └── _ViewStart.cshtml
└── appsettings.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/codeql.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Advanced"
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '18 0 * * 5'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: actions
build-mode: none
- language: csharp
build-mode: none
- language: javascript-typescript
build-mode: none
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
# - name: Setup runtime (example)
# uses: actions/setup-example@v1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
================================================
FILE: .gitignore
================================================
packages
/.vs/config
/.vs
/*.user
*.user
.idea
.idea/.idea.PopForums/.idea
.idea/.idea.PopForums/riderModule.iml
.DS_Store
bin
obj
packages
*.pubxml
node_modules
src/PopForums.AzureKit.Functions/Properties/ServiceDependencies
src/PopForums.Mvc/wwwroot/lib/*
src/PopForums.Mvc/wwwroot/PopForums.js
src/PopForums.Mvc/package-lock.json
src/PopForums.Mvc/node_modules
src/PopForums.Web/Areas/Forums
/src/PopForums.Web/appsettings.development.json
/src/PopForums.AzureKit.Functions/local.settings.dev.json
/.claude
.claude/settings.local.json
================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
POP Forums is an ASP.NET Core forum and Q&A application targeting .NET 10. It uses SignalR for real-time updates, TypeScript for front-end components, and SQL Server as the primary data store.
## Solution Structure
| Project | Purpose |
|---|---|
| `PopForums` | Core business logic, service interfaces, repository interfaces, models |
| `PopForums.Sql` | SQL Server data access implementations, caching layer, migrations scripts |
| `PopForums.Mvc` | ASP.NET MVC area (`/Forums`), controllers, views, TypeScript client, CSS |
| `PopForums.Web` | Host app template — references above projects, contains `Program.cs` |
| `PopForums.AzureKit` | Azure-specific implementations: Redis cache, Azure Search, Blob Storage, queues |
| `PopForums.AzureKit.Functions` | Azure Functions implementations for background jobs |
| `PopForums.ElasticKit` | ElasticSearch search implementation |
| `PopForums.Test` | xUnit tests using NSubstitute, covers services and some MVC code |
## Build Commands
### .NET
```bash
# Build entire solution
dotnet build PopForums.sln
# Run all tests
dotnet test src/PopForums.Test/PopForums.Test.csproj
# Run a single test class
dotnet test src/PopForums.Test/PopForums.Test.csproj --filter "FullyQualifiedName~PostMasterServiceTests"
# Run a single test method
dotnet test src/PopForums.Test/PopForums.Test.csproj --filter "FullyQualifiedName~PostMasterServiceTests.SomeMethodName"
```
### Front-end asset setup (run once from `src/PopForums.Mvc/`)
```bash
npm install
npx gulp copies # copy node_modules assets (Bootstrap, SignalR, TinyMCE, Vue, etc.) to wwwroot/lib
npx gulp css # minify CSS
```
TypeScript compilation is handled automatically by `Microsoft.TypeScript.MSBuild` as part of the .NET build — no manual `tsc` or `gulp ts` needed. The Mvc project's static assets (JS, CSS, fonts) are embedded into the NuGet package and served to the host app via `StaticWebAssetBasePath=/PopForums`. The app itself is run from `PopForums.Web`, not `PopForums.Mvc`.
## Running Locally
The `PopForums.Web` project is the host application. Key setup steps:
1. Set the connection string in `appsettings.json` under `PopForums:Database:ConnectionString` (default looks for a local SQL Server DB named `popforums21`)
2. First run: navigate to `/Forums/Setup` to initialize the database and admin account (don't run the SQL script manually before this)
3. Background jobs: by default `Program.cs` uses `AddPopForumsAzureFunctionsAndQueues()`. For local development without Azure, switch to `AddPopForumsBackgroundJobs()` (in-process)
### Docker services for local dev
```bash
# SQL Server (ARM: azure-sql-edge; x86: mssql/server:2022-latest)
docker run --cap-add SYS_PTRACE -e 'ACCEPT_EULA=1' -e 'MSSQL_SA_PASSWORD=P@ssw0rd' -p 1433:1433 --name sqledge -d mcr.microsoft.com/azure-sql-edge
# Azurite (storage + queues)
docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite
# Redis (distributed cache / SignalR backplane)
docker run --name some-redis -p 6379:6379 -d redis
# ElasticSearch
docker run --name es-9 -p 9200:9200 -e discovery.type=single-node -it docker.elastic.co/elasticsearch/elasticsearch:9.3.0
```
## Architecture Patterns
### Layered dependency direction
`PopForums.Mvc` → `PopForums` (interfaces) ← `PopForums.Sql` (implementations)
- `PopForums` defines all repository interfaces (`IForumRepository`, `IPostRepository`, etc.) in `Repositories/` and service classes in `Services/`
- `PopForums.Sql` implements those repository interfaces with SQL Server + Dapper-style access
- Services depend on repository interfaces; they never touch SQL directly
- `PopForums.AzureKit` and `PopForums.ElasticKit` swap in alternative implementations via DI extension methods
### DI registration pattern
Each library exposes extension methods on `IServiceCollection`:
- `services.AddPopForumsSql()` — registers SQL repos and in-memory cache
- `services.AddPopForumsMvc()` — registers MVC services, auth, and base forum services
- `services.AddPopForumsRedisCache()` — overrides cache with Redis two-level cache
- `services.AddPopForumsElasticSearch()` / `services.AddPopForumsAzureSearch()` — override search
- `services.AddPopForumsAzureFunctionsAndQueues()` — routes background work to Azure queues
- `services.AddPopForumsBackgroundJobs()` — runs background jobs in-process (local dev)
### MVC Area
All forum routes are under the `Forums` area. Controllers live in `src/PopForums.Mvc/Areas/Forums/Controllers/`. The area is mapped via `app.AddPopForumsEndpoints()`.
### Background jobs
Background tasks (email, search indexing, award calculation, session cleanup, etc.) are implemented as `BackgroundService` derivatives. In production, these run as Azure Functions via `PopForums.AzureKit.Functions`. In-process mode is available for single-node or local use.
### Front-end
- No SPA framework for the main forum UI — raw TypeScript components in `Client/Components/`
- Components extend `ElementBase.ts` and use a simple state engine in `State/`
- SignalR connects on page load; components react to hub messages for real-time updates
- Vue.js + Vue Router are used **only** for the admin interface
- Localization on the client side uses a JSON payload from the server; see `FormattedTime.ts` for an example
### Testing
- Tests are in `PopForums.Test`, mirroring the folder structure of the projects under test
- Mocking via NSubstitute; test framework is xUnit
- Tests focus on service layer; controller and repository coverage is minimal
## Database
- Initial schema: `src/PopForums.Sql/PopForums.sql`
- Migration scripts follow the pattern `PopForumsXXtoYY.sql` in `src/PopForums.Sql/`
- From v21.x to v22.x, run `PopForums21to22.sql`
- Statistics (post counts, etc.) are precomputed at write time rather than aggregated at query time
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at jeff@popw.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
================================================
FILE: LICENSE.txt
================================================
POP Forums
Copyright (c)1999-2023, POP World Media, LLC and Jeffrey M. Putz
https://popw.com/
https://jeffputz.com/
TRANSLATIONS PROVIDED BY:
Spanish: Mauricio Atanache
Dutch: Steven van Deursen
Ukrainian: Nazar Harasym
German: Manfred Theis
Taiwanese Mandarin: Cheng Liu
MIT LICENSE:
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.
OTHER LICENSES:
NSubstitute: BSD 3-Clause
.NET Core, ASP.NET Core, Bootstrap, popper.js, MailKit, TinyMCE: MIT
SignalR, xunit: Apache 2.0
ImageSharp: Apache 2.0 as long as you meet the open source and/or revenue stipulations
indicated in their license: https://github.com/SixLabors/ImageSharp/blob/main/LICENSE
================================================
FILE: NuGet.config
================================================
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<activePackageSource>
<add key="All" value="(Aggregate source)" />
</activePackageSource>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="pi-prerelease" value="https://www.myget.org/F/popidentity/api/v3/index.json" />
</packageSources>
<disabledPackageSources>
<add key="prerelease" value="true" />
</disabledPackageSources>
<packageSourceCredentials>
</packageSourceCredentials>
</configuration>
================================================
FILE: PopForums.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.156
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{044AC2DE-7D9D-4C1A-8C83-38AF448B5A61}"
ProjectSection(SolutionItems) = preProject
.gitignore = .gitignore
CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
LICENSE.txt = LICENSE.txt
NuGet.config = NuGet.config
README.md = README.md
CLAUDE.md = CLAUDE.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PopForums.Web", "src\PopForums.Web\PopForums.Web.csproj", "{78900BC9-3B9B-42C1-9112-8412A7AACFB7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PopForums", "src\PopForums\PopForums.csproj", "{1787FE89-F023-482E-ABBA-996554DD332D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PopForums.Sql", "src\PopForums.Sql\PopForums.Sql.csproj", "{229CDD35-A4A5-44F2-8937-61AB286D6A77}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PopForums.Test", "src\PopForums.Test\PopForums.Test.csproj", "{AB4006F4-F457-490B-B9FC-8DE9CDA67127}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PopForums.AzureKit", "src\PopForums.AzureKit\PopForums.AzureKit.csproj", "{C3E4460C-E785-4FF4-AFAF-07AF2EA8812D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PopForums.Mvc", "src\PopForums.Mvc\PopForums.Mvc.csproj", "{0AE33580-28F6-41CB-B757-56E02394F645}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PopForums.ElasticKit", "src\PopForums.ElasticKit\PopForums.ElasticKit.csproj", "{20986460-15F5-4C08-BAE2-226F12B1CB23}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PopForums.AzureKit.Functions", "src\PopForums.AzureKit.Functions\PopForums.AzureKit.Functions.csproj", "{D50E69CC-5070-41DD-A881-20D29B1913EE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CI|Any CPU = CI|Any CPU
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{78900BC9-3B9B-42C1-9112-8412A7AACFB7}.CI|Any CPU.ActiveCfg = Release|Any CPU
{78900BC9-3B9B-42C1-9112-8412A7AACFB7}.CI|Any CPU.Build.0 = Release|Any CPU
{78900BC9-3B9B-42C1-9112-8412A7AACFB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{78900BC9-3B9B-42C1-9112-8412A7AACFB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{78900BC9-3B9B-42C1-9112-8412A7AACFB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{78900BC9-3B9B-42C1-9112-8412A7AACFB7}.Release|Any CPU.Build.0 = Release|Any CPU
{1787FE89-F023-482E-ABBA-996554DD332D}.CI|Any CPU.ActiveCfg = Release|Any CPU
{1787FE89-F023-482E-ABBA-996554DD332D}.CI|Any CPU.Build.0 = Release|Any CPU
{1787FE89-F023-482E-ABBA-996554DD332D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1787FE89-F023-482E-ABBA-996554DD332D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1787FE89-F023-482E-ABBA-996554DD332D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1787FE89-F023-482E-ABBA-996554DD332D}.Release|Any CPU.Build.0 = Release|Any CPU
{229CDD35-A4A5-44F2-8937-61AB286D6A77}.CI|Any CPU.ActiveCfg = Release|Any CPU
{229CDD35-A4A5-44F2-8937-61AB286D6A77}.CI|Any CPU.Build.0 = Release|Any CPU
{229CDD35-A4A5-44F2-8937-61AB286D6A77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{229CDD35-A4A5-44F2-8937-61AB286D6A77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{229CDD35-A4A5-44F2-8937-61AB286D6A77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{229CDD35-A4A5-44F2-8937-61AB286D6A77}.Release|Any CPU.Build.0 = Release|Any CPU
{AB4006F4-F457-490B-B9FC-8DE9CDA67127}.CI|Any CPU.ActiveCfg = Debug|Any CPU
{AB4006F4-F457-490B-B9FC-8DE9CDA67127}.CI|Any CPU.Build.0 = Debug|Any CPU
{AB4006F4-F457-490B-B9FC-8DE9CDA67127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB4006F4-F457-490B-B9FC-8DE9CDA67127}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB4006F4-F457-490B-B9FC-8DE9CDA67127}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB4006F4-F457-490B-B9FC-8DE9CDA67127}.Release|Any CPU.Build.0 = Release|Any CPU
{C3E4460C-E785-4FF4-AFAF-07AF2EA8812D}.CI|Any CPU.ActiveCfg = Debug|Any CPU
{C3E4460C-E785-4FF4-AFAF-07AF2EA8812D}.CI|Any CPU.Build.0 = Debug|Any CPU
{C3E4460C-E785-4FF4-AFAF-07AF2EA8812D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3E4460C-E785-4FF4-AFAF-07AF2EA8812D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3E4460C-E785-4FF4-AFAF-07AF2EA8812D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3E4460C-E785-4FF4-AFAF-07AF2EA8812D}.Release|Any CPU.Build.0 = Release|Any CPU
{0AE33580-28F6-41CB-B757-56E02394F645}.CI|Any CPU.ActiveCfg = Debug|Any CPU
{0AE33580-28F6-41CB-B757-56E02394F645}.CI|Any CPU.Build.0 = Debug|Any CPU
{0AE33580-28F6-41CB-B757-56E02394F645}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0AE33580-28F6-41CB-B757-56E02394F645}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0AE33580-28F6-41CB-B757-56E02394F645}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0AE33580-28F6-41CB-B757-56E02394F645}.Release|Any CPU.Build.0 = Release|Any CPU
{20986460-15F5-4C08-BAE2-226F12B1CB23}.CI|Any CPU.ActiveCfg = Debug|Any CPU
{20986460-15F5-4C08-BAE2-226F12B1CB23}.CI|Any CPU.Build.0 = Debug|Any CPU
{20986460-15F5-4C08-BAE2-226F12B1CB23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{20986460-15F5-4C08-BAE2-226F12B1CB23}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20986460-15F5-4C08-BAE2-226F12B1CB23}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20986460-15F5-4C08-BAE2-226F12B1CB23}.Release|Any CPU.Build.0 = Release|Any CPU
{D50E69CC-5070-41DD-A881-20D29B1913EE}.CI|Any CPU.ActiveCfg = Debug|Any CPU
{D50E69CC-5070-41DD-A881-20D29B1913EE}.CI|Any CPU.Build.0 = Debug|Any CPU
{D50E69CC-5070-41DD-A881-20D29B1913EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D50E69CC-5070-41DD-A881-20D29B1913EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D50E69CC-5070-41DD-A881-20D29B1913EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D50E69CC-5070-41DD-A881-20D29B1913EE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DC971413-E75E-4D0A-8189-B71EE5DBAED1}
EndGlobalSection
EndGlobal
================================================
FILE: PopForums.sln.DotSettings
================================================
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PM/@EntryIndexedValue">PM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PMID/@EntryIndexedValue">PMID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QA/@EntryIndexedValue">QA</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sitemap/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
================================================
FILE: README.md
================================================

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 10+. The v22.x branch is v22.x, running on .NET 10. If you're looking for the version that works on .NET Framework 4.5+ with MVC 5, check out v13.0.2.
Roadmap:
v22 is another iterative release, with the biggest feature being an ignore list. I've observed fast page rendering, average 19ms 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):
https://popworldmedia.github.io/POPForums/
CI build of main runs here:
https://popforumsdev.azurewebsites.net/Forums
[](https://dev.azure.com/popw/POP%20Forums/_build/latest?definitionId=13)
Latest release:
https://github.com/POPWorldMedia/POPForums/releases/tag/v22.0.0
Packages available on NuGet.
The latest CI build packages can be found with these feeds on MyGet:
https://www.myget.org/F/popforums/api/v3/index.json
Sample app using only the packages:
https://github.com/POPWorldMedia/POPForums.Sample
## Prerequisites:
* .NET v10.
* 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 image storage, queues and Azure Functions.
* ElasticKit optionally requires ElasticSearch for search.
* Works great on Windows, Mac and Linux.
* Build with Visual Studio or JetBrains Rider.
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ----------- | ------------------ |
| 17.x | :white_check_mark: |
| 17.99.0.x | :x: |
| < 17.0 | :x: |
## Reporting a Vulnerability
If you find something suboptimal, add an issue to the Github project.
================================================
FILE: docs/_config.yml
================================================
remote_theme: just-the-docs/just-the-docs@v0.10.1
aux_links:
"POP Forums on GitHub":
- "https://github.com/POPWorldMedia/POPForums"
footer_content: "©2025, POP World Media, LLC"
title: "POP Forums"
================================================
FILE: docs/architecture.md
================================================
---
layout: default
title: Architecture
nav_order: 2.5
---
# POP Forums Architecture
Forums are a text-driven medium intended to enable communication between people. To that end, the design philosophy behind POP Forums has always been to keep the interface simple, and not fill the screen with interface elements that don't serve that philosophy. Things that you don't need are hidden by default. Conversation comes first. Peripheral concerns include search engine optimisation, performance and maintainability.
As an open source project, intended first to be used in community sites like [CoasterBuzz](https://coasterbuzz.com/), its evolution is not perfect, or even ideal, but it does represent two decades of refinement. Some parts are pretty cool, others desperately need to be refactored. No pull request will be ignored!
## Data structure
POP Forums was originally written using SQL Server as a data store, but the data access bits are contained entirely in the `PopForums.Sql` project. An enterprising developer could easily port this to any of the technologies supported by the .Net ecosystem (which is to say, all of them). This library also contains a basic caching layer, leveraging in-memory cache. It is seeded by a single SQL script, `PopForums.sql`. This is the basic configuration, and it works fine for light duty use on cheap hardware, virtual or otherwise.
To facilitate scaling, caching can be delegated to Redis, using the `PopForums.AzureKit` library. (Instructions are found in the [Using AzureKit Library](azurekitlibrary.md) section.) This employs a two-level cache that combines the use of Redis and local memory. The app will first attempt to retrieve data from local memory, and if it's not available, it will attempt to retrieve it from Redis. If it's not available there, it will fetch from SQL and then cache that data as apporopriate. This also enables the use of multiple nodes by using the message bus in Redis. When the local cache needs to be invalidated on the other nodes, a message is sent to them via the bus. I didn't invent this pattern, but saw it on a Stack Overflow blog post.
The basic search functionality is performed by building an enormous table of words, then matching and scoring them for results. The algorithm to index the words is not efficient, but this too works fine for light duty use. Using the `PopForums.ElasticKit` library enables, wait for it, the use of ElasticSearch. No need to invent something, because Elastic does this really well. (Instructions are found in the [Using ElasticKit Library](elastickitlibrary.md) section.) This is a more robust solution that can scale to larger forums, and it can be used in conjunction with the Redis caching layer.
There is a bit of what I call "precomputing" of statistics, because it doesn't make sense to be doing aggregate counts via SQL queries. For example, the post count on a topic is incremented or decremented at the time a post is added or (soft) deleted.
## Background Processing
A number of different tasks are necessarily performed asynchronously:
* Award Calculation
* Close Aged Topics
* Email
* Post Image Cleanup
* Search Indexing
* Subscribe Notifications
* User Session Cleanup
The default implementation uses jobs registered as derivatives of `Microsoft.Extensions.Hosting.BackgroundService`. This works fine in a single-node environment, and most of the actions are not resource intensive, save for the search indexing (regardless of using the base search or Elastic).
The solution for that is to encapsulate the jobs as Azure Functions. These are fantastic in a production situation because you'll literally spend pennies a month on them, while not impacting the resources of your web nodes. If you run on Azure, this is a no-brainer.
## Image Handling
Out of the box, POP Forums stores post images in the database. Streaming those bytes out of SQL Server all the way to the browser is reasonably efficient, but the memory cost is not zero. The advantage of this arrangement is that the forum is very portable, as you can export the database to a `.bacpac` file and restore it, with images, anywhere. User avatars and images are also stored this way.
For scale, especially if you pay for your database by the bit, it may be preferable to store post images in Azure Blob Storage. If you're using Azure Functions, you'll already need a storage account for the background queues. This too is configured using the `PopForums.AzureKit` library, saving images to a public blob container. This means that you could also use a CDN, if you're really nuts about performance.
Because a user might upload an image but not submit the post, a cleanup job is run to remove images that are not associated with a post.
## Scaling POP Forums
The above options allow you to greatly scale the application. Because the app uses ASP.NET's authorization and authentication, running multiple nodes requires a shared data protection key. This is outlined elsewhere and set in the `Program.cs` startup.
Using the CoasterBuzz database as a reference, three Azure Web App instances, running on P0v3 Linux machines, backed by a 50 DTU SQL database, can handle 1,000 requests per minute without issue. I haven't tested with higher loads and configurations, but it's not clear that either would be a bottleneck running at higher levels.
## The Web Application
All of the web app code is contained in the `PopForums.Mvc` project, which also references the base `PopForums` and `PopForums.Sql` libraries, and the above-mentioned libraries as necessary for scale. The assets, including all of the CSS and transpiled TypeScript, are also shipped in the `Mvc` library. This makes it really easy to update the forum bits in your own application, without having to replace a bunch of loose files. Update the package, and you're done.
The app leverages ASP.NET's SignalR for real-time communication with the server via web sockets, including notifications of new posts, updating the forum and topic grids, new private messages, etc.
In accordance with the simple design philosophy, the web app does not use any specific front-end library, aside from Vue.js, which is used for the admin interface. Again, the intent is to produce search engine friendly markup without a web of dependencies and npm packages. That doesn't mean that there isn't any rich interactivity, because a number of small, raw elements are written in TypeScript. They live in `PopForums.Mvc/Client`. Along with a few small service classes and a simple state engine, "reactive" elements are updated when a notification comes in via web sockets.
While server-side localization is straight forward enough, the client-side bits use a small JSON payload apply the right language to the interface. For example, the use of time words varies by language, so the `FormattedTime.ts` component uses those strings for "5 minutes ago" or whatever the right variant is.
## Unit Testing
The unit test suite is rough, because there are parts of the app that have not been refactored from an earlier state. A few of the service classes look like dumping grounds, and many do too many things. That makes writing tests for those retroactively difficult, and likely unnecessary if they'll eventually be refactored anyway. You'll also find code in the controllers that likely doesn't belong there. Again, this is after two decades of change. Like any good project, it will never be "done."
================================================
FILE: docs/azurekitlibrary.md
================================================
---
layout: default
title: Using Azure Kit Library
nav_order: 6
---
# Using AzureKit Library
The `PopForums.AzureKit` library makes it possible to wire up the following scenarios:
* Using Redis for caching (not dependent on Azure specifically... Redis runs everywhere!)
* Using Azure Storage queues and Functions to queue work for search indexing, emailing and scoring game award calculation
* Using Azure Storage for image uploads
* Using Azure Search
* Using Azure Storage for hosting uploaded images in posts
* Using Azure Table Storage for error logging
You don't need to use the AzureKit components to run in an Azure App Service. These components are intended for making scale-out possible. The web app can run self-contained in a single node on an Azure App Service without these optional bits.
## Configuration with Azure App Services and Azure Functions
The POP Forums configuration system uses the typical configuration files, but adhere's to the overriding system implemented via environment variables. This by extension means that you can set these values in the Application Settings section of the Azure portal for App Services and Functions. It uses the colon notation that you may be familiar with. For example, use `PopForums:Queue:ConnectionString` to correspond to the hierarchy of the `appsettings.json file`. (For Linux-based App Services and Functions in Azure, use a double underscore instead of colons in the portal settings, i.e., `PopForums__Queue__ConnectionString`.)
## Irrelevant settings when using Azure Functions
Once you get the background stuff out of the web app context, some of the configuration options in the admin are no longer applicable.
* In email: The sending interval and mailer quantity no longer matter, because the functions only respond when there's something in the queue, and scale as necessary. You may need to limit the number of instances via host.json or the Azure portal if your email service provider throttles your email delivery.
* In search: The search indexing interval only reacts when something is queued (like email). Furthermore, if you use Azure Search or ElasticSearch, the junk words no longer apply, as these indexing strategies are handled by the appropriate service.
* In scoring game: The interval is again irrelevant because of the queue.
## Running locally
You can almost run everything in this stack locally. Here's the breakdown:
* Redis is easy to run locally using a Docker container: `docker run -p 6379:6379 -d redis`
* Azure Storage (for queues) can be simulated locally running [Azurite](https://github.com/azure/azurite) on Windows or Mac (the Azure Storage Emulator has been deprecated). Run this in a Docker container with `docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite`
* Azure Functions CLI runs on Windows and Mac.
* Azure Search only runs in Azure.
* ElasticSearch can run in a Docker container.
## Setting locale in Azure Functions
Since Azure Functions do not run as a normal web app, listening to the locale of the user's web browser, it defaults to whatever Azure decides is default, probably `en-US` in a lot of places. For some of the functions that are generating notifications, this matters, because you might be serving a Spanish-speaking audience and want them to get notifications in that language.
To set the language in a function, add the following to those function methods in one of the supported languages:
```
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("es");
```
## Using Redis for caching
Redis is a great tool for caching data for a stand-alone instance of the app or between many nodes. The default caching provided by the `PopForms.Sql` implementation uses in-memory cache in the app instance itself, which doesn't work when you have many nodes (that is, several web heads running behind a load balancer, like a scaled-out Azure App Service). Redis helps by caching data in a "neutral" location between these nodes.
To use Redis (which is available all over the place, and _not_ just in Azure), use the following configuration lines in your ASP.NET `Program.cs`:
```
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
...
services.AddPopForumsRedisCache();
services.AddSignalR().AddRedisBackplaneForPopForums();
...
```
The first line configures the app to use the Redis caching mechanism. Under the hood, this replaces the `PopForums.Sql` implementation of `ICacheHelper` with the one found in `PopForums.AzureKit`. The second line adds `AddRedisBackplaneForPopForums()` to the configuration of SignalR, so that websocket messages back to the browser are funneled to clients regardless of which web node they're connected to. For example, a user can make a post connected to one node, and the message to update the recent topics page will be signaled to update for users on every node.
You'll also need to setup some values in the `appsettings.json` configuration file (or equivalents in your Azure App Service configuration):
```
{
"PopForums": {
"Cache": {
"Seconds": 180,
"ConnectionString": "127.0.0.1:6379,abortConnect=false",
"ForceLocalOnly": false
},
...
```
* `Seconds`: The number of seconds to persist data in the cache.
* `ConnectionString`: The connection string to the Redis instance.
* `ForceLocalOnly`: When set to true, the app will not use Redis, just local memory. This might be useful if you scale down to one node and no longer need Redis, but don't want to redeploy, for example. Obviously don't set to true if you're running more than one node.
This version of `ICacheHelper` is actually a two-level cache. The data is stored locally in the instance memory of the web app, as well as Redis, because it's still faster if it can avoid calling over the wire. Invalidation of data is handled over Redis' built-in communication channels. So if you update something with a particular cache key, Redis will notify all nodes to invalidate any local value they have. Because it's a two-level cache, you might find that your Redis stats seem not to be active, and when it is being called, it's usually a miss. That's because it doesn't have to go to the Redis instance itself, since the value is already in local memory.
The Azure functions do _not_ use caching. The data that is fetched by the functions is typically transient, not cached or not likely to be.
If you want to prefix cache keys with a specific string, you can do that by using the dependency injection to replace the default `ITenantService` and implementing its `GetTenant()` method. The default implementation simply returns an empty string. See [Multi-tenant options](multitenant.md) for more information.
To run Redis locally, consider using Docker. It only takes a few minutes to setup. Use the Google to figure that out.
## Instrumenting Redis and cache usage
Most managed Redis services have ways to generally observe the behavior and health of the service, but you might be interested in going deeper. For example, the default TTL for caching on all of POP Forums is 90 seconds, but that might not be the "right" amount of time. Also, because this implementation is a two-level cache, monitoring Redis alone doesn't give you the complete picture. POP Forums has an interface called `ICacheTelemetry` in this library, with a default interface that is just an event sink. If you use an external monitoring service like Azure Insights, you may want to replace this with your own implementation. It's super easy! The interface only has two members:
```
void Start();
void End(string eventName, string key);
```
The Redis implementation of `CacheHelper` wraps each call to the memory cache and Redis with the above methods. It includes the cache key and the type of event (`SetRedis`, `GetRedisHit`, `GetRedisMiss`, etc.) for you to persist in whatever your monitoring solution is. In the [hosted forums](https://popforums.com/), we use the following to write the events to Azure Insights. The `TelemetryClient` comes in via dependency injection:
```
public class WebCacheTelemetry : ICacheTelemetry
{
private readonly TelemetryClient _telemetryClient;
private Stopwatch _stopwatch;
public WebCacheTelemetry(TelemetryClient telemetryClient)
{
_telemetryClient = telemetryClient;
}
public void Start()
{
_stopwatch = new Stopwatch();
_stopwatch.Start();
}
public void End(string eventName, string key)
{
_stopwatch.Stop();
var dependencyTelemetry = new DependencyTelemetry();
dependencyTelemetry.Name = eventName;
dependencyTelemetry.Properties.Add("Key", key);
dependencyTelemetry.Duration = new TimeSpan(_stopwatch.ElapsedTicks);
dependencyTelemetry.Type = "CacheOp";
_telemetryClient.TrackDependency(dependencyTelemetry);
}
}
```
Then, to wire up this new implementation, we swap out the event sink for our code in `Program.cs`:
`services.Replace(ServiceDescriptor.Transient<ICacheTelemetry, WebCacheTelemetry>());`
## Using Azure Storage queues and Functions
Azure Storage queues can be used instead of using SQL tables. Using SQL for this is not inherently bad, and honestly the volume of queued things in POP Forums probably never gets huge even on a busy forum, but with queues you get some of the magic of triggering Azure Functions, for example. These are most logically used when you have functions.
To enable queue usage, use this in your `Program.cs` config:
```
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
...
services.AddPopForumsAzureFunctionsAndQueues();
...
```
It's important to _not_ have `services.AddPopForumsBackgroundServices();` in your `Program.cs`, because this would run the background services in the context of the web app. You don't want that, because you're going to run them in Azure Functions.
You'll also need to add a connection string to your Azure Storage account and web app service base. These values must appear in the configuration of your web app _and_ Azure Functions.
```
{
"PopForums": {
"WebAppUrlAndArea": "https://somehost/Forums",
"Queue": {
"ConnectionString": "DefaultEndpointsProtocol=https;AccountName=youraccountname;AccountKey=xxxYourAccountKeyxxx=="
...
```
Look at the Azure documentation to see how to provision and deploy Azure Functions, and apply that new knowledge to deploy the `PopForums.AzureKit.Functions` project. (Defining Azure Functions is beyond the scope of this documentation.) You should avoid committing any connection secrets to configuration in source control. See the section above about configuration, and make sure that your Functions have the same settings as your web app.
The `WebAppUrlAndArea` is used to point the functions back at your web app to notify them as necessary and have them in turn notify users in real-time. The URL should end without a slash, and probably ends in `/Forums` unless you changed the name of the area throughout the code. Behind the scenes, the award calculator uses this to call an endpoint on the web app and let it know that a user has received an award. For security, it uses a hash of the queue connection string, _which must be the same for the web app and the functions_.
The connection string for using the local Azure storage emulator is `UseDevelopmentStorage=true`.
## Using Azure Search
_Note: v18+ breaks compatibility with previous indexes using Azure Search._
Use this in your `Program.cs` configuration if you're using web in-process search indexing:
```
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
...
services.AddPopForumsAzureSearch();
...
```
Under the hood, this replaces the `PopForums.Sql` implementation of the search interfaces with those used for Azure Search.
For use in the Azure functions, you'll need to set the `PopForums:Search:Provider` (or `PopForums__Search__Provider` if it's Linux-based) setting in the portal blade for the functions to `azuresearch`.
You'll also need to setup the right configuration values:
```
{
"PopForums": {
"Search": {
"Url": "https://somesearchservice.search.windows.net",
"Key": "99011A70D3D50D251B0A6141A97B40E7",
"Provider": ""
},
```
* `Url`: The URL for Azure Search, typically `https://{nameOfSearchService}.search.windows.net` with the name set in the Azure portal
* `Key`: A key provisioned by the portal to connect to Azure Search
* `Provider`: This is only used in `PopForums.AzureKit.Functions`, where it's used to switch between `elasticsearch`, `azuresearch` and the default bits in the `PopForums.Sql` library. _Important: If the value is left blank, the Azure Functions will use the SQL-based search provider._
## Using Azure storage for hosting uploaded images in posts
The default implementation for uploading images into forum posts is to upload them into the database. While this is convenient and super portable, it may not be the least expensive option, since database storage is typically more expensive than other means. To that end, you can use `AzureKit` to upload and host the images in an Azure storage container.
There are a few configuration values you'll need:
```
"PopForums": {
"BaseImageBlobUrl": "http://127.0.0.1:10000/devstoreaccount1",
"Storage": {
"ConnectionString": "UseDevelopmentStorage=true"
},
```
* `BaseImageBlobUrl`: The base URL for the storage where images are uploaded. For local development, using the Azurite storage emulator, this is `http://127.0.0.1:10000/devstoreaccount1`. For a typical Azure storage account, it's probably something like `https://mystorageaccount.blob.core.windows.net`. It should *not* end with a slash, and it shouldn't end with the container name, since that's added in the repository code. In the event you have to move the images for some reason, it's ideal if you could alias a domain name that you own to the storage account.
* `ConnectionString`: It's assumed that you're going to use the same storage account as your queues, but regardless, you need to specify the connection string here. You need this in the web app *and* the functions app.
The code will create a container called `postimage` in your storage account, but if you plan to use the public endpoints of the storage account (instead of a CDN), make sure that `Allow blob public access` is enabled for the account, and then when the container is created, it will be created with the `Blob` access level, meaning anyone can access the images, but they can't see the directory or otherwise manipulate the storage account.
Your web app will need to register the right implementation for the `IPostImageRepository`, and this is achieved in your startup/program with this line in the service configuration:
```
using PopForums.AzureKit;
...
services.AddPopForumsAzureBlobStorageForPostImages();
```
It's important to note that `PopForums.AzureKit.Functions` is already wired to use the blob storage `IPostImageRepository` version, because it's assumed that if you're already using an Azure queue, you also have a storage account.
Another thing to keep in mind is that if you're working locally, and your Azurite instance doesn't have `https` configured, it will break because most browsers do not allow non-`https` images to appear in a secure page. The simplest work around for this is not to install a local certificate, but to change your launch settings for the web app to not run on `https`.
## Using Azure Table Storage for error logging
You may prefer to do your error logging to Azure Table Storage instead of the SQL database. You can do this by adding one line to your `Program` file, which swaps out the SQL error repository for the table storage:
```
services.AddPopForumsTableStorageLogging();
```
The one limitation here is that you can't use the admin UI to look at errors, since paging and ordering is fairly crude in table storage. For the connection string, it will use whatever is found in `PopForums:Storage:ConnectionString`, the same setting used by the image uploads.
================================================
FILE: docs/customization.md
================================================
---
layout: default
title: Customization
nav_order: 2.5
---
# Customization
POP Forums is fairly easy to customize to make it your own. And please, make it your own, because the default Bootstrap style is pretty boring.
## Style
POP Forums uses [Bootstrap](https://getbootstrap.com/) for its base style. We're big fans of the library because it really does provide a solid starting point and mature components that feel like the _lingua franca_ of web user interfaces. It's also super easy to customize it to your liking with relatively little effort.
### The basic layout that hosts the forum
The basic page that we include in the main and sample repositories is fairly sparse:
```
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewBag.Title</title>
@await RenderSectionAsync("HeaderContent", false)
</head>
<body>
<div class="container">
@RenderBody()
</div>
</body>
</html>
```
You'll notice that after the `title` tags, we render a section called `HeaderContent`. This is where the forum drops in all of its `script` and `link` references for Javascript and CSS. If you want to go deeper, look in the `PopForums.Mvc` project at `/Areas/Forums/Views/Shared/PopForumsMaster.csthml`.
### Style overrides
One simple approach to customizing the look is to include a style sheet, linked in the template header _after_ Bootstrap. So given the template shown above, you would include your `link` tag to your CSS after the `RenderSectionAsync` call. Mostly, your CSS will consist of things like font selection and colors on high-level elements. For example, given that you've imported fonts elsewhere:
```
body {
font-family: 'Roboto Slab', 'Times New Roman', serif;
font-size: 16px;
}
nav, h1, h2, h3, h4, h5, small, .small, .btn, .breadcrumb {
font-family: 'Open Sans Condensed', Helvetica, Arial, sans-serif;
font-weight: 700;
}
a, a:visited, a:hover, .btn-link {
color: red;
text-decoration: underline;
}
```
If you wanted to override something specific in Bootstrap, like adding a big border to buttons, you would have to make sure you apply an `!important` designation.
```
.btn {
border: solid 2px #000000 !important;
}
```
### Bootstrap replacement
You can also use your own Bootstrap build and go crazy with customization on the variables. There are great pre-built themes to download from [Bootswatch](https://bootswatch.com/), and [Bootstrap Build](https://bootstrap.build/) has a hassle-free way to customize everything and output a ready-to-use build of Bootstrap. Of course, you can get the [Bootstrap source](https://github.com/twbs/bootstrap) and modify any of the variables or `SCSS` files and build your own, if you like.
To use your own Bootstrap build from any of the methods above, first you have to turn off the rendering of the default Bootstrap included in the `PopForums.Mvc` package. To do so, you'll need to change the `appsettings.json`:
```
{
"PopForums": {
"RenderBootstrap": false,
...
```
With that taken care of, considering the template above, add references to your built Bootstrap CSS _and_ script _before_ you render the header content:
```
<script src="~/pathToMyBootstrap/bootstrap.bundle.js" asp-append-version="true"></script>
<link href="~/pathToMyBootstrap/bootstrap.min.css" rel="stylesheet" asp-append-version="true" />
@await RenderSectionAsync("HeaderContent", false)
```
## Forum adapters
The MVC project has an interface called `IForumAdapter`, which allows you to generate your own view model for a topic, typically with new or augmented data. When a forum adapter is configured in the admin of the app (on a per-forum basis), it uses the code in that configured adapter to render a specific view (typically in the `Views/Shared` folder of your app) and the model the adapter specifies. Consider the following:
```
public class TestAdapter : IForumAdapter
{
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 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;
// now get the "extra"
var resolver = controller.HttpContext.RequestServices;
var scoreService = (IScoreService)resolver.GetService(typeof(IScoreService));
var highScore = scoreService.GetHighScore();
controller.ViewBag.HighScore = highScore;
// use Shared/ScoreTopic.cshtml for the view
ViewName = "ScoreTopic";
}
...
```
Now a different view will be rendered, and it might look something like this:
```
@model PopForums.Models.TopicContainer
<h1>High score: @ViewBag.HighScore</h1>
@foreach(var post in Model.Posts) {
// render posts from the model
```
This is super flexible, but not without a lot of work. You're highjacking the model from a page like `/Forums/Topic/some-topic`, replacing it with your own, then rendering your own view.
To light one of these up, you'll have to go to the admin -> Forums -> Edit, and in the bottom field, labeled `Forum Adapter (optional, use "Namespace.Type, AssemblyName")`, you should enter what it's asking for. So if the fully qualified name of your adapter is `MyLibrary.MyForumAdapter` in the `MyLibrary` assembly, you would put `MyLibrary.MyForumAdapter, MyLibrary` here.
================================================
FILE: docs/elastickitlibrary.md
================================================
---
layout: default
title: Using ElasticKit Library
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 and v21.x uses v8.x of ElasticSearch. v22.x uses v9.x of ElasticSearch. For prior versions, please see the `docs` folder in those branches. Configuration is significantly different for >=v22.1, and is a breaking change._
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.
## Configuration with Azure App Services and Azure Functions
The POP Forums configuration system uses the `appsettings.json` file, but adhere's to the overriding system implemented via environment variables. This by extension means that you can set these values in the Application Settings section of the Azure portal for App Services and Functions. It uses the colon notation that you may be familiar with. For example, use `PopForums:Queue:ConnectionString` to correspond to the hierarchy of the `appsettings.json` file. (For Linux-based App Services and Functions in Azure, use a double underscore instead of colons in the portal settings, i.e., `PopForums__Queue__ConnectionString`.)
## Irrelevant admin settings when using ElasticKit
* In search: The search indexing interval only reacts when something is queued for in-Web processing, not Azure Functions. Furthermore, if you use ElasticSearch, the junk words no longer apply, as these indexing strategies are handled by ES.
## Using ElasticSearch for search
ElasticSearch is a search engine you can run on your own or in managed services from AWS, Elastic and others. To use this service instead of the internal POP Forums search indexing, you'll need to configure this line in your `Program.cs` if you're using web in-process search processing:
```
using PopForums.ElasticKit;
...
namespace YourWebApp;
...
services.AddPopForumsElasticSearch();
```
For use in the Azure functions, you'll need to set the `PopForums:Search:Provider` (or `PopForums__Search__Provider` on a Linux instance) setting in the portal blade for the functions to `elasticsearch` (see `Provider` config below).
You'll also need to setup the right configuration values if you're running web in-process:
```
{
"PopForums": {
"Search": {
"Url": "https://myelasticsearchindex",
"Key": "",
"Provider": ""
},
```
* `Url`: The base URL for the ElasticSearch endpoints. If you're using managed ES from Elastic, this is the "ElasticSearch Copy endpoint" result in the portal.
* `Key`: This is the API key.
* `Provider`: This is optional in the web app and not actually implemented anywhere other than in our Azure Functions example project, where it's used to switch between `elasticsearch`, `azuresearch` and the default bits in the `PopForums.Sql` library.
Configuring ElasticSearch and setting up security rules for it are beyond the scope of this wiki.
================================================
FILE: docs/externalloginconfig.md
================================================
---
layout: default
title: External Login Configuration
nav_order: 5
---
# External Login Configuration
>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.
Starting in v16, POP Forums is completely decoupled from the Identity libraries that verify user identity via third party services, including Google, Facebook and Microsoft. We already don't use Identity because it's so tightly coupled to Entity Framework, with strong opinions about how to store user data. Identity also requires that you configure it at app start (or restart if you change it), and it can't be changed at request time. That prevents a multi-tenancy scenario from working. It was time to cut the cord.
We spun off the [PopIdentity](https://github.com/POPWorldMedia/POPIdentity) project to be a lightweight, non-opinionated means to do the necessary round trips to identity providers and just give you the data that you want, mostly the ID, name and email of the user. It does not bake the identity into a `Principal` for general use. Check out the sample project there for more information.
In POP Forums, you can go to the External Logins page of the admin area and configure Google, Facebook, Microsoft and any generic OAuth2 provider that returns JWT's. Check the box, fill in the client ID and secret from the providers. For each, you'll need to specify the callback URL. These are configured:
* In Facebook's developer administration, under the "Facebook Login" and "Products" navigation at left.
* In the Google Cloud Console, drill down to "Credentials" under "API's and Services."
* In Microsoft's Azure portal, search for "Azure Active Directory," choose "App Registrations," choose or create your app, then under "Authentication" enter your redirect URL.
The format for the URL is this, substituting in your domain: `https://whateveryourdomainis/Forums/Identity/CallbackHandler`
WARNING: That URL might be case sensitive in some services. Use the caps in "Forums" and such, because that's how the app will generate the URL.
Once configured, you'll see buttons on the login page for each service you've enabled.
There's also one for any other OAuth2 provider that returns JWT's. For that option, you'll need to fill in the URL's for the base login URL (POP Forums will append the appropriate query string) and token fetching URL (again, we'll handle the query string).
================================================
FILE: docs/faq.md
================================================
---
layout: default
title: FAQ
nav_order: 3
---
# Frequently Asked Questions
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 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.
## Sounds like you've been doing this a long time.
Yes, I sometimes feel cursed to rewrite it for all eternity. The Webforms versions were really kind of a mess, and no version was a true rewrite. Once MVC came along, it gave me great incentive to start fresh. Dotnet Core and the evolving front-end frameworks give plenty of new opportunities for refactoring.
## Is this project the basis for the commercial hosted product?
Yes, it's the very same code, though obviously decorated with additional code to facilitate multi-tenancy and provisioning.
## What languages are supported?
Currently we have English, Spanish (es), Dutch (nl), Ukrainian (uk), Taiwanese Mandarin (zh-TW) and German (de). If you'd like to translate, the .resx file has around 400 entries. Open an issue to learn more, and we can talk about a pull request to add another language.
## You used to work on the forums for MSDN and TechNet. Is this that forum?
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, 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.
## What external frameworks are you using, and why?
I wanted to keep external binaries to a minimum, but I'm using MailKit for email functions, ImageSharp for photo resizing, NSubstitute for test mocking, and xUnit for unit testing. On the front end, the main app uses vanilla web components written in TypeScript, along with Bootstrap and TinyMCE. The admin area uses Vue.js. Github has that handy dependency graph now that you can look at for more information.
## What? You're not using React?
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 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 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!
================================================
FILE: docs/features.md
================================================
---
layout: default
title: Features
nav_order: 1.5
---
# Features
## Classic forum functionality
* Categories, forums, topics, oh my!
* Optional Q&A-style threading
* Direct message, real-time chat between users
* Upload photos or embed external images
* Automatically embed YouTube videos
* Selectively quote previous posts
* Real-time notifications in-app
* Rich text editing
* Avatars and signatures, mutable by users ("hide vanity")
* Recent topics across all forums
* User profiles with links to social networks
* Save your favorite topics, subscribe automatically to new post notifications
* Mark individual or all forums read
* Jump to the newest post
* Real-time updating with new posts
* Continuous scroll topics
* Vote up and recognize posts
* Automatic adjustments to display local times
* Private forums
* Restrict posts to certain roles by forum
* Edit posts
* Ignore users
* 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
* Adjust number of topics and posts per page
* Restrict size of uploaded images and YouTube video size
* Automatically close topics after days of inactivity
* External (social) logins
* External identity (All-OAuth mode) that relies on your OAuth/OIDC provider, ideal for enterprise.
* View detailed security logs
* Limit posts by time interval in seconds
* View all recent user sign-ups
* Error logging and viewing
* Monitor last run of background services
* Edit users
* Email all users
* Set topic/post page size
## Moderation
* All-private, sign-up required option
* E-mail confirmed sign-ups
* CAPTCHA check
* Parse out naughty words
* Assign users to custom roles, limit viewing and posting to those roles by forum
* Approve profile photos
* Ban e-mail and IP addresses
* Edit and soft delete posts, with history
* Close, pin, move, soft or hard delete topics
* View moderation logs
================================================
FILE: docs/index.md
================================================
---
layout: default
title: Home
nav_order: 1
---

POP Forums v22 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 v22, check the `/docs` folder in the source branch that matches the version you're using._
Get a load of [all the features](features.md).
Make test posts and try it out here:
https://meta.popforums.com/Forums
The project goals include:
* Use ASP.NET Core and cloud resources for robust scale-out.
* Keep the project open source.
* Be the best and fastest ASP.NET Core-based forum.
* Not duplicate UBB's 1998 UI for the Nth time.
* Localize: Now available in English, Spanish, German, Ukrainian, Dutch and Taiwanese Mandarin.
More information:
* [FAQ](faq.md)
* [Architecture](architecture.md)
* [POP Forums Version History](versionhistory.md)
* [CI build from `main` in action](https://popforumsdev.azurewebsites.net/Forums)
* Follow more on [Jeff's blog](https://jeffputz.com/) (may contain autism advocacy and politics)
Setup:
To set it up, check the installation instructions in the [Start Here](starthere.md) section.
POP Forums v13 for ASP.NET MVC 5 is also available as a previous release.
Do you speak English and another language? We want to make POP Forums globally useful. Since v9.2, the app is easily localized. Volunteers have translated to Spanish, Dutch, Ukrainian, Taiwanese Mandarin and German, and we'd love help for additional languages. Drop Jeff an e-mail to jeff@popw.com for more information.
Found a bug? Add it to the issue tracker.
================================================
FILE: docs/multitenant.md
================================================
---
layout: default
title: Multi-tenant options
nav_order: 8
---
# Multi-tenant options
POP Forums has some plumbing for multi-tenancy, originally created to facilitate the [cloud-hosted version of POP Forums](https://popforums.com/). However, there are some tricks here that you can rely on for shared resource scenarios.
# Using `ITenantService`
The core library defines `ITenantService` and provides a basic implementation. It has two methods, `SetTenant(string tenantID)` and `GetTenant()`. The former throws a `NotImplementedException` and is not called by any of the code in this repository. It's there for you to use in a true multi-tenant environment. The latter is used all over the place, and the default implementation returns an empty string.
# Example: Sharing an instance of ElasticSearch
Let's say that we have three different sites running their own copy of POP Forums, each with their own database, in a shared pool in Azure. Having multiple databases doesn't cost you anything extra in this scenario, but if you're using managed ElasticSearch hosted by Elastic (also in Azure), you may want to share a single instance. Like many of the resources in POP Forums, the code in [`PopForums.ElasticKit`](elastickitlibrary.md) makes sure to store and query data with a `TenantID`. By default, this doesn't matter, because the ID is just a blank string.
To share this resource, create an implementation for each of your apps. You'll implement just the `GetTenant()` method:
```
public class TenantService : ITenantService
{
public void SetTenant(string tenantID)
{
throw new System.NotImplementedException();
}
public string GetTenant()
{
return "mytenantid"; // unique for every app
}
}
```
Then, in your `Program.cs` file, swap out the default implementation for your own. If you're using Azure Functions with [`PopForums.AzureKit`](azurekitlibrary.md), be sure to do it in the function project's `Program.cs` as well:
```
services.Replace(ServiceDescriptor.Transient<ITenantService, MyApp.TenantService>());
```
In our ElasticSearch scenario, the indexer will store the ID with every document, and searches will filter by it.
# What uses `TenantID`?
It's a long list that is best explored in the source code by finding usages of the `GetTenant()` method, but here's a non-exhaustive list:
Core libraries:
* All of the queue messaging. That means you'll find a TenantID in the code that dequeues the messages (primarily Azure Functions).
* SignalR plumbing, so clients listening for notifications, for example, are unique to the tenant.
In `PopForums.AzureKit`:
* `IPostImageRepository` (used in naming blobs for image storage)
* All of the Redis bits, so you can share a Redis instance.
In `PopForums.ElasticKit`:
* All of the ElasticSearch bits, see example above.
================================================
FILE: docs/oauthonly.md
================================================
---
layout: default
title: OAuth-Only Mode
nav_order: 2.7
---
# OAuth-Only Mode
>Important: OAuth-Only Mode relies entirely on an external identity provider and provisions accounts through it. [External logins](externalloginconfig.md) are not the same as OAuth-Only Mode. Those are simply a shortcut so your users don't need to remember their forum-specific credentials. They still create an account in the forum.
>
> External logins are great for public forums. For corporate or private forums coupled exlcusively to an external identity platform, use OAuth-Only Mode.
Starting in v20, POP Forums has an OAuth-only mode, which means that user authenticaton is handled entirely by a third party. Examples include OAuth providers of corporate identity systems, like Azure Active Directory, Keycloak, Okta and Auth0. In this mode, users can't create an account in the forum, they can only come in via the external identity provider. The assignment of moderator and admin roles are mapped from claims issued by the identity provider.
> This mode is set at the configuration level (`appsettings.json` locally, or the typical environment variables in regular environments). There are consequences for changing this setting to `true` in an established instance of the forum. Existing users would not be mapped to identities from the external provider. Going the other direction would be possible, though each user would need to reset their password with the email address used by the identity system.
If you don't have a basic understanding of how OAuth works, now's a good time to do a little research. Here's how this mode works in the forum:
* The user can only access a page with a single login button.
* Clicking that button sends the user to the external identity provider.
* The user enters credentials with the provider if they aren't already logged in. You've likely done this before with "social" logins like Google or Facebook.
* The identity provider redirects the user back to the forum, with a JWT token.
* The forum calls the identity provider's token endpoint with the provided token and verifies its authenticity.
* In return, the identity provider returns information about the user called _claims_.
* The forum checks to see if there's a user account associated with the unique identifier from the provider (given in the `sub` claim). If there is no account, it's created with the provided name and email, otherwise it uses the existing one.
* The claims are compared to those configured in the forum for moderators and admins, and those roles are assigned to the user if they match.
* The forum uses an algorithm to reconcile the name and email of the user.
* The user is then logged in and browsing the forum.
* After a configured amount of time, the forum will use the refresh token issued by the provider to make sure the user is still legitimate, without the user having to authenticate again.
This mode uses OpenID Connect (OIDC) claims. The identity provider, in addition to the `sub` claim, must also return a `name` and `email` claim. The provider might need to be configured for this, but those claims should be present if it implements OIDC. We do have to ask for these claims by specifying `scope` in our request, which we'll get to in a minute.
## Configuring your OAuth Provider
The amount of access and configuration that you have in your identity provider varies a ton. At the very least, the provider should have OIDC enabled, and return `email` and `name` claims. Beyond that, it should return specific claims for forum admins and moderators. The forum can assign these roles based on just the presence of a claim, or by the claim and a specific value.
>In Azure Active Directory, for example, you can create a group and assign members to it. In an app registration, you can configure tokens to return groups as claims. The claims will all be named `roles`, with values that are guids that identify the groups' object ID's. So if a group called "Forum Admins" has an object ID of `978efeac-3baf-4e61-a519-9b06eb26a0bf`, the token will have a claim called `roles` with that guid as a value. With other identity providers, it may be possible to simply assign a claim called `ForumAdmin` with no value to represent a forum administrator.
Find out what _scopes_ are required to make sure you're getting the `name` and `email` claims, as well as those that identify your moderators and admins. The typical scope you'll specify, as it relates to the OIDC standard, is:
```
openid email profile offline_access
```
The last one, `offline_access`, is typically required to generate a refresh token, used as described in the flow above.
Finally, the provider has to know what the valid redirect URL back to the forum is. How you set this varies by identity provider. This follows this pattern:
```
https://localhost:5091/Forums/Identity/CallbackHandler
```
This is what you would use to redirect to a locally running developer instance of the forum. For real environments, you replace `localhost:5091` with your domain, like `example.com`. Most providers require `https`.
## Configure POP Forums for OAuth-Only
Now that you understand the provider's needs, you can set up the configuration for the forum. These are in addition to the settings described on the [Start Here](starthere.md) page.
```
{
"PopForums": {
"OAuthOnly": {
"IsOAuthOnly": true,
"OAuthClientID": "provided by identity provider",
"OAuthClientSecret": "provided by identity provider",
"OAuthLoginBaseUrl": "where the forum redirects users",
"OAuthTokenUrl": "where the forum validates tokens",
"OAuthAdminClaimType": "name of the Admin role claim",
"OAuthAdminClaimValue": "optional, value of the Admin role claim",
"OAuthModeratorClaimType": "name of the Moderator role claim",
"OAuthModeratorClaimValue": "optional, value of Moderator role claim",
"OAuthScopes": "openid email profile offline_access",
"OAuthRefreshExpirationMinutes": "60"
}
}
}
```
Here's what these do:
* `IsOAuthOnly`: The master switch for this mode. When set to true, all of the things the forum would do to manage user accounts, like account creation, passwords, email, goes away, delegating it to the OAuth identity provider.
* `OAuthClientID`: Sometimes called an "application ID," this value comes from the identity provider to understand what service (your forum, in this case) is talking to it.
* `OAuthClientSecret`: The forum uses this value when it calls back to the provider to validate or refresh a token.
* `OAuthLoginBaseUrl`: This is the base URL that the forum uses to redirect users to the identity provider. It appends this with a query string, including the callback URL (handled by the forum), the scope, and a state value.
* `OAuthTokenUrl`: The URL that the forum uses to validate a code or refresh token that came back from the user redirect.
* `OAuthAdminClaimType`: This is the name of the claim that identifies a user as a forum administrator.
* `OAuthAdminClaimValue`: This is the value of the above named claim that identifies a user as a forum administrator. If not set, the presence of a `OAuthAdminClaimType` claim with any or no value designates the user as a forum administrator.
* `OAuthModeratorClaimType`: This is the name of the claim that identifies a user as a forum moderator.
* `OAuthModeratorClaimValue`: This is the value of the above named claim that identifies a user as a forum moderator. If not set, the presence of a `OAuthModeratorClaimType` claim with any or no value designates the user as a forum administrator.
* `OAuthScopes`: The scopes to get from the identity provider so that it returns the `sub`, `name` and `email` claims. This is often how you tell the service to return a refresh token as well. Typically, this setting will use `openid email profile offline_access`.
* `OAuthRefreshExpirationMinutes`: The number of minutes that should pass until the forum asks the identity provider's token endpoint for an updated refresh token. If the user is no longer valid, they will be logged out on their next request. Use a value that is short enough to cause revoked accounts to be shut out, but long enough that every forum request isn't slowed by fetching a refresh token.
## Troubleshooting
Errors should appear right in the user interface. If you need additional context, check the `pf_SecurityLog` table in the database.
================================================
FILE: docs/scoringgame.md
================================================
---
layout: default
title: The Scoring Game
nav_order: 9
---
# The Scoring Game
Let me tell you a story of HR-discouraged workplace fun. Back in the day, prior to the crash-and-burn of Insurance.com, we had this thing in the development part of the company called the Scoring Game. [I wrote about it](https://jeffputz.com/blog/the-scoring-game) a couple of years ago on my personal blog. The long and short of it is that we kept a running total of +/-1’s for virtually anything you can think of, for each participant. This was back in 2006, before it became trendy to do it for everything else on the Internets.
Later, Digg started doing all kinds of voting, and it was really the first active example that I can think of that I used in terms of measuring value of content (yes, slashdot did it, but I never went there). Various forums started doing it. StackOverflow based much of its value on a scoring system, along with achievements. When I worked at Microsoft, I worked on the reputation system that feeds the various MSDN properties. It seems inevitable that I’d have to add something like this to POP Forums.
Originally, I was thinking just in terms of voting up posts, but then I realized that there were actually two things to build. The voting mechanism was one part, but the actual scoring was a second part that should be decoupled from the voting. So the workflow goes like this:
Process Event –> Publish to user profile (optional) –> Get associated awards –> Qualify awards –> Give award
To use the system, you only need only a few lines of code. Use the dependency injection to get the implementation of `PopForums.ScoringGame.IEventPublisher`. If you're using the typical constructor injection, you'll probably have a reference to it in your class called `_eventPublisher`. The user can be obtained from an instance of `PopForums.Mvc.Areas.Forums.Services.IUserRetrievalShim` in the controller layer.
```c#
_eventPublisher.ProcessEvent("message for feed", user, "TestEventID", false);
```
Pretty simple, eh? The first string is the text that will be published to the user’s feed (if the event is set to publish), the second is the `PopForums.Models.User` object to associate with the event, and the third is the actual event ID. Event definitions are really simple.
There are three events that are static, permanently built into the system. These are wired into the post voting, and the creation of new topics and posts. So for example, when someone votes up a post, a string of HTML is passed in to the ProcessEvent() method, with the user object associated with the post, and the event ID PostVote.
Events don’t have to be published to the user’s profile, and they don’t even need to assign points. New posts and topic events fall into this category. So what’s the point then? Awards! POP Forums leaves that up to you. Award definitions are super simple as well. We can assign any combination of events to the award.
That’s really all there is to it. You can set up stuff anywhere in your app to record events, and publish them to the user profile. Give points, give awards. Knock yourself out!
================================================
FILE: docs/starthere.md
================================================
---
layout: default
title: Start Here
nav_order: 2
---
# Start Here
POP Forums attempts to not get in the way of your application, by working as an MVC area. All of the front-end dependencies are embedded in the Nuget packages, so there's no need to npm packages and build and copy stuff.
How to use [The Scoring Game](scoringgame.md) in your own application.
## Upgrading?
This version has data changes. From v21.x, run the `PopForums21to22.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.
## Prerequisites
You'll need the following locally:
* Visual Studio 2026 or later, with the Azure workload (community version is fine), Visual Studio for Mac or Jetbrains Rider
* Node.js (comes with npm)
* SQL Server Developer, or SQL Server running in a Docker container
* A mail sending service that supports SMTP
* Optionally, Docker if you intend to run Azurite, Redis, ElasticSearch, etc. (instructions below)
## Build vs. reference
You should definitely get to know the installation information below to understand the project structure, but understand that you can also use POP Forums by way of Nuget package references. The [POPWorldMedia/POPForums.Sample](https://github.com/POPWorldMedia/POPForums.Sample) project shows how you can do this without having to build this project, and it's literally adding a Nuget package reference and adding some config stuff in `Program.cs`.
## Reference
* Again, [POPWorldMedia/POPForums.Sample](https://github.com/POPWorldMedia/POPForums.Sample) is a good starting point when using POP Forums via reference, but the `PopForums.Web` project in the source code works similarly, with project references instead of NuGet references.
* Reference `PopForums.Mvc` and `PopForums.Sql` from Nuget. If you want to use the scale-out kits (`PopForums.AzureKit` and `PopForums.ElasticKit`), add those as well.
* Starting with v19, `PopForums.Mvc` includes all of the front-end goodies, the Javascript and CSS, right in the package.
* You'll need a layout view for the forum to live in.
* Set up the various options in `Program.cs` as described in its comments and this documentation.
* `appsettings.json` will have your forum configuration.
* There is no package for the Azure Functions, because it's currently hard to make them work from a shared library in certain situations. However, you can deploy the project from the main repo with ease given the tooling in VS or Azure DevOps Pipelines. Just be sure to set the right values up in the application configuration in the Azure portal.
* POP Forums uses ASP.NET Data Protection in multi-node or external login scenarios. Actually, the basic anti-forgery code baked into the framework does as well, so when you deploy, or swap deployment slots in Azure, you need to persist the underlying key somewhere. This is also true if you run multiple nodes (scale out). You can persist the underlying keys in a number of different ways (I prefer Azure Blob Storage). In your `Program.cs`, use `services.AddDataProtection()` and the appropriate extension method. If you don't do this for multi-node, things like social logins and anti-forgery will fail and fill your error logs with stuff about broken things. If you use slots in Azure App Services, you'll also want the Data Protection setup, otherwise the swap will cause everyone to be logged out.
For the bleeding edge, latest build from `main`, the CI build packages can be obtained by a MyGet feed:
* https://www.myget.org/F/popforums/api/v3/index.json (Nuget package includes the server application and front-end assets)
## Build
* Clone the latest source code from GitHub, or use the production packages as described above. Build it. If your IDE doesn't automatically build Javascript or Typescript, be sure to `npm install` in the `PopForums.Mvc` project, and then run the `gulpfile.js`.
* The project files require an up-to-date version of Visual Studio 2026 or later, but it also works great with Jetbrains' Rider on Mac or Windows. I prefer it.
* This project is built on ASP.NET v10. Make sure you have the required SDK installed (v10.0.100).
* 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.
> Running the background services in the web context can cause some wild variations in CPU and RAM usage on a busy forum, especially in the code associated with updating the search index. If you are running in Azure, using Functions is a much better choice for consistent and predictable app performance.
## Installation
* Once you've completed one of the above scenarios, reference or build, it's time to fire it up, starting with the configuration file.
* `appsettings.json`, in the root of the web project, is the basic configuration file for POP Forums. It works like any other config file in ASP.NET Core, so when you're running in Azure, you can use the colon notation in the App Service application settings to set these values (i.e., `PopForums:Cache:Seconds` as the key).
> If you run the app in a Linux App Service or container, your settings notation should replace `:` with a double underscore, `__`. So the above would be `PopForums__Cache__Seconds`.
```js
{
"PopForums": {
"IpLookupUrlFormat": "https://whatismyipaddress.com/ip/{0}", // used on Recent Users screen of admin to lookup IP addresses
"BaseImageBlobUrl": "http://127.0.0.1:10000/devstoreaccount1", // if using AzureKit to host images, points to the base URL of images uploaded to blob storage (you should really alias the storage to a domain you own)
"Storage": {
"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=popforums21;Trusted_Connection=True;TrustServerCertificate=True;"
},
"Cache": {
"Seconds": 180,
"ConnectionString": "127.0.0.1:6379,abortConnect=false", // used for Redis cache in AzureKit
"ForceLocalOnly": false // used for Redis cache in AzureKit
},
"Search": { // used for Elastic or Azure Search (see docs)
"Url": "popforumsdev",
"Key": "99011A70D3D50D251B0A6141A97B40E7",
"Provider": ""
},
"Queue": { // used for queues with Azure Functions
"ConnectionString": "UseDevelopmentStorage=true"
},
"LogTopicViews": true, // optional, records topic views for future analytics
"ReCaptcha": { // Google ReCaptcha on signup (the key/secret below works on localhost)
"UseReCaptcha": true,
"SiteKey": "6Lc2drIUAAAAAPaa1iHozzu0Zt9rjCYHhjk4Jvtr",
"SecretKey": "6Lc2drIUAAAAADXBXpTjMp67L-T5HdLe7OoKlLrG"
},
"WebAppUrlAndArea": "https://somehost/forums", // used only by Azure Functions to find endpoint of your web app
"RenderBootstrap": true, // optional, defaults to true, put false here if your host page will have its own build of Bootstrap CSS
"OAuthOnly": {
// this section is detailed in the OAuth-Only Mode section
}
}
}
```
* Attempt to run the app locally via Kestrel, and go to the URL `/Forums` to see an error page about not finding the settings table. It will fail either because the database isn’t set up, or because it can’t connect to it. The biggest reason for failure is an incorrect connection string. If you change nothing locally, by default it's looking for a local database on the default SQL Server instance called `popforums21`.
* If you want to use the setup page (and you should), don’t run the SQL script. Once the POP Forums tables exist in the database, the setup page will tell you that you’re prohibited from going there.
* Point the browser to `/Forums/Setup` now, and if your connection string is correct, you should see a page with some of the basic fields to set up.
> If you're running in OAuth-Only Mode, there is no setup for the fields below. The forum will attempt to set up the database, and that's it. That mode has no email functionality, and user creation and roles are delegated to the external identity provider. See [OAuth-Only Mode](oauthonly.md) for more information.
* The `PopForums.Mvc` package includes Bootstrap, which is used as the base style for the entire app. To give it your own look, you can add your own CSS to override Bootstrap in your `_Layout.cshtml`, or do your own build of Bootstrap with whatever variables you like. If you prefer your own build, make sure _both_ the Javascript and CSS tags appear _before_ the `RenderSection` in your header, and set the `RenderBootstrap` setting in `appconfig.json` to `false`. Learn more in [customization](customization.md).
* If you're using Azure functions in the background, instead of embedding the background work in the web app (see [Using AzureKit](azurekitlibrary.md)), you'll want to run multiple startup projects, specifically the `PopForums.Web` and `PopForums.AzureKit.Functions`.
Here’s what each field on the setup page does:
* **Forum title:** This is what your forum will be called at the root, in an h1 tag. You can edit this (and everything else) later.
* **SMTP Server:** The host name of the server you’ll connect to for sending e-mail. Enabling this functionality on your server is beyond the scope of this document, but we usually use SendGrid to send email.
* **Port:** Typically 25, though some services (like Gmail) use others.
* **From e-mail address:** When a user receives e-mail from the forum, it will be “from” this address.
* **Use SSL:** Check if your server uses or requires SSL.
* **Use ESMTP for credentials:** Check this box if you have to authenticate with your server (this is almost always the case). Checking this makes the two boxes below it editable.
* **SMTP User:** User name (often the e-mail address) to authenticate with. Not editable unless the “Use ESMTP” box is checked.
* **SMTP Password:** Password to authenticate with. Not editable unless the “Use ESMTP” box is checked.
* **Display name:** How you want your name to appear in the forum.
* **E-mail:** The e-mail address you’ll use to login with.
* **Password:** The password you’ll use to login with.
You're almost there!
* If you typed everything you need correctly, you should see a happy result, otherwise you’ll see a stack trace and exception.
* Restart the app.
* From here, you can follow the link to the admin home page and add categories and forums. You’ll be logged in as the user you created, and that account will be part of the Admin and Moderator roles.
* Once you’ve added some forums on the “Forums” admin page, you can go to `/Forums` to start posting.
* If you want to test your e-mail setup, go to `/Forums/Account/Forgot` and enter your e-mail address. Failures are also logged in the error log, which is found in the admin area.
* For future reference, you can revisit the admin area at `/Forums/Admin`, and when you're logged in as an admin, a link appears in the user dropdown from the navigation menu.
## Integration
The `PopForums.Web` project is the template you can use as the basis for your own POP Forums apps. If you want to build via the most recent stable builds, the [POPWorldMedia/POPForums.Sample](https://github.com/POPWorldMedia/POPForums.Sample) project is an example of how to do that (see above). The app uses the standard claims-based authentication, but it does not use Identity or Entity Framework. When you're logged in, you'll find the identity of the user on the User property of the controller as expected. The `PopForumsAuthorizationMiddleware` loads user and profile data into the request pipeline, so it can be loaded once and used throughout the request lifecycle.
Accessing the user data can be achieved via an instance of `IUserRetrievalShim`, which you can inject into your dependency chain. From a controller, simply call `_userRetrievalShim.GetUser()` to get the fully hydrated POP Forums `User`, or `_userRetrievalShim.GetProfile()` to get the profile. Under the hood, these are stored in the `Items` collection of the current `HttpContext`.
The easiest way to integrate with an existing set of users is to connect via an OAuth2 provider. Read more about [OAuth-Only Mode](oauthonly.md).
## Running third-party services in Docker containers
If you want to run locally with some of the "kits" described in the documentation, you'll need to fire them up using Docker. Here are the commands for the most common things. These sometimes change, because of new names, versions and such, but they're current as of early 2023.
* SQL Server (keep in mind that `mcr.microsoft.com/azure-sql-edge` is the ARM versoin of SQL)
`docker run --cap-add SYS_PTRACE -e 'ACCEPT_EULA=1' -e 'MSSQL_SA_PASSWORD=P@ssw0rd' -p 1433:1433 --name sqledge -d mcr.microsoft.com/azure-sql-edge`
* Azureite, for storage and queues
`docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite`
* Redis, for distributed cache and SignalR backplane
`docker run --name some-redis -p 6379:6379 -d redis`
* ElasticSearch, for better search
`docker run --name es-9 -p 9200:9200 -e discovery.type=single-node -it docker.elastic.co/elasticsearch/elasticsearch:9.3.0`
You may want to have your databases be more durable in the event you trash the SQL container or update to a new one. To do that, first create a new volume, either in Docker Desktop or on the command line:
```
docker volume create sqldata
```
Then fire up the container and associate it with the volume, and tell it to use that volume for all of the data.
```
docker run -e 'ACCEPT_EULA=1' -e 'MSSQL_SA_PASSWORD=P@ssw0rd' -p 1433:1433 --name sqledge -v sqldata:/DATA -d mcr.microsoft.com/azure-sql-edge
```
If you would like to host the data files in your own file system, you can start the container like this, replacing the approprirate paths to your local spots, where `<host directory>` is your spot:
```
docker run -e 'ACCEPT_EULA=1' -e 'MSSQL_SA_PASSWORD=P@ssw0rd' -p 1433:1433 --name sql2022 -v <host directory>:/var/opt/mssql/data -d mcr.microsoft.com/mssql/server:2022-latest
```
And if you need to copy files out of an existing container, you can do that too. `~/sqlvolumes` in this case points to a folder in my user folders on a Mac:
```
docker cp containerID3bed54c7734b:/var/opt/mssql ~/sqlvolumes
```
## Running Azure Functions on a Mac
This isn't the most straightfoward thing, and it's hard to find the information, but you need to install the Azure Functions Core tools via Homebrew. [Microsoft explains how to do this.](https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cmacos%2Ccsharp%2Cportal%2Cbash#install-the-azure-functions-core-tools)
## Customization
To make POP Forums look the way you want, or with extra functionality, read up on [customization](customization.md).
================================================
FILE: docs/versionhistory.md
================================================
---
layout: default
title: Version History
nav_order: 4
---
# POP Forums Version History
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.1.0 (PopForums.ElasticKit only, 12/16/25)
* The ElasticSearch key value in the configuration should simply be the API key, which is a more modern convention used in Elastic's cloud service.
## Version v22.0.0 (11/24/25)
* Implement an ignore feature #318
* BUG: YouTube short links throwing exception on submit #386
* BUG: Hosted service failure in startup will prevent app start #381
* BUG: In process hosted jobs run at silly intervals #383
## Version v21.0.1 (PopForums.Mvc only, 12/8/24)
* BUG: Hosted service failure in startup will prevent app start #381
* BUG: In process hosted jobs run at silly intervals #383
## Version v21.0.0 (12/7/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
* Update ElasticKit to use v8.x #335
* Updating to TypeScript 5.x requires accommodation of suppressImplicitAnyIndexErrors deprecation #345
* Animate notification and PM count so you see it #327
* Reduce size of trimmed URL's to fit in mobile situations #323
* Delete queued email messages after send #145
* Update to .NET v8 #348
* Update Polly to v8.x (in ElasticKit) #352
* Replace Moq with NSubstitute #340
* User creation should be atomic with profile, not sourced in a controller #328
* Refactor out the old FullUrlHelper #326
* PopForumsUserAttribute needs to be refactored to async #347
* BUG: Fix regex not escaping special characters #342
* BUG: Close private chat if the other user is deleted #321
* BUG: Chromium 114 causes element property name conflict #336
* BUG: Associate external login failing #324
* BUG: Load more before reply chokes when only one page of posts #319
* BUG: Images uploaded in post edit are flagged for deletion #316
## Version v19.0.2 (6/6/23)
* BUG: Chromium 114 causes element property name conflict #336
## Version v19.0.1 (1/29/23)
* BUG: Images uploaded in edit are flagged for deletion #316
* BUG: Load more before reply chokes when only one page of posts #319
* BUG: Associate external login failing #324
## Version v19.0.0 (10/9/22)
* Image upload in posts #109
* Create notification system #265
* Change PM system to real-time chat #304
* Refine post quoting to reduce full-post quotes #283
* Clean up old notifications #298
* Refresh and expand iconography #300
* Migrate from email based subscriptions to in-app notification #264
* Remove email subscriptions #276
* Update PM count in real-time #275
* New setting: reply-to email address #252
* Offer view of recent users in admin for spam monitoring #258
* Don't show user profiles for unverified accounts #263
* Include prompts to verify account where necessary #266
* Allow vote up reversal #287
* Use a reactive state box as base for new features #269
* Remove composite activity feed #299
* Use fulltext editor for profile signatures #291
* Decommission email from profile #310
* Add option to write error log to table storage #314
* Refactor: Move all of the client stuff to the `Mvc` project, ditch the npm package #285
* Refactor: Update MailKit library to v3.x #268
* Refactor: Update ImageSharp library to v2.x #267
* Refactor: Update TinyMCE library to v6.x #274
* Refactor: DateTime parsing on client using server localization, with DST #188
* Refactor: Create proper client-side localization mechanism #293
* Refactor: Migrate old PopForums.js to a more manageable, not-spaghetti, TypeScript base #286
* Refactor: Clean up on aisle admin #295
* Refactor: Exclude bots from session tracking #301
* Refactor: Signalr hub consolidation #312
* BUG: New `SqlCommand` can't parse setup script without semicolons #288
* BUG: Scroll to newest misses target because of inline images loading #290
* BUG: Infinite scroll repositions back to hash when more posts load #257
* BUG: New topic or reply fails if using Azure queues and they fail #284
## Version v18.0.2 (5/28/22)
* BUG: Fix bug in newer version of SqlClient when running setup script. #288
## Version v18.0.1 (1/8/22)
* BUG: Fix auto scroll when new posts load. #257
## Version 18.0.0 (11/8/21)
* Update to .NET 6. #211
* Migrate to Bootstrap v5. #215
* Eliminate dependencies on jQuery. #216
* Migrate admin to Vue.js v3. #232
* Embrace C# concepts. #249
* Use crop mode for avatars when they're uploaded. #239
* Update text parser to default to https on www URL's. #248
* Trim IP and email ban entries before saving. #222
* Remove dependency on Newtonsoft serializer for controllers with enums. #247
* Add a security policy. #238
* Update `AzureKit` to use modern libraries. #226
* Put a cache sink in Redis `CacheHelper` in `AzureKit`. #231
* Update Redis `CacheHelper` to use `System.Text.Json` when it's compatible. #169
* Discontinue use of `PopForums.json` for config, use default instead. #225
* BUG: Mailing list unsubscribe doesn't decode spaces from URL's. #237
* BUG: CSS needs case sensitive path for Linux environments. #228
* BUG: `SmtpWrapper` doesn't catch connections or auth exceptions. #237
* BUG: Bots causing null ref exception in `TopicViewCountService` when trying to fetch cookies. #210
* BUG: Setup stopped working in a previous version. #244
* BUG: Text parser fails on URL's with multiples protocol instances (like those from web archive). #233
## Version 17.0.2 (9/29/21)
* Fix for broken setup bug. #244
## Version 17.0.1 (4/4/21)
* Fix for multiple image bug. #234
## Version 17.0.0 (8/24/20)
* Rename AwsKit project to ElasticKit. #184
* Add alerts for admin errors. #152
* Use the right Bootstrap color context on email verification. #195
* Add configuration for entirely private forum. #86
* Use the HTML quoting in post edit box instead of forum tags. #201
* Generate site maps for all topics. #199
* Audit CSS and use Bootstrap when possible. #186
* Search for user on enter on admin user edit page. #194
* Use hashing mechanism for topic unsubscribes, the way mailing list works. #189
* Migrate to `Microsoft.Azure.Storage` packages from `Microsoft.WindowsAzure.Storage`. #182
* Use Bootstrap hidden utilities to hide elements on mobile. #181
* Move recent and feed links to navigation bar. #187
* Embrace `IHttpContextAccessor` in user shim. #176
* Add a telemetry interface for Redis cache, but don't implement it. #185
* Use contrasting colors for new post indicators. #179
* Refresh user profiles. #174
* Improve ElasticSearch for proper resiliency, add API key ability. #173
* Log search service errors. #171
* BUG: User profile tabs have wrong background for activity and awards. #172
* BUG: Avatars and signatures not appearing for anonymous user. #197
* BUG: Pasted URL's paste as links, parser can't shorten the text. #163
* BUG: Formatting in quoted posts sometimes causes portions of post to get parsed out. #198
* BUG: LastTopicView could have duplicate entries. #202
## Version 16.0.1 (12/27/19)
* BUG: Redis cache helper can't serialize forum view/post graphs. #168
## Version 16.0.0 (12/17/19)
* Update to .Net Core v3.1. #151
* Redis connection failures recorded as "information" instead of "error." #162
* Optimize user objects and caching. #44
* Using "page" in routes can potentially interfere with Razor pages. #150
* Close dormant threads on a background job. #67
* Allow topic author to edit title. #80
* Refactor all the things to async/await. #132
* Refactor external logins to decouple from Identity (uses [POP Identity](https://github.com/POPWorldMedia/POPIdentity)). #140
* Cleanup startup configuration. #129
* Refactor the posting service classes. #121
* Cleanup unused methods and tests. #133
* Add unique constraints for user name and email. #144
* Add ReCAPTCHA option for login. #143
* Update to a stronger hash algorithm for passwords. #142
* Reintroduce profile caching. #148
* BUG: Failed reply doesn't wire up error message and attempts to redirect. #160
* BUG: Delete, undelete, hard delete doesn't remove from search index. #154
* BUG: Give background job to delete indexed words in self-rolled search more time. #149
* BUG: Creation of Redis connection not thread safe, possible race condition. #135
* BUG: Delete/undelete does not trigger a search reindex. #136
* BUG: Search indexer Azure function does not respect settings for provider setting. #137
* BUG: External login list has duplicate entries for description. #139
## Version 15.0.0 (5/27/19)
* General update of dependencies.
* Rewrite of admin to use Vue.js. #120
* Scaffolding for recording view data, correlating between users and topics (for future analytic use). #104
* Optionally run background processes as Azure functions. #76
* Social icons in profile. #119
* Redis backplane for SingalR in multi-node hosting. #64
* Migrated to Bootstrap v4.x. #94
* Abandon decade-old constructors in models. #96
* Remove first post preview from topic lists (no one used it). #97
* Truncate error log instead of delete all. #103
* Adopt Dapper usage in `PopForums.Sql` library. #105
* Improve performance for IP history and security log. #106
* Realign social links in profile to modern services. #107
* Provide a standard way to fail distributed events. #117
* Add support for ElasticSearch. #116
* BUG: Over-zealous regex hangs unparse of client HTML. #118
* BUG: Fix Favorite & Subscription Topic pages. #111
* BUG: It's possible to submit empty posts with just returns. #82
* BUG: TinyMCE is mangling hyperlinks. #125
* BUG: TinyMCE is inserting extra attributes in image tags, breaking parsing. #128
## Version 14.1.0 (12/9/18)
* Update to .Net Core v2.2.
* General package updates.
* Move all MVC views to a project that can be published as a Razor class library package.
* Remove ability to resize images in TinyMCE editor, since attributes are ignored anyway.
* Bug: for pager links in faves and subs (#90 and #91).
## Version 14.0.0 (7/15/18)
* This is a port of v13 to ASP.NET Core v2.1.0. It's mostly intended to achieve feature parity.
* Experimental AzureKit allows for multi-instance use and scaling.
## Version 13.0.0 (2/14/15)
* Completely revised UI uses Bootstrap, replaces separate mobile views.
* New Q&A style forums.
* Preview your posts for formatting.
* Social logins using OWIN 2.x.
* StructureMap replaces Ninject for dependency injection.
* Admins can permanently delete a topic.
* Facebook and Twitter links added to profiles.
* IP ban works on partial matches.
* Bug: Initial user creation didn't salt passwords ([Codeplex 131](http://popforums.codeplex.com/workitem/131))
* Bug: Replies not triggering reindex for topics (#4).
* Bug: LastReadService often called from Post action of ForumController without user, throws null ref (#1).
* Bug: Reply and quote buttons appear in posts even when the topic is closed (#8).
* Bug: When email verify is on, changing email does not set IsApproved to false (#10).
* Bug: Image controller throws when Googlebot sends a weird If-Modified-Since header (#13).
* Bug: Reply or new topic can be added to archived forum via direct POST outside of UI (#15).
* Bug: Multiple entries to last forum and topic view tables causing exception when reading values into dictionary (#17).
* Experimental: Support for multiple instances in Azure with shared Redis cache (not production ready).
## Version 12.1.0 (4/25/14)
* Added Taiwanese Mandarin translation
* Fixed HtmlHelper to remove reference to DependencyResolver. #122: HtmlHelper for role checkboxes referenced static DependencyResolver
* Disable submit buttons on new topics/replies for mobile views. #121: Port the submit button disable for posts in mobile view
* Fixed mobile view of edit doesn't parse text for overridden mobile mode. #123: Mobile post edit view has HTML, save doesn't persist line breaks
## Version 12.0.0 (12/8/13)
* Updated to use .NET 4.5.1 and MVC 5, including the latest library code (jQuery, SignalR, OWIN, etc.)
* User passwords now include per-user salt, backward compatible to existing user data. #120: Salt passwords by user
* External logins implemented via OWIN, for Google, Facebook, Twitter and Microsoft accounts. #117:Integrate the OWIN external auth stuff
* YouTube URL's not formatted as hyperlinks converted to embedded video, provided images are allowed in posts. #116: Parse YouTube URL's to convert into YouTube iframes
* Controller dependencies converted to private members. #115: Refactor controller dependencies to private members
## Version 11.1.0 (9/4/13)
* Added Ukrainian to supported languages. Also includes English, Spanish, German and Dutch.
* Fixed issue #115: Mobile view allows double post.
## Version 11.0.1 (5/15/13)
* Fix for issue #113: User can post in closed topic via mobile views.
## Version 11.0.0 (4/17/13)
* Updated to use v4.5 of .NET.
* External references now use NuGet.
* Adding an award definition in admin now bounces you to its edit page.
* Fixed: Show more posts updates topic context with updated page counts.
* Activities and awards restyled.
* User profiles are tabbed.
* Activity feed shows real-time view of activity sent via the scoring game API.
* Times are updated every minute, formatted to current culture.
* More posts are loaded on scroll (a la Facebook), but pager links are maintained for search engine discoverability.
* New posts appear inline at end of post stream as they're made.
* Forum home and individual topic lists updated in real time.
* Breadcrumb/navigation floats at top of browser.
* .forumGrid CSS removes outline, so it's more Metro-y.
## Version 10.0.1 (9/15/12)
This update has no UI component or data changes. It only addresses the following bug:
* ServiceModule has potential race condition in ASP.NET v4.5
* A bug in the MVC 4 framework requires this package for mobile views: http://nuget.org/packages/Microsoft.AspNet.Mvc.FixedDisplayModes
## Version 10.0.0 (8/16/12)
* Uses a very light weight CSS and Javascript package to provide a touch-friendly interface for mobile devices.
* Numbers are formatted (sensitive to culture) when 1,000 or higher.
* CSS is more integration friendly, and specific to the ForumContainer element.
* Mail delivery from queue is now parallel, so you can specify a sending interval, and the number of messages to process on each interval.
* Background "services" refactored, and will only run with a call on app start to PopForumsActivation.StartServices(). This is partly to facilitate future use in Web farms/multiple Web roles in Azure.
* Update to jQuery v1.7.1.
* Replaced use of .live() with .on() in script, pursuant to jQuery update, which deprecates .live().
* Renamed HomeController to ForumHomeController, to make lives easier when integrating into an MVC app.
* Dependency resolution no longer requires that you set Ninject as the container for the entire MVC app. The controllers now resolve their dependencies in their constructors, so you're free to set up any DI container in your global.asax.
* The included single-server SQL data layer now uses the base classes and interfaces for (DbConnection, DbCommand, etc.) instead of the specific SQL flavors, for easier refactoring in case you want to build an Oracle version or something.
* FIX: Bug in topic repository around caching keys for single-server data layer.
* FIX: Pager links on recent topics pointed to incorrect route.
* FIX: Deleting a post didn't update last user/post time.
* FIX: Ditched attempt at writing to event log with super failures, since almost no one has permission in production.
* FIX: Bug in grayed-out fields in admin mail setup.
* FIX: Weird color profiles would break loading of images for resize.
* FIX: TOS text on account sign-up was double encoded.
## Version 9.2.1 (1/26/12)
* Added Spanish (es) translation.
## Version 9.2.0 (1/23/12)
* Localization: The app can be easily translated using .resx files. Initially includes English (en), German (de) and Dutch (nl).
* Vote up posts: Give credit to people who make good posts, see who voted up each one.
* The scoring game: Extensible system that allows you to give users points, and issue awards based on repeated events. For example, you can set up awards based on the number of new posts or topics a user makes (both of which are recorded).
* Fix: Weird line breaks in lists when posting from Firefox.
## Version 9.1.1 (12/18/11)
* Corrects a bug that prevented a topic from being marked viewed when a user looked at it, resulting in "new post" indicators that didn't go away until the user marked the entire forum as read.
## Version 9.1.0 (12/15/11)
* New "adapter" interface for forums. Using the IForumAdapter interface, a developer can plug-in code that alters the model and/or resulting view on topic lists and the actual threads. For example, you might add to or alter the model, then present a different view to display the data. See the comments on the IForumAdapter interface for more information.
* Also new, users starting a reply will see a button indicating that they can load any new posts that have occurred since they started writing their apply, so they don't miss any of the conversation.
* Fix: Moderating topic title doesn't update the UrlName.
* SEO enhancement: Page links in topics and forums include rel="next" and rel="prev" to tell search engines there's more to look at.
* Fix: User post list had broken markup, preventing topic preview.
* Fix: Added missing permission checking on action methods to preview or load individual posts.
* User name in top nav now acts as a link to the user's profile.
* Fix: Cache key for caching view post roles was incorrect.
## Version 9.0.0 (4/24/11)
* Rewritten from scratch for ASP.NET MVC3, with reasonable test coverage
* Posts can be loaded inline
* Avatars and user images resized on server
## Version 8.5.0 (not publicly released)
* Added plug-in infrastructure to allow changes to UI. Made for photo forum on CoasterBuzz
## Version 8.0.0 (11/10/08)
* Added AJAX features, takes advantage of ASP.NET v3.5.
## Version 7.5.1 (2/9/05)
* Significantly altered the TextParser class
* Changed text in RegisterLogin.ascx to indicate e-mail is used to send activation code
* Topic titles now parsed for naughty words and HTML
## Version 7.5.0 (10/25/04)
* New text parsing engine
* New online user engine
* RichText control displays in Windows 2000
* Fixed member post paging
* Online user stats now draw from PopForums.OnlineUsers
* Added RequiredFieldValidator to SendPrivateMessage.ascx to check for a subject
* PM reply doesn't add endless string of "re:"
* Fixed PagerLinks.cs to correctly display tool tips
* Added PagedPagerLinks.cs to display paged results from new PopForums.Forum.GetTopics() overload
* Made the member mailer text box in the admin bigger
* Can't reply to closed topics, even if reply box was visible before submitting
## Version 7.0.3 (1/24/04)
* Fixed URL and image detection in TextParser.
## Version 7.0.2 (11/11/03)
* Updated the RichText class to make it compatible with a recent update to Internet Explorer.
## Version 7.0.1 (11/4/03)
* Removed license scheme to make POP Forums free.
## Version 7.0.0 (10/22/03)
* Total rewrite with separation of data, logic and user interface.
* Several user interfaces available at launch.
* Data caching can reduce database activity by 60% or more.
* A RichText server control that renders in Internet Explorer.
* Role-based security you can use anywhere on your site, based on ASP.NET's forms authentication.
* Discreet data class, so you can write your own to access any database. (SQL Server used by default.)
* A TimeAdjust class to convert times to local time zones, and even adjust for daylight savings.
* Text parsing engine takes care of HTML generated by RichText as well as traditional "forum code."
## Version 6.0.0 (7/1/02)
* Original ASP application ported to ASP.NET.
* Significant improvements to HTML parsing engine.
* Forum exists as a user control, just drop it in your .aspx page!
* E-mail notification for anyone who replies to a topic.
* All-CSS interface shipped along side "admin-able" formatting.
* Asynchronous mailing to opt-in members (no need to tie up your browser with mailing process).
* Last post indicated by member name.
* Scroll to new post bounces you to page with newest post.
* Role-based security. Only those in certain roles can access or post in the forums you designate.
* Robust forum property and ordering in admin area.
* Error logging to database.
## Version 5.1 (3/4/02)
* New HTML/forum code parsing engine.
## Version 5.0 (8/19/01)
* Support for SQL Server Full-Text Indexing built-in for much faster searching.
* WYSIWYG post editor for Internet Explorer users, normal for other browsers.
* Favorite topic list.
* Terms of Service agreement with first post, reset all members' agreement.
* Member post quotas, to limit "noisy" members.
* Support for Persits and Dimac mail components.
* Post preview.
* "Jump to" added to topic and thread pages to jump to another forum.
* Public stats shown optionally (number of sessions, topics, members, etc.)
* Client-side form validation of new topics or replies to challenge empty fields.
* Admin edit member accounts.
* Recent topics shows links to multi-paged topics.
* Error page for URL's of deleted topics and forums.
* Fixed edit page hang for long posts.
* Search only returns private forum results to those who have access.
* Removed "requires AspMail" from admin page.
* Moderator IP view spans all pages in thread.
* Manage e-mail notification page reformatted.
* Double carriage returns now parsed as p tags.
* Fixed CDONTS mailer for compatibility with settings of other components.
* Fixed br unparsing with forum code off.
## Version 4.0 (1/8/01)
* Added support for CDO, CDONTS and AspQMail components.
* Post new topic and reply links added to topic and thread pages.
* COPPA check defeat.
* Support for Spellchecker.net.
* Scroll to newest post link.
* Addition of pre and quote forum tags.
* Paged threads. Posts per page are admin-defined. Links to each page appear in topic list.
* Auto-login after first post.
* AIM and ICQ hyperlinks in member info.
* Non-logged-in forums indicates "register to track new posts."
* COPPA (Children's Online Privacy Protection Act) compliance.
* Moderators can view IP addresses of posters.
* E-mail notification of new posts when member starts thread.
* Member area to remove e-mail notification of new posts.
* Opt-out or delete account option built into special URL sent with mass mailings to members.
* Mail to friend now uses system e-mail contact as from address, member as replyto address (to handle SMTP authentication issues).
* Moving lone topic from forum no longer results in an error.
## Version 3.2 (11/12/00)
* Included explanation of smilies in help file.
## Version 3.1 (9/20/00)
* One-click close/open/delete threads for moderators.
* Parse ftp:// URL's.
* Post-and-close thread check box for moderators,
* Next/previous thread.
* Mail thread to a friend.
* Recent topics.
* Fixed left column text color in search results.
## Version 3.0 (8/22/00)
* Major rewrite of most code.
* Dozens of files consolidated.
* Made to be portable between systems.
* Extensive administration area.
* Custom formatting added to instantly change fonts, colors, etc.
* Search engine added.
* Private and archived forums added.
## Version 2.0 (1/31/00)
* Written for CoasterBuzz.
* Cleaner format.
* Forum off/on.
* "Mark posts read" time stored in profile instead of browser.
* Signature block added.
* Profile photo upload added.
## Version 1.0 (11/23/99)
* Written for Guide to The Point.
* Basic features only.
================================================
FILE: src/.editorconfig
================================================
# EditorConfig is awesome:http://EditorConfig.org
# top-most EditorConfig file
root = true
# Don't use tabs for indentation.
[ "*" ]
indent_style = tab
end_of_line = lf
insert_final_newline = true
# (Please don't specify an indent_size here; that has too many unintended consequences.)
# Code files
[*.{cs,csx,vb,vbx,cshtml}]
indent_style = tab
indent_size = 4
# Xml project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_style = tab
indent_size = 2
# Xml config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_style = tab
indent_size = 2
# JSON files
[*.json]
indent_style = space
indent_size = 2
================================================
FILE: src/PopForums/Composers/ForumStateComposer.cs
================================================
namespace PopForums.Composers;
public interface IForumStateComposer
{
ForumState GetState(Forum forum, PagerContext pagerContext);
}
public class ForumStateComposer : IForumStateComposer
{
public ForumState GetState(Forum forum, PagerContext pagerContext)
{
var forumState = new ForumState {ForumID = forum?.ForumID, PageSize = pagerContext.PageSize, PageIndex = pagerContext.PageIndex};
return forumState;
}
}
================================================
FILE: src/PopForums/Composers/PrivateMessageStateComposer.cs
================================================
namespace PopForums.Composers;
public interface IPrivateMessageStateComposer
{
Task<PrivateMessageState> GetState(PrivateMessage pm);
}
public class PrivateMessageStateComposer : IPrivateMessageStateComposer
{
private readonly IPrivateMessageService _privateMessageService;
public PrivateMessageStateComposer(IPrivateMessageService privateMessageService)
{
_privateMessageService = privateMessageService;
}
public async Task<PrivateMessageState> GetState(PrivateMessage pm)
{
var state = new PrivateMessageState();
var messages = await _privateMessageService.GetMostRecentPosts(pm.PMID, pm.LastViewDate);
state.NewestPostID = messages.Any() ? messages.First().PMPostID : 0;
var bufferMessages = await _privateMessageService.GetPosts(pm.PMID, pm.LastViewDate);
messages.InsertRange(0, bufferMessages);
state.PmID = pm.PMID;
var clientMessages = ClientPrivateMessagePost.MapForClient(messages);
state.Messages = clientMessages;
state.Users = pm.Users;
var pmUsersFromPMRecord = pm.Users.Deserialize<List<object>>();
var pmUsers = await _privateMessageService.GetUsers(pm.PMID);
var isUserNotFound = pmUsers.Count != pmUsersFromPMRecord.Count;
state.IsUserNotFound = isUserNotFound;
return state;
}
}
================================================
FILE: src/PopForums/Composers/ResourceComposer.cs
================================================
namespace PopForums.Composers;
public interface IResourceComposer
{
dynamic GetForCurrentThread();
}
public class ResourceComposer : IResourceComposer
{
public dynamic GetForCurrentThread()
{
var resources = new
{
LessThanMinute = Resources.LessThanMinute,
OneMinuteAgo = Resources.OneMinuteAgo,
MinutesAgo = Resources.MinutesAgo,
TodayTime = Resources.TodayTime,
YesterdayTime = Resources.YesterdayTime,
Notifications = Resources.Notifications,
NewReplyNotification = Resources.NewReplyNotification,
Award = Resources.Award,
VoteUpNotification = Resources.VoteUpNotification,
QuestionAnsweredNotification = Resources.QuestionAnsweredNotification,
Send = Resources.Send,
UploadImage = Resources.UploadImage
};
return resources;
}
}
================================================
FILE: src/PopForums/Composers/TopicStateComposer.cs
================================================
namespace PopForums.Composers;
public interface ITopicStateComposer
{
Task<TopicState> GetState(Topic topic, int? pageIndex, int? pageCount, int lastVisiblePostID);
}
public class TopicStateComposer : ITopicStateComposer
{
private readonly IUserRetrievalShim _userRetrievalShim;
private readonly ISettingsManager _settingsManager;
private readonly ISubscribedTopicsService _subscribedTopicsService;
private readonly IFavoriteTopicService _favoriteTopicService;
public TopicStateComposer(IUserRetrievalShim userRetrievalShim, ISettingsManager settingsManager, ISubscribedTopicsService subscribedTopicsService, IFavoriteTopicService favoriteTopicService)
{
_userRetrievalShim = userRetrievalShim;
_settingsManager = settingsManager;
_subscribedTopicsService = subscribedTopicsService;
_favoriteTopicService = favoriteTopicService;
}
public async Task<TopicState> GetState(Topic topic, int? pageIndex, int? pageCount, int lastVisiblePostID)
{
var topicState = new TopicState {TopicID = topic.TopicID, PageIndex = pageIndex, PageCount = pageCount, LastVisiblePostID = lastVisiblePostID, AnswerPostID = topic.AnswerPostID};
var user = _userRetrievalShim.GetUser();
if (user != null)
{
topicState.IsImageEnabled = _settingsManager.Current.AllowImages;
topicState.IsFavorite = await _favoriteTopicService.IsTopicFavorite(user.UserID, topic.TopicID);
topicState.IsSubscribed = await _subscribedTopicsService.IsTopicSubscribed(user.UserID, topic.TopicID);
}
return topicState;
}
}
================================================
FILE: src/PopForums/Configuration/Config.cs
================================================
namespace PopForums.Configuration;
public interface IConfig
{
string DatabaseConnectionString { get; }
int CacheSeconds { get; }
string CacheConnectionString { get; }
bool ForceLocalOnly { get; }
string SearchUrl { get; }
string SearchKey { get; }
string QueueConnectionString { get; }
string SearchProvider { get; }
bool LogTopicViews { get; }
bool UseReCaptcha { get; }
string ReCaptchaSiteKey { get; }
string ReCaptchaSecretKey { get; }
string IpLookupUrlFormat { get; }
string WebAppUrlAndArea { get; }
string BaseImageBlobUrl { get; }
string StorageConnectionString { get; }
bool RenderBootstrap { get; }
bool IsOAuthOnly { get; }
string OAuthClientID { get; }
string OAuthClientSecret { get; }
string OAuthLoginBaseUrl { get; }
string OAuthTokenUrl { get; }
string OAuthAdminClaimType { get; }
string OAuthAdminClaimValue { get; }
string OAuthModeratorClaimType { get; }
string OAuthModeratorClaimValue { get; }
string OAuthScopes { get; }
int OAuthRefreshExpirationMinutes { get; }
}
public class Config : IConfig
{
public Config(IConfiguration configuration)
{
if (_configContainer == null)
{
var loader = new ConfigLoader();
_configContainer = loader.GetConfig(configuration);
}
}
private static ConfigContainer _configContainer;
public string DatabaseConnectionString => _configContainer.DatabaseConnectionString;
public int CacheSeconds => _configContainer.CacheSeconds;
public string CacheConnectionString => _configContainer.CacheConnectionString;
public bool ForceLocalOnly => _configContainer.CacheForceLocalOnly;
public string SearchUrl => _configContainer.SearchUrl;
public string SearchKey => _configContainer.SearchKey;
public string QueueConnectionString => _configContainer.QueueConnectionString;
public string SearchProvider => _configContainer.SearchProvider;
public bool LogTopicViews => _configContainer.LogTopicViews;
public bool UseReCaptcha => _configContainer.UseReCaptcha;
public string ReCaptchaSiteKey => _configContainer.ReCaptchaSiteKey;
public string ReCaptchaSecretKey => _configContainer.ReCaptchaSecretKey;
public string IpLookupUrlFormat => _configContainer.IpLookupUrlFormat;
public string WebAppUrlAndArea => _configContainer.WebAppUrlAndArea;
public string BaseImageBlobUrl => _configContainer.BaseImageBlobUrl;
public string StorageConnectionString => _configContainer.StorageConnectionString;
public bool RenderBootstrap => _configContainer.RenderBootstrap;
public bool IsOAuthOnly => _configContainer.IsOAuthOnly;
public string OAuthClientID => _configContainer.OAuthClientID;
public string OAuthClientSecret => _configContainer.OAuthClientSecret;
public string OAuthLoginBaseUrl => _configContainer.OAuthLoginBaseUrl;
public string OAuthTokenUrl => _configContainer.OAuthTokenUrl;
public string OAuthAdminClaimType => _configContainer.OAuthAdminClaimType;
public string OAuthAdminClaimValue => _configContainer.OAuthAdminClaimValue;
public string OAuthModeratorClaimType => _configContainer.OAuthModeratorClaimType;
public string OAuthModeratorClaimValue => _configContainer.OAuthModeratorClaimValue;
public string OAuthScopes => _configContainer.OAuthScopes;
public int OAuthRefreshExpirationMinutes => _configContainer.OAuthRefreshExpirationMinutes;
}
================================================
FILE: src/PopForums/Configuration/ConfigContainer.cs
================================================
namespace PopForums.Configuration;
public class ConfigContainer
{
public string DatabaseConnectionString { get; set; }
public int CacheSeconds { get; set; }
public string CacheConnectionString { get; set; }
public bool CacheForceLocalOnly { get; set; }
public string SearchUrl { get; set; }
public string SearchKey { get; set; }
public string QueueConnectionString { get; set; }
public string SearchProvider { get; set; }
public bool LogTopicViews { get; set; }
public bool UseReCaptcha { get; set; }
public string ReCaptchaSiteKey { get; set; }
public string ReCaptchaSecretKey { get; set; }
public string IpLookupUrlFormat { get; set; }
public string WebAppUrlAndArea { get; set; }
public string BaseImageBlobUrl { get; set; }
public string StorageConnectionString { get; set; }
public bool RenderBootstrap { get; set; }
public bool IsOAuthOnly { get; set; }
public string OAuthClientID { get; set; }
public string OAuthClientSecret { get; set; }
public string OAuthLoginBaseUrl { get; set; }
public string OAuthTokenUrl { get; set; }
public string OAuthAdminClaimType { get; set; }
public string OAuthAdminClaimValue { get; set; }
public string OAuthModeratorClaimType { get; set; }
public string OAuthModeratorClaimValue { get; set; }
public string OAuthScopes { get; set; }
public int OAuthRefreshExpirationMinutes { get; set; }
}
================================================
FILE: src/PopForums/Configuration/ConfigLoader.cs
================================================
namespace PopForums.Configuration;
public class ConfigLoader
{
public ConfigContainer GetConfig(IConfiguration configuration)
{
var container = new ConfigContainer();
container.DatabaseConnectionString = configuration["PopForums:Database:ConnectionString"];
var cacheSeconds = configuration["PopForums:Cache:Seconds"];
container.CacheSeconds = string.IsNullOrEmpty(cacheSeconds) ? 90 : Convert.ToInt32(cacheSeconds);
container.CacheConnectionString = configuration["PopForums:Cache:ConnectionString"];
container.CacheForceLocalOnly = Convert.ToBoolean(configuration["PopForums:Cache:ForceLocalOnly"]);
container.SearchUrl = configuration["PopForums:Search:Url"];
container.SearchKey = configuration["PopForums:Search:Key"];
var searchProvider = configuration["PopForums:Search:Provider"];
container.SearchProvider = searchProvider ?? string.Empty;
container.QueueConnectionString = configuration["PopForums:Queue:ConnectionString"];
var logTopicViews = configuration["PopForums:LogTopicViews"];
container.LogTopicViews = logTopicViews != null && bool.Parse(logTopicViews);
var useReCaptcha = configuration["PopForums:ReCaptcha:UseReCaptcha"];
container.UseReCaptcha = useReCaptcha != null && bool.Parse(useReCaptcha);
container.ReCaptchaSiteKey = configuration["PopForums:ReCaptcha:SiteKey"];
container.ReCaptchaSecretKey = configuration["PopForums:ReCaptcha:SecretKey"];
container.IpLookupUrlFormat = configuration["PopForums:IpLookupUrlFormat"];
container.WebAppUrlAndArea = configuration["PopForums:WebAppUrlAndArea"];
container.BaseImageBlobUrl = configuration["PopForums:BaseImageBlobUrl"];
container.StorageConnectionString = configuration["PopForums:Storage:ConnectionString"];
var renderBootstrap = configuration["PopForums:RenderBootstrap"];
container.RenderBootstrap = renderBootstrap != null ? bool.Parse(renderBootstrap) : true;
var isOAuthOnly = configuration["PopForums:OAuthOnly:IsOAuthOnly"];
container.IsOAuthOnly = isOAuthOnly != null ? bool.Parse(isOAuthOnly) : false;
container.OAuthClientID = configuration["PopForums:OAuthOnly:OAuthClientID"];
container.OAuthClientSecret = configuration["PopForums:OAuthOnly:OAuthClientSecret"];
container.OAuthLoginBaseUrl = configuration["PopForums:OAuthOnly:OAuthLoginBaseUrl"];
container.OAuthTokenUrl = configuration["PopForums:OAuthOnly:OAuthTokenUrl"];
container.OAuthAdminClaimType = configuration["PopForums:OAuthOnly:OAuthAdminClaimType"];
container.OAuthAdminClaimValue = configuration["PopForums:OAuthOnly:OAuthAdminClaimValue"];
container.OAuthModeratorClaimType = configuration["PopForums:OAuthOnly:OAuthModeratorClaimType"];
container.OAuthModeratorClaimValue = configuration["PopForums:OAuthOnly:OAuthModeratorClaimValue"];
container.OAuthScopes = configuration["PopForums:OAuthOnly:OAuthScopes"];
var refreshMinutes = configuration["PopForums:OAuthOnly:OAuthRefreshExpirationMinutes"];
container.OAuthRefreshExpirationMinutes = string.IsNullOrEmpty(refreshMinutes) ? 60 : Convert.ToInt32(refreshMinutes);
return container;
}
}
================================================
FILE: src/PopForums/Configuration/ErrorLog.cs
================================================
namespace PopForums.Configuration;
public interface IErrorLog
{
void Log(Exception exception, ErrorSeverity severity);
void Log(Exception exception, ErrorSeverity severity, string additionalContext);
List<ErrorLogEntry> GetErrors(int pageIndex, int pageSize, out PagerContext pagerContext);
PagedList<ErrorLogEntry> GetErrors(int pageIndex, int pageSize);
Task DeleteError(int errorID);
Task DeleteAllErrors();
}
public class ErrorLog : IErrorLog
{
public ErrorLog(IErrorLogRepository errorLogRepository)
{
_errorLogRepository = errorLogRepository;
}
private readonly IErrorLogRepository _errorLogRepository;
public void Log(Exception exception, ErrorSeverity severity)
{
Log(exception, severity, null);
}
public void Log(Exception exception, ErrorSeverity severity, string additionalContext)
{
if (exception != null && exception is ErrorLogException)
return;
var message = string.Empty;
var stackTrace = string.Empty;
var s = new StringBuilder();
if (additionalContext != null)
{
s.Append("Additional context:\r\n");
s.Append(additionalContext);
s.Append("\r\n\r\n");
}
if (exception != null)
{
message = exception.GetType().Name + ": " + exception.Message;
if (exception.InnerException != null)
message += "\r\n\r\nInner exception: " + exception.InnerException.Message;
stackTrace = exception.StackTrace ?? string.Empty;
foreach (DictionaryEntry item in exception.Data)
{
s.Append(item.Key);
s.Append(": ");
s.Append(item.Value);
s.Append("\r\n");
}
}
s.Append("\r\n");
var moreData = s.ToString();
try
{
// TODO: Eventually make this async, but its web of call stacks are huge
_errorLogRepository.Create(DateTime.UtcNow, message, stackTrace, moreData, severity);
}
catch
{
throw new ErrorLogException($"Can't log error: {message}\r\n\r\n{stackTrace}\r\n\r\n{moreData}");
}
}
public List<ErrorLogEntry> GetErrors(int pageIndex, int pageSize, out PagerContext pagerContext)
{
var startRow = ((pageIndex - 1) * pageSize) + 1;
var errors = _errorLogRepository.GetErrors(startRow, pageSize).Result;
var errorCount = _errorLogRepository.GetErrorCount().Result;
var totalPages = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(errorCount) / Convert.ToDouble(pageSize)));
pagerContext = new PagerContext { PageCount = totalPages, PageIndex = pageIndex, PageSize = pageSize };
return errors;
}
public PagedList<ErrorLogEntry> GetErrors(int pageIndex, int pageSize)
{
var errors = GetErrors(pageIndex, pageSize, out PagerContext pagerContext);
var list = new PagedList<ErrorLogEntry> { PageCount = pagerContext.PageCount, PageIndex = pagerContext.PageIndex, PageSize = pagerContext.PageSize, List = errors };
return list;
}
public async Task DeleteError(int errorID)
{
await _errorLogRepository.DeleteError(errorID);
}
public async Task DeleteAllErrors()
{
await _errorLogRepository.DeleteAllErrors();
}
}
================================================
FILE: src/PopForums/Configuration/ErrorLogException.cs
================================================
namespace PopForums.Configuration;
public class ErrorLogException : Exception
{
public ErrorLogException(string message) : base(message)
{
}
public override string Message => "Can't log exception: " + base.Message;
}
================================================
FILE: src/PopForums/Configuration/ErrorSeverity.cs
================================================
namespace PopForums.Configuration;
public enum ErrorSeverity
{
Critical = 1,
Warning = 2,
Information = 3,
Debug = 4,
Error = 5,
Email = 6
}
================================================
FILE: src/PopForums/Configuration/ICacheHelper.cs
================================================
namespace PopForums.Configuration;
public interface ICacheHelper
{
/// <summary>
/// Saves an object to cache using he configured number of seconds.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
void SetCacheObject(string key, object value);
/// <summary>
/// Saves an object to cache using the specified number of seconds.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="seconds"></param>
void SetCacheObject(string key, object value, double seconds);
/// <summary>
/// Saves an object to cache without a time limit. Expiration should be deferred to
/// the cache mechanism.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
void SetLongTermCacheObject(string key, object value);
/// <summary>
/// Stores an object in cache as a group. When the root key is removed, all of the paged items
/// are also removed. Useful for storing paged threads and lists of topics.
/// </summary>
/// <typeparam name="T">The type for the collections stored together (like a List<Post>).</typeparam>
/// <param name="rootKey">They key that references the collection of paged lists.</param>
/// <param name="page">The page number of the collection to store.</param>
/// <param name="value">The collection of T objects to cache.</param>
void SetPagedListCacheObject<T>(string rootKey, int page, List<T> value);
/// <summary>
/// Removes an object from cache.
/// </summary>
/// <param name="key"></param>
void RemoveCacheObject(string key);
/// <summary>
/// Removes an object from cache.
/// </summary>
/// <param name="key">Key of the cache item to remove.</param>
/// <remarks>
/// Implementations of this method should call the <see cref="OnRemoveCacheKey"/> event.
/// </remarks>
T GetCacheObject<T>(string key);
List<T> GetPagedListCacheObject<T>(string rootKey, int page);
/// <summary>
/// Can be used as a notification mechanism for downstream actions when cache is invalidated.
/// </summary>
/// <remarks>
/// Implementations of ICacheHelper should call this event whenever they invalidate a cached object.
/// </remarks>
event Action<string> OnRemoveCacheKey;
string GetEffectiveCacheKey(string key);
}
================================================
FILE: src/PopForums/Configuration/Settings.cs
================================================
namespace PopForums.Configuration;
public class Settings
{
public Settings()
{
TermsOfService = string.Empty;
IsNewUserApproved = true;
TopicsPerPage = 20;
PostsPerPage = 20;
ForumTitle = string.Empty;
MinimumSecondsBetweenPosts = 30;
SmtpServer = "localhost";
SmtpPort = 25;
MailerAddress = string.Empty;
ReplyToAddress = string.Empty;
UseEsmtp = false;
SmtpUser = string.Empty;
SmtpPassword = string.Empty;
MailSendingInverval = 1500;
UseSslSmtp = false;
SessionLength = 20;
CensorWords = string.Empty;
CensorCharacter = "*";
AllowImages = false;
LogSecurity = true;
LogModeration = true;
LogErrors = true;
IsNewUserImageApproved = false;
SearchIndexingInterval = 10000;
IsSearchIndexingEnabled = true;
IsMailerEnabled = true;
UserImageMaxHeight = 300;
UserImageMaxWidth = 400;
UserImageMaxkBytes = 100;
UserAvatarMaxHeight = 90;
UserAvatarMaxWidth = 90;
UserAvatarMaxkBytes = 10;
MailSignature = string.Empty;
ScoringGameCalculatorInterval = 1000;
MailerQuantity = 4;
UseGoogleLogin = false;
UseFacebookLogin = false;
FacebookAppID = string.Empty;
FacebookAppSecret = string.Empty;
UseMicrosoftLogin = false;
MicrosoftClientID = string.Empty;
MicrosoftClientSecret = string.Empty;
YouTubeHeight = 360;
YouTubeWidth = 640;
GoogleClientId = string.Empty;
GoogleClientSecret = string.Empty;
UseOAuth2Login = false;
OAuth2ClientID = string.Empty;
OAuth2ClientSecret = string.Empty;
OAuth2LoginUrl = string.Empty;
OAuth2TokenUrl = string.Empty;
OAuth2DisplayName = string.Empty;
OAuth2Scope = "email";
IsClosingAgedTopics = false;
CloseAgedTopicsDays = 365;
IsPrivateForumInstance = false;
PostImageMaxHeight = 1000;
PostImageMaxWidth = 1000;
PostImageMaxkBytes = 5000;
}
public virtual string TermsOfService { get; set; }
public virtual bool IsNewUserApproved { get; set; }
public virtual int TopicsPerPage { get; set; }
public virtual int PostsPerPage { get; set; }
public virtual string ForumTitle { get; set; }
public virtual int MinimumSecondsBetweenPosts { get; set; }
public virtual string SmtpServer { get; set; }
public virtual int SmtpPort { get; set; }
public virtual string MailerAddress { get; set; }
public virtual string ReplyToAddress { get; set; }
public virtual bool UseEsmtp { get; set; }
public virtual string SmtpUser { get; set; }
public virtual string SmtpPassword { get; set; }
public virtual int MailSendingInverval { get; set; }
public virtual bool UseSslSmtp { get; set; }
public virtual int SessionLength { get; set; }
public virtual string CensorWords { get; set; }
public virtual string CensorCharacter { get; set; }
public virtual bool AllowImages { get; set; }
public virtual bool LogSecurity { get; set; }
public virtual bool LogModeration { get; set; }
public virtual bool LogErrors { get; set; }
public virtual bool IsNewUserImageApproved { get; set; }
public virtual int SearchIndexingInterval { get; set; }
public virtual bool IsSearchIndexingEnabled { get; set; }
public virtual bool IsMailerEnabled { get; set; }
public virtual int UserImageMaxHeight { get; set; }
public virtual int UserImageMaxWidth { get; set; }
public virtual int UserImageMaxkBytes { get; set; }
public virtual int UserAvatarMaxHeight { get; set; }
public virtual int UserAvatarMaxWidth { get; set; }
public virtual int UserAvatarMaxkBytes { get; set; }
public virtual string MailSignature { get; set; }
public virtual int ScoringGameCalculatorInterval { get; set; }
public virtual int MailerQuantity { get; set; }
public virtual bool UseGoogleLogin { get; set; }
public virtual bool UseFacebookLogin { get; set; }
public virtual string FacebookAppID { get; set; }
public virtual string FacebookAppSecret { get; set; }
public virtual bool UseMicrosoftLogin { get; set; }
public virtual string MicrosoftClientID { get; set; }
public virtual string MicrosoftClientSecret { get; set; }
public virtual int YouTubeHeight { get; set; }
public virtual int YouTubeWidth { get; set; }
public virtual string GoogleClientId { get; set; }
public virtual string GoogleClientSecret { get; set; }
public virtual bool UseOAuth2Login { get; set; }
public virtual string OAuth2ClientID { get; set; }
public virtual string OAuth2ClientSecret { get; set; }
public virtual string OAuth2LoginUrl { get; set; }
public virtual string OAuth2TokenUrl { get; set; }
public virtual string OAuth2DisplayName { get; set; }
public virtual string OAuth2Scope { get; set; }
public virtual bool IsClosingAgedTopics { get; set; }
public virtual int CloseAgedTopicsDays { get; set; }
public virtual bool IsPrivateForumInstance { get; set; }
public virtual int PostImageMaxHeight { get; set; }
public virtual int PostImageMaxWidth { get; set; }
public virtual int PostImageMaxkBytes { get; set; }
}
================================================
FILE: src/PopForums/Configuration/SettingsManager.cs
================================================
namespace PopForums.Configuration;
public interface ISettingsManager
{
Settings Current { get; }
void SaveCurrent();
void Save(Settings settings);
}
public class SettingsManager : ISettingsManager
{
public SettingsManager(ISettingsRepository settingsRepository, IErrorLog errorLog)
{
_settingsRepository = settingsRepository;
_errorLog = errorLog;
_settingsRepository.OnSettingsInvalidated += () =>
{
_settings = null;
};
}
private readonly ISettingsRepository _settingsRepository;
private readonly IErrorLog _errorLog;
private Settings _settings;
public Settings Current
{
get
{
if (_settings == null)
LoadSettings();
return _settings;
}
}
private void LoadSettings()
{
var dictionary = _settingsRepository.Get();
var settings = new Settings();
foreach (var setting in dictionary.Keys)
{
var property = settings.GetType().GetProperty(setting);
if (property == null)
{
_errorLog.Log(null, ErrorSeverity.Warning, $"Settings repository returned a setting called {setting}, which does not exist in code.");
}
else
{
switch (property.PropertyType.FullName)
{
case "System.Boolean":
property.SetValue(settings, Convert.ToBoolean(dictionary[setting]), null);
break;
case "System.String":
property.SetValue(settings, dictionary[setting], null);
break;
case "System.Int32":
property.SetValue(settings, Convert.ToInt32(dictionary[setting]), null);
break;
case "System.Double":
property.SetValue(settings, Convert.ToDouble(dictionary[setting]), null);
break;
case "System.DateTime":
property.SetValue(settings, Convert.ToDateTime(dictionary[setting]), null);
break;
default:
throw new Exception($"Settings loader not coded to convert values of type {property.PropertyType.FullName}.");
}
}
}
_settings = settings;
}
public void Save(Settings settings)
{
_settings = settings;
SaveCurrent();
}
public void SaveCurrent()
{
var dictionary = new Dictionary<string, object>();
var properties = Current.GetType().GetProperties();
foreach (var property in properties)
{
dictionary.Add(property.Name, property.GetValue(Current, null));
}
_settingsRepository.Save(dictionary);
}
}
================================================
FILE: src/PopForums/Email/EmailQueuePayload.cs
================================================
namespace PopForums.Email;
public class EmailQueuePayload
{
public int MessageID { get; set; }
public EmailQueuePayloadType EmailQueuePayloadType { get; set; }
public string ToEmail { get; set; }
public string ToName { get; set; }
public string TenantID { get; set; }
}
================================================
FILE: src/PopForums/Email/EmailQueuePayloadType.cs
================================================
namespace PopForums.Email;
public enum EmailQueuePayloadType
{
FullMessage = 1,
MassMessage = 2,
DeleteMassMessage = 3
}
================================================
FILE: src/PopForums/Email/EmailWorker.cs
================================================
namespace PopForums.Email;
public interface IEmailWorker
{
Task Execute();
}
public class EmailWorker(ISettingsManager settingsManager, ISmtpWrapper smtpWrapper, IQueuedEmailMessageRepository queuedEmailMessageRepository, IEmailQueueRepository emailQueueRepository, IErrorLog errorLog) : IEmailWorker
{
public async Task Execute()
{
try
{
var messageGroup = new List<QueuedEmailMessage>();
for (var i = 1; i <= settingsManager.Current.MailerQuantity; i++)
{
var payload = await emailQueueRepository.Dequeue();
if (payload == null)
break;
if (payload.EmailQueuePayloadType == EmailQueuePayloadType.DeleteMassMessage)
throw new NotImplementedException($"EmailQueuePayloadType {payload.EmailQueuePayloadType} not implemented.");
var queuedMessage = await queuedEmailMessageRepository.GetMessage(payload.MessageID);
if (payload.EmailQueuePayloadType == EmailQueuePayloadType.MassMessage)
{
queuedMessage.ToEmail = payload.ToEmail;
queuedMessage.ToName = payload.ToName;
}
if (queuedMessage == null)
break;
messageGroup.Add(queuedMessage);
await queuedEmailMessageRepository.DeleteMessage(queuedMessage.MessageID);
}
Parallel.ForEach(messageGroup, message =>
{
try
{
smtpWrapper.Send(message);
}
catch (Exception exc)
{
if (message == null)
errorLog.Log(exc, ErrorSeverity.Email, "There was no message for the MailWorker to send.");
else
errorLog.Log(exc, ErrorSeverity.Email, $"MessageID: {message.MessageID}, To: <{message.ToEmail}> {message.ToName}, Subject: {message.Subject}");
}
});
}
catch (Exception exc)
{
errorLog.Log(exc, ErrorSeverity.Error);
}
}
}
================================================
FILE: src/PopForums/Email/ForgotPasswordMailer.cs
================================================
namespace PopForums.Email;
public interface IForgotPasswordMailer
{
Task ComposeAndQueue(User user, string resetLink);
}
public class ForgotPasswordMailer : IForgotPasswordMailer
{
public ForgotPasswordMailer(ISettingsManager settingsManager, IQueuedEmailService queuedEmailService)
{
_settingsManager = settingsManager;
_queuedEmailService = queuedEmailService;
}
private readonly ISettingsManager _settingsManager;
private readonly IQueuedEmailService _queuedEmailService;
public async Task ComposeAndQueue(User user, string resetLink)
{
if (user == null)
throw new ArgumentNullException("user");
if (String.IsNullOrEmpty(resetLink))
throw new ArgumentException("resetLink");
var settings = _settingsManager.Current;
var body = String.Format(Resources.ForgotPasswordEmail
, settings.ForumTitle, resetLink, settings.MailSignature, Environment.NewLine);
var message = new QueuedEmailMessage
{
Body = body,
Subject = String.Format(Resources.ForgotPasswordSubject, settings.ForumTitle),
ToEmail = user.Email,
ToName = user.Name,
FromName = settings.ForumTitle,
QueueTime = DateTime.UtcNow
};
await _queuedEmailService.CreateAndQueueEmail(message);
}
}
================================================
FILE: src/PopForums/Email/MailingListComposer.cs
================================================
namespace PopForums.Email;
public interface IMailingListComposer
{
void ComposeAndQueue(User user, string subject, string body, string htmlBody, string unsubscribeLink);
}
public class MailingListComposer : IMailingListComposer
{
public MailingListComposer(ISettingsManager settingsManager, IQueuedEmailService queuedEmailService)
{
_settingsManager = settingsManager;
_queuedEmailService = queuedEmailService;
}
private readonly ISettingsManager _settingsManager;
private readonly IQueuedEmailService _queuedEmailService;
public void ComposeAndQueue(User user, string subject, string body, string htmlBody, string unsubscribeLink)
{
var settings = _settingsManager.Current;
var ps = $"{Environment.NewLine}{Environment.NewLine}Unsubscribe: {unsubscribeLink}";
var message = new QueuedEmailMessage
{
Body = body + ps,
Subject = subject,
ToEmail = user.Email,
ToName = user.Name,
FromName = settings.ForumTitle,
QueueTime = DateTime.UtcNow
};
if (!string.IsNullOrWhiteSpace(htmlBody))
message.HtmlBody = $"{htmlBody}<p>Unsubscribe: <a href=\"{unsubscribeLink}\">{unsubscribeLink}</a></p>";
_queuedEmailService.CreateAndQueueEmail(message);
}
}
================================================
FILE: src/PopForums/Email/NewAccountMailer.cs
================================================
namespace PopForums.Email;
public interface INewAccountMailer
{
SmtpStatusCode? Send(User user, string verifyUrl);
/// <summary>
/// Used to deliver the text for a welcome e-mail, where the user is already
/// approved. The default implementation uses Resources.RegisterEmailThankYou.
/// It uses the following string format items:
/// {0} Forum title (from settings)
/// {1} Mail signature (from settings)
/// {2} Environment.NewLine
/// </summary>
string NewUserApprovedEmail { get; }
/// <summary>
/// Used to deliver the text for a welcome e-mail, where the user is must follow
/// a verification link. The default implementation uses Resources.RegisterEmailThankYou.
/// It uses the following string format items:
/// {0} Forum title (from settings)
/// {1} Verification URL + auth code (generated by calling code)
/// {2} Verification URL
/// {3} Authorization key (from user object)
/// {4} Mail signature (from settings)
/// {5} Environment.NewLine
/// </summary>
string NewUserVerifyEmail { get; }
}
public class NewAccountMailer : INewAccountMailer
{
public NewAccountMailer(ISettingsManager settingsManager, ISmtpWrapper smtpWrapper)
{
_settingsManager = settingsManager;
_smtpWrapper = smtpWrapper;
}
private readonly ISettingsManager _settingsManager;
private readonly ISmtpWrapper _smtpWrapper;
public SmtpStatusCode? Send(User user, string verifyUrl)
{
var settings = _settingsManager.Current;
if (String.IsNullOrWhiteSpace(settings.MailerAddress))
throw new Exception("There is no MailerAddress to send e-mail from. Perhaps you didn't set up the settings.");
var message = new EmailMessage
{
ToEmail = user.Email,
ToName = user.Name,
FromName = settings.ForumTitle
};
message.Subject = String.Format(Resources.RegisterEmailSubject, settings.ForumTitle);
string body;
if (settings.IsNewUserApproved)
body = String.Format(NewUserApprovedEmail, settings.ForumTitle, settings.MailSignature, "\r\n");
else
body = String.Format(NewUserVerifyEmail, settings.ForumTitle, verifyUrl + "/" + user.AuthorizationKey, verifyUrl, user.AuthorizationKey, settings.MailSignature, "\r\n");
message.Body = body;
return _smtpWrapper.Send(message);
}
public virtual string NewUserApprovedEmail
{
get { return Resources.RegisterEmailThankYou; }
}
public virtual string NewUserVerifyEmail
{
get { return Resources.RegisterEmailThankYouVerify; }
}
}
================================================
FILE: src/PopForums/Email/SmtpStatusCode.cs
================================================
namespace PopForums.Email;
public enum SmtpStatusCode
{
SystemStatus = 211,
HelpMessage = 214,
ServiceReady = 220,
ServiceClosingTransmissionChannel = 221,
AuthenticationSuccessful = 235,
Ok = 250,
UserNotLocalWillForward = 251,
CannotVerifyUserWillAttemptDelivery = 252,
AuthenticationChallenge = 334,
StartMailInput = 354,
ServiceNotAvailable = 421,
PasswordTransitionNeeded = 432,
MailboxBusy = 450,
ErrorInProcessing = 451,
InsufficientStorage = 452,
TemporaryAuthenticationFailure = 454,
CommandUnrecognized = 500,
SyntaxError = 501,
CommandNotImplemented = 502,
BadCommandSequence = 503,
CommandParameterNotImplemented = 504,
AuthenticationRequired = 530,
AuthenticationMechanismTooWeak = 534,
AuthenticationInvalidCredentials = 535,
EncryptionRequiredForAuthenticationMechanism = 538,
MailboxUnavailable = 550,
UserNotLocalTryAlternatePath = 551,
ExceededStorageAllocation = 552,
MailboxNameNotAllowed = 553,
TransactionFailed = 554,
MailFromOrRcptToParametersNotRecognizedOrNotImplemented = 555
}
================================================
FILE: src/PopForums/Email/SmtpWrapper.cs
================================================
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
namespace PopForums.Email;
public interface ISmtpWrapper
{
SmtpStatusCode? Send(EmailMessage message);
}
public class SmtpWrapper : ISmtpWrapper
{
public SmtpWrapper(ISettingsManager settingsManager, IErrorLog errorLog)
{
_settingsManager = settingsManager;
_errorLog = errorLog;
}
private readonly ISettingsManager _settingsManager;
private readonly IErrorLog _errorLog;
public SmtpStatusCode? Send(EmailMessage message)
{
if (message == null)
throw new ArgumentNullException(nameof(message));
var parsedMessage = ConvertEmailMessage(message);
var settings = _settingsManager.Current;
SmtpStatusCode? result = SmtpStatusCode.Ok;
using var client = new SmtpClient();
try
{
client.Connect(settings.SmtpServer, settings.SmtpPort, settings.UseSslSmtp ? SecureSocketOptions.StartTls : SecureSocketOptions.None);
if (settings.UseEsmtp)
client.Authenticate(settings.SmtpUser, settings.SmtpPassword);
client.Send(parsedMessage);
}
catch (SmtpCommandException exc)
{
var statusCode = (int)exc.StatusCode;
result = (SmtpStatusCode)statusCode;
_errorLog.Log(exc, ErrorSeverity.Email, $"To: {message.ToEmail}, Subject: {message.Subject}, SmtpCommandException: {statusCode}");
}
catch (SmtpProtocolException exc)
{
result = null;
_errorLog.Log(exc, ErrorSeverity.Email, $"To: {message.ToEmail}, Subject: {message.Subject}, SmtpProtocolException: {exc.Message}");
}
catch (Exception exc)
{
result = null;
_errorLog.Log(exc, ErrorSeverity.Email, $"To: {message.ToEmail}, Subject: {message.Subject}, Exception: {exc.Message}");
}
finally
{
client.Disconnect(true);
}
return result;
}
private MimeMessage ConvertEmailMessage(EmailMessage forumMessage)
{
var message = new MimeMessage();
message.Headers.Add("X-Mailer", "POP Forums");
message.To.Add(new MailboxAddress(forumMessage.ToName, forumMessage.ToEmail));
message.From.Add(new MailboxAddress(forumMessage.FromName, _settingsManager.Current.MailerAddress));
if (!string.IsNullOrWhiteSpace(forumMessage.ReplyTo))
message.ReplyTo.Add(new MailboxAddress(forumMessage.FromName, forumMessage.ReplyTo));
else
message.ReplyTo.Add(new MailboxAddress(forumMessage.FromName, _settingsManager.Current.ReplyToAddress));
message.Subject = forumMessage.Subject;
var builder = new BodyBuilder();
builder.TextBody = forumMessage.Body;
builder.HtmlBody = forumMessage.HtmlBody;
message.Body = builder.ToMessageBody();
return message;
}
}
================================================
FILE: src/PopForums/Extensions/ServiceCollections.cs
================================================
namespace PopForums.Extensions;
public static class ServiceCollections
{
public static void AddPopForumsBase(this IServiceCollection services)
{
// config
services.AddTransient<IConfig, Config>();
services.AddTransient<IErrorLog, ErrorLog>();
services.AddSingleton<ISettingsManager, SettingsManager>();
services.AddTransient<ITenantService, TenantService>();
// composers
services.AddTransient<ITopicStateComposer, TopicStateComposer>();
services.AddTransient<IForumStateComposer, ForumStateComposer>();
services.AddTransient<IPrivateMessageStateComposer, PrivateMessageStateComposer>();
// email
services.AddTransient<IForgotPasswordMailer, ForgotPasswordMailer>();
services.AddTransient<IMailingListComposer, MailingListComposer>();
services.AddTransient<INewAccountMailer, NewAccountMailer>();
services.AddTransient<ISmtpWrapper, SmtpWrapper>();
services.AddTransient<IEmailWorker, EmailWorker>();
// external auth?
services.AddTransient<IExternalUserAssociationManager, ExternalUserAssociationManager>();
// feeds
services.AddTransient<IFeedService, FeedService>();
// scoring game
services.AddTransient<IAwardCalculator, AwardCalculator>();
services.AddTransient<IAwardDefinitionService, AwardDefinitionService>();
services.AddTransient<IEventDefinitionService, EventDefinitionService>();
services.AddTransient<IEventPublisher, EventPublisher>();
services.AddTransient<IUserAwardService, UserAwardService>();
// services
services.AddTransient<IBanService, BanService>();
services.AddTransient<ICategoryService, CategoryService>();
services.AddTransient<IFavoriteTopicService, FavoriteTopicService>();
services.AddTransient<IForumService, ForumService>();
services.AddTransient<IImageService, ImageService>();
services.AddTransient<IIPHistoryService, IPHistoryService>();
services.AddTransient<ILastReadService, LastReadService>();
services.AddTransient<IMailingListService, MailingListService>();
services.AddTransient<IModerationLogService, ModerationLogService>();
services.AddTransient<IPostService, PostService>();
services.AddTransient<IPrivateMessageService, PrivateMessageService>();
services.AddTransient<IProfileService, ProfileService>();
services.AddTransient<IQueuedEmailService, QueuedEmailService>();
services.AddTransient<ISearchService, SearchService>();
services.AddTransient<ISecurityLogService, SecurityLogService>();
services.AddTransient<ISetupService, SetupService>();
services.AddTransient<ISubscribedTopicsService, SubscribedTopicsService>();
services.AddTransient<ITextParsingService, TextParsingService>();
services.AddTransient<ITopicService, TopicService>();
services.AddTransient<ITopicViewLogService, TopicViewLogService>();
services.AddTransient<IUserService, UserService>();
services.AddTransient<IUserSessionService, UserSessionService>();
services.AddTransient<IServiceHeartbeatService, ServiceHeartbeatService>();
services.AddTransient<ISearchIndexSubsystem, SearchIndexSubsystem>();
services.AddTransient<IPostMasterService, PostMasterService>();
services.AddTransient<IForumPermissionService, ForumPermissionService>();
services.AddTransient<IReCaptchaService, ReCaptchaService>();
services.AddTransient<ISitemapService, SitemapService>();
services.AddTransient<ITimeFormatStringService, TimeFormatStringService>();
services.AddTransient<IResourceComposer, ResourceComposer>();
services.AddTransient<INotificationManager, NotificationManager>();
services.AddTransient<INotificationAdapter, NotificationAdapter>();
services.AddTransient<INotificationTunnel, NotificationTunnel>();
services.AddTransient<IPostImageService, PostImageService>();
services.AddTransient<IClaimsToRoleMapper, ClaimsToRoleMapper>();
services.AddTransient<IUserNameReconciler, UserNameReconciler>();
services.AddTransient<IUserEmailReconciler, UserEmailReconciler>();
services.AddTransient<IUserSessionWorker, UserSessionWorker>();
services.AddTransient<ISearchIndexWorker, SearchIndexWorker>();
services.AddTransient<IAwardCalculatorWorker, AwardCalculatorWorker>();
services.AddTransient<ICloseAgedTopicsWorker, CloseAgedTopicsWorker>();
services.AddTransient<IPostImageCleanupWorker, PostImageCleanupWorker>();
services.AddTransient<ISubscribeNotificationWorker, SubscribeNotificationWorker>();
services.AddTransient<IIgnoreService, IgnoreService>();
}
}
================================================
FILE: src/PopForums/Extensions/Streams.cs
================================================
namespace PopForums.Extensions;
public static class Streams
{
public static byte[] ToBytes(this Stream stream)
{
var length = (int)stream.Length;
var bytes = new byte[length];
stream.ReadExactly(bytes, 0, length);
return bytes;
}
}
================================================
FILE: src/PopForums/Extensions/Strings.cs
================================================
namespace PopForums.Extensions;
public static class Strings
{
public static string GetSHA256Hash(this string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return string.Empty;
}
var input = Encoding.UTF8.GetBytes(text);
using (var sha256 = SHA256.Create())
{
var output = sha256.ComputeHash(input);
return Convert.ToBase64String(output);
}
}
public static string GetSHA256Hash(this string text, Guid salt)
{
var concatString = text + salt;
return GetSHA256Hash(concatString);
}
public static string GetMD5Hash(this string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return string.Empty;
}
var input = Encoding.UTF8.GetBytes(text);
using (var md5 = MD5.Create())
{
var output = md5.ComputeHash(input);
return Convert.ToBase64String(output);
}
}
public static string GetMD5Hash(this string text, Guid salt)
{
var concatString = text + salt;
return GetMD5Hash(concatString);
}
public static bool IsEmailAddress(this string text)
{
return Regex.IsMatch(text, @"^\S+?@([a-z0-9\-\.])+?\.([a-z0-9\-\.])+$", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
}
public static string ToUrlName(this string text)
{
if (text == null)
throw new Exception("Can't Url convert a null string.");
var result = text.Replace(" ", "-");
var replacer = new Regex(@"[^\w\-]", RegexOptions.None);
result = replacer.Replace(result, "").ToLower();
return result;
}
public static string ToUniqueUrlName(this string name, List<string> matchingStartsWith)
{
var urlName = name.ToUrlName();
return ToUniqueName(urlName, matchingStartsWith);
}
public static string ToUniqueName(this string name, List<string> matchingStartsWith)
{
name = Regex.Escape(name).Replace("\\ ", " ");
var originalName = name;
var matchTest = name.Replace("-", @"\-");
var count = matchingStartsWith.Count(m => Regex.IsMatch(m, @"^(" + matchTest + @")(\-\d)?$"));
if (count > 0)
name = name + "-" + (count + 1);
while (matchingStartsWith.Exists(x => x == name))
{
count++;
name = originalName + "-" + (count + 1);
}
return name;
}
public static string Trimmer(this string stringToTrim, int maxLength)
{
if (maxLength < 20) maxLength = 20;
if (stringToTrim.Length <= maxLength) return stringToTrim;
return stringToTrim.Substring(0, maxLength - 13) + "..." +
stringToTrim.Substring(stringToTrim.Length - 10, 10);
}
}
================================================
FILE: src/PopForums/Extensions/Users.cs
================================================
namespace PopForums.Extensions;
public static class Users
{
public static bool IsPostEditable(this User user, Post post)
{
if (user == null)
return false;
return user.IsInRole(PermanentRoles.Moderator) || user.UserID == post.UserID;
}
}
================================================
FILE: src/PopForums/ExternalLogin/ExternalAuthenticationResult.cs
================================================
namespace PopForums.ExternalLogin;
public class ExternalAuthenticationResult
{
public string Issuer { get; set; }
public string ProviderKey { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
================================================
FILE: src/PopForums/ExternalLogin/ExternalLoginInfo.cs
================================================
namespace PopForums.ExternalLogin;
public class ExternalLoginInfo
{
public ExternalLoginInfo(string loginProvider, string providerKey,
string displayName)
{
LoginProvider = loginProvider;
ProviderKey = providerKey;
ProviderDisplayName = displayName;
}
public string LoginProvider { get; set; }
public string ProviderKey { get; set; }
public string ProviderDisplayName { get; set; }
}
================================================
FILE: src/PopForums/ExternalLogin/ExternalUserAssociation.cs
================================================
namespace PopForums.ExternalLogin;
public class ExternalUserAssociation
{
public int ExternalUserAssociationID { get; set; }
public int UserID { get; set; }
public string Issuer { get; set; }
public string ProviderKey { get; set; }
public string Name { get; set; }
}
================================================
FILE: src/PopForums/ExternalLogin/ExternalUserAssociationManager.cs
================================================
namespace PopForums.ExternalLogin;
public interface IExternalUserAssociationManager
{
Task<ExternalUserAssociationMatchResult> ExternalUserAssociationCheck(ExternalLoginInfo externalLoginInfo, string ip);
Task Associate(User user, ExternalLoginInfo externalLoginInfo, string ip);
Task<List<ExternalUserAssociation>> GetExternalUserAssociations(User user);
Task RemoveAssociation(User user, int externalUserAssociationID, string ip);
}
public class ExternalUserAssociationManager : IExternalUserAssociationManager
{
public ExternalUserAssociationManager(IExternalUserAssociationRepository externalUserAssociationRepository, IUserRepository userRepository, ISecurityLogService securityLogService)
{
_externalUserAssociationRepository = externalUserAssociationRepository;
_userRepository = userRepository;
_securityLogService = securityLogService;
}
private readonly IExternalUserAssociationRepository _externalUserAssociationRepository;
private readonly IUserRepository _userRepository;
private readonly ISecurityLogService _securityLogService;
public async Task<ExternalUserAssociationMatchResult> ExternalUserAssociationCheck(ExternalLoginInfo externalLoginInfo, string ip)
{
if (externalLoginInfo == null)
throw new ArgumentNullException(nameof(externalLoginInfo));
var match = await _externalUserAssociationRepository.Get(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey);
if (match == null)
{
await _securityLogService.CreateLogEntry((int?)null, null, ip, $"Issuer: {externalLoginInfo.LoginProvider}, Provider: {externalLoginInfo.ProviderKey}, Name: {externalLoginInfo.ProviderDisplayName}", SecurityLogType.ExternalAssociationCheckFailed);
return new ExternalUserAssociationMatchResult {Successful = false};
}
var user = await _userRepository.GetUser(match.UserID);
if (user == null)
{
await _securityLogService.CreateLogEntry((int?)null, null, ip, $"Issuer: {externalLoginInfo.LoginProvider}, Provider: {externalLoginInfo.ProviderKey}, Name: {externalLoginInfo.ProviderDisplayName}", SecurityLogType.ExternalAssociationCheckFailed);
return new ExternalUserAssociationMatchResult {Successful = false};
}
var result = new ExternalUserAssociationMatchResult
{
Successful = true,
ExternalUserAssociation = match,
User = user
};
await _securityLogService.CreateLogEntry(user, user, ip, $"Issuer: {match.Issuer}, Provider: {match.ProviderKey}, Name: {match.Name}", SecurityLogType.ExternalAssociationCheckSuccessful);
return result;
}
public async Task Associate(User user, ExternalLoginInfo externalLoginInfo, string ip)
{
if (user == null)
throw new ArgumentNullException(nameof(user));
if (externalLoginInfo != null)
{
if (string.IsNullOrEmpty(externalLoginInfo.LoginProvider))
throw new NullReferenceException("The external login info contains no provider.");
if (string.IsNullOrEmpty(externalLoginInfo.ProviderKey))
throw new NullReferenceException("The external login info contains no provider key.");
if (string.IsNullOrEmpty(externalLoginInfo.ProviderDisplayName))
externalLoginInfo.ProviderDisplayName = string.Empty;
await _externalUserAssociationRepository.Save(user.UserID, externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey, externalLoginInfo.ProviderDisplayName);
await _securityLogService.CreateLogEntry(user, user, ip, $"Provider: {externalLoginInfo.LoginProvider}, DisplayName: {externalLoginInfo.ProviderDisplayName}", SecurityLogType.ExternalAssociationSet);
}
}
public async Task<List<ExternalUserAssociation>> GetExternalUserAssociations(User user)
{
return await _externalUserAssociationRepository.GetByUser(user.UserID);
}
public async Task RemoveAssociation(User user, int externalUserAssociationID, string ip)
{
var association = await _externalUserAssociationRepository.Get(externalUserAssociationID);
if (association == null)
return;
if (association.UserID != user.UserID)
throw new Exception($"Can't delete external user association {externalUserAssociationID} because it doesn't match UserID {user.UserID}.");
await _externalUserAssociationRepository.Delete(externalUserAssociationID);
await _securityLogService.CreateLogEntry(user, user, ip, $"Issuer: {association.Issuer}, Provider: {association.ProviderKey}, Name: {association.Name}", SecurityLogType.ExternalAssociationRemoved);
}
}
================================================
FILE: src/PopForums/ExternalLogin/ExternalUserAssociationMatchResult.cs
================================================
namespace PopForums.ExternalLogin;
public class ExternalUserAssociationMatchResult
{
public bool Successful { get; set; }
public ExternalUserAssociation ExternalUserAssociation { get; set; }
public User User { get; set; }
}
================================================
FILE: src/PopForums/Feeds/FeedService.cs
================================================
namespace PopForums.Feeds;
public interface IFeedService
{
Task PublishToFeed(User user, string message, int points, DateTime timeStamp);
Task<List<FeedEvent>> GetFeed(User user);
}
public class FeedService : IFeedService
{
public FeedService(IFeedRepository feedRepository, IBroker broker)
{
_feedRepository = feedRepository;
_broker = broker;
}
private readonly IFeedRepository _feedRepository;
private readonly IBroker _broker;
public const int MaxFeedCount = 50;
public async Task PublishToFeed(User user, string message, int points, DateTime timeStamp)
{
if (user == null)
return;
await _feedRepository.PublishEvent(user.UserID, message, points, timeStamp);
var cutOff = await _feedRepository.GetOldestTime(user.UserID, MaxFeedCount);
await _feedRepository.DeleteOlderThan(user.UserID, cutOff);
}
public async Task<List<FeedEvent>> GetFeed(User user)
{
return await _feedRepository.GetFeed(user.UserID, MaxFeedCount);
}
}
================================================
FILE: src/PopForums/Global.cs
================================================
global using System;
global using System.Collections;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Security;
global using System.Security.Cryptography;
global using System.Text;
global using System.Text.Encodings.Web;
global using System.Text.Json;
global using System.Text.Json.Serialization;
global using System.Text.RegularExpressions;
global using System.Threading;
global using System.Threading.Tasks;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using PopForums.Composers;
global using PopForums.Configuration;
global using PopForums.Email;
global using PopForums.Extensions;
global using PopForums.ExternalLogin;
global using PopForums.Feeds;
global using PopForums.Messaging;
global using PopForums.Models;
global using PopForums.Repositories;
global using PopForums.ScoringGame;
global using PopForums.Services;
================================================
FILE: src/PopForums/Messaging/IBroker.cs
================================================
namespace PopForums.Messaging;
public interface IBroker
{
void NotifyNewPosts(Topic topic, int lasPostID);
void NotifyForumUpdate(Forum forum);
void NotifyTopicUpdate(Topic topic, Forum forum, string topicLink);
void NotifyNewPost(Topic topic, int postID);
void NotifyPMCount(int userID, int pmCount);
void NotifyUser(Notification notification);
void NotifyUser(Notification notification, string tenantID);
void SendPMMessage(PrivateMessagePost post);
}
================================================
FILE: src/PopForums/Messaging/Models/AwardData.cs
================================================
namespace PopForums.Messaging.Models;
public class AwardData
{
public string Title { get; set; }
}
================================================
FILE: src/PopForums/Messaging/Models/AwardPayload.cs
================================================
namespace PopForums.Messaging.Models;
public class AwardPayload
{
public string Title { get; set; }
public int UserID { get; set; }
public string TenantID { get; set; }
}
================================================
FILE: src/PopForums/Messaging/Models/QuestionData.cs
================================================
namespace PopForums.Messaging.Models;
public class QuestionData
{
public string AskerName { get; set; }
public string Title { get; set; }
public int PostID { get; set; }
}
================================================
FILE: src/PopForums/Messaging/Models/ReplyData.cs
================================================
namespace PopForums.Messaging.Models;
public class ReplyData
{
public string PostName { get; set; }
public int TopicID { get; set; }
public string Title { get; set; }
}
================================================
FILE: src/PopForums/Messaging/Models/ReplyPayload.cs
================================================
namespace PopForums.Messaging.Models;
public class ReplyPayload
{
public string PostName { get; set; }
public string Title { get; set; }
public int TopicID { get; set; }
public int UserID { get; set; }
public string TenantID { get; set; }
}
================================================
FILE: src/PopForums/Messaging/Models/VoteData.cs
================================================
namespace PopForums.Messaging.Models;
public class VoteData
{
public string VoterName { get; set; }
public string Title { get; set; }
public int PostID { get; set; }
}
================================================
FILE: src/PopForums/Messaging/Notification.cs
================================================
namespace PopForums.Messaging;
public class Notification
{
public int UserID { get; set; }
public DateTime TimeStamp { get; set; }
public bool IsRead { get; set; }
public NotificationType NotificationType { get; set; }
public long ContextID { get; set; }
public JsonElement Data { get; set; }
public int UnreadCount { get; set; }
}
================================================
FILE: src/PopForums/Messaging/NotificationAdapter.cs
================================================
using PopForums.Messaging.Models;
namespace PopForums.Messaging;
public interface INotificationAdapter
{
Task Reply(string postName, string title, int topicID, int userID, string tenantID);
Task Vote(string voterName, string title, int postID, int userID);
Task QuestionAnswer(string askerName, string title, int postID, int userID);
Task Award(string title, int userID);
Task Award(string title, int userID, string tenantID);
}
public class NotificationAdapter : INotificationAdapter
{
private readonly INotificationManager _notificationManager;
public NotificationAdapter(INotificationManager notificationManager)
{
_notificationManager = notificationManager;
}
public async Task Reply(string postName, string title, int topicID, int userID, string tenantID)
{
var replyData = new ReplyData
{
PostName = postName,
Title = title,
TopicID = topicID
};
await _notificationManager.ProcessNotification(userID, NotificationType.NewReply, replyData.TopicID, replyData, tenantID);
}
public async Task Vote(string voterName, string title, int postID, int userID)
{
var voteData = new VoteData
{
VoterName = voterName,
Title = title,
PostID = postID
};
await _notificationManager.ProcessNotification(userID, NotificationType.VoteUp, postID, voteData);
}
public async Task QuestionAnswer(string askerName, string title, int postID, int userID)
{
var questionData = new QuestionData
{
AskerName = askerName,
Title = title,
PostID = postID
};
await _notificationManager.ProcessNotification(userID, NotificationType.QuestionAnswered, postID, questionData);
}
public async Task Award(string title, int userID)
{
await Award(title, userID, null);
}
public async Task Award(string title, int userID, string tenantID)
{
var awardData = new AwardData
{
Title = title
};
var sequentialContext = DateTime.UtcNow.Ticks;
await _notificationManager.ProcessNotification(userID, NotificationType.Award, sequentialContext, awardData, tenantID);
}
}
================================================
FILE: src/PopForums/Messaging/NotificationManager.cs
================================================
namespace PopForums.Messaging;
public interface INotificationManager
{
Task MarkNotificationRead(int userID, NotificationType notificationType, long contextID);
Task ProcessNotification(int userID, NotificationType notificationType, long contextID, dynamic data);
Task ProcessNotification(int userID, NotificationType notificationType, long contextID, dynamic data, string tenantID);
Task<int> GetUnreadNotificationCount(int userID);
Task MarkAllRead(int userID);
Task<List<Notification>> GetNotifications(int userID, DateTime afterDateTime);
}
public class NotificationManager : INotificationManager
{
private readonly INotificationRepository _notificationRepository;
private readonly IBroker _broker;
private const int PageSize = 20;
private const int MaxNotificationCount = 100;
public NotificationManager(INotificationRepository notificationRepository, IBroker broker)
{
_notificationRepository = notificationRepository;
_broker = broker;
}
public async Task ProcessNotification(int userID, NotificationType notificationType, long contextID, dynamic data)
{
await ProcessNotification(userID, notificationType, contextID, data, null);
}
public async Task ProcessNotification(int userID, NotificationType notificationType, long contextID, dynamic data, string tenantID)
{
var serializedData = JsonSerializer.SerializeToElement(data, new JsonSerializerOptions{ PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
var notification = new Notification
{
UserID = userID,
TimeStamp = DateTime.UtcNow,
IsRead = false,
NotificationType = notificationType,
ContextID = contextID,
Data = serializedData
};
var recordsUpdated = await _notificationRepository.UpdateNotification(notification);
if (recordsUpdated == 0)
await _notificationRepository.CreateNotification(notification);
notification.UnreadCount = await _notificationRepository.GetUnreadNotificationCount(userID);
if (tenantID == null || string.IsNullOrWhiteSpace(tenantID))
_broker.NotifyUser(notification);
else
_broker.NotifyUser(notification, tenantID);
}
public async Task MarkNotificationRead(int userID, NotificationType notificationType, long contextID)
{
await _notificationRepository.MarkNotificationRead(userID, notificationType, contextID);
}
public async Task<List<Notification>> GetNotifications(int userID, DateTime afterDateTime)
{
return await _notificationRepository.GetNotifications(userID, afterDateTime, PageSize);
}
public async Task<int> GetUnreadNotificationCount(int userID)
{
var count = await _notificationRepository.GetUnreadNotificationCount(userID);
return count > MaxNotificationCount ? MaxNotificationCount : count;
}
public async Task MarkAllRead(int userID)
{
await _notificationRepository.MarkAllRead(userID);
}
}
================================================
FILE: src/PopForums/Messaging/NotificationTunnel.cs
================================================
namespace PopForums.Messaging;
public interface INotificationTunnel
{
void SendNotificationForUserAward(string title, int userID, string tenantID);
void SendNotificationForReply(string postName, string title, int topicID, int userID, string tenantID);
}
public class NotificationTunnel : INotificationTunnel
{
public static string HeaderName = "PfApi";
private readonly INotificationAdapter _notificationAdapter;
public NotificationTunnel(INotificationAdapter notificationAdapter)
{
_notificationAdapter = notificationAdapter;
}
public async void SendNotificationForUserAward(string title, int userID, string tenantID)
{
await _notificationAdapter.Award(title, userID, tenantID);
}
public async void SendNotificationForReply(string postName, string title, int topicID, int userID, string tenantID)
{
await _notificationAdapter.Reply(postName, title, topicID, userID, tenantID);
}
}
================================================
FILE: src/PopForums/Messaging/NotificationType.cs
================================================
namespace PopForums.Messaging;
public enum NotificationType
{
NewReply = 0,
VoteUp = 1,
QuestionAnswered = 2,
Award = 3
}
================================================
FILE: src/PopForums/Models/AwardCalculationPayload.cs
================================================
namespace PopForums.Models;
public class AwardCalculationPayload
{
public string EventDefinitionID { get; set; }
public int UserID { get; set; }
public string TenantID { get; set; }
}
================================================
FILE: src/PopForums/Models/BasicJsonMessage.cs
================================================
namespace PopForums.Models;
public class BasicJsonMessage
{
public bool Result { get; set; }
public string Message { get; set; }
public object Data { get; set; }
public string Redirect { get; set; }
}
================================================
FILE: src/PopForums/Models/BasicServiceResponse.cs
================================================
namespace PopForums.Models;
public class BasicServiceResponse<T> where T : class
{
public bool IsSuccessful { get; set; }
public string Message { get; set; }
public T Data { get; set; }
public string Redirect { get; set; }
}
================================================
FILE: src/PopForums/Models/CategorizedForumContainer.cs
================================================
namespace PopForums.Models;
public class CategorizedForumContainer
{
public CategorizedForumContainer(IEnumerable<Category> categories, IEnumerable<Forum> forums)
{
ReadStatusLookup = new Dictionary<int, ReadStatus>();
AllCategories = categories;
AllForums = forums;
UncategorizedForums = forums.Where(f => !f.CategoryID.HasValue || f.CategoryID == 0).OrderBy(f => f.SortOrder).ToList();
CategoryDictionary = new Dictionary<Category, List<Forum>>();
foreach (var category in AllCategories.OrderBy(c => c.SortOrder))
{
var forumSet = AllForums.Where(f => f.CategoryID == category.CategoryID).OrderBy(f => f.SortOrder).ToList();
if (forumSet.Count > 0)
CategoryDictionary.Add(category, forumSet);
}
}
public IEnumerable<Category> AllCategories { get; private set; }
public IEnumerable<Forum> AllForums { get; private set; }
public List<Forum> UncategorizedForums { get; private set; }
public Dictionary<Category, List<Forum>> CategoryDictionary { get; private set; }
public string ForumTitle { get; set; }
public Dictionary<int, ReadStatus> ReadStatusLookup { get; private set; }
}
================================================
FILE: src/PopForums/Models/Category.cs
================================================
namespace PopForums.Models;
public class Category
{
public int CategoryID { get; set; }
public string Title { get; set; }
public int SortOrder { get; set; }
}
================================================
FILE: src/PopForums/Models/CategoryContainerWithForums.cs
================================================
namespace PopForums.Models;
public class CategoryContainerWithForums
{
public Category Category { get; set; }
public IEnumerable<Forum> Forums { get; set; }
}
================================================
FILE: src/PopForums/Models/ClientPrivateMessagePost.cs
================================================
namespace PopForums.Models;
public class ClientPrivateMessagePost
{
public int PMPostID { get; set; }
public int UserID { get; set; }
public string Name { get; set; }
public string PostTime { get; set; }
public string FullText { get; set; }
public static ClientPrivateMessagePost[] MapForClient(List<PrivateMessagePost> posts)
{
var messages = posts.Select(x => new ClientPrivateMessagePost { PMPostID = x.PMPostID, UserID = x.UserID, Name = x.Name, PostTime = x.PostTime.ToString("o"), FullText = x.FullText }).ToArray();
return messages;
}
public static ClientPrivateMessagePost MapForClient(PrivateMessagePost post)
{
var message = new ClientPrivateMessagePost { PMPostID = post.PMPostID, UserID = post.UserID, Name = post.Name, PostTime = post.PostTime.ToString("o"), FullText = post.FullText };
return message;
}
}
================================================
FILE: src/PopForums/Models/DisplayProfile.cs
================================================
namespace PopForums.Models;
public class DisplayProfile
{
public DisplayProfile(User user, Profile profile, UserImage userImage)
{
UserID = user.UserID;
Name = user.Name;
Joined = user.CreationDate;
Dob = profile.Dob;
Location = profile.Location;
Web = profile.Web;
Instagram = profile.Instagram;
Facebook = profile.Facebook;
AvatarID = profile.AvatarID;
ImageID = profile.ImageID;
ShowDetails = profile.ShowDetails;
if (userImage != null && userImage.IsApproved)
IsImageApproved
gitextract_3gvf_42o/
├── .github/
│ └── workflows/
│ └── codeql.yml
├── .gitignore
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── LICENSE.txt
├── NuGet.config
├── PopForums.sln
├── PopForums.sln.DotSettings
├── README.md
├── SECURITY.md
├── docs/
│ ├── _config.yml
│ ├── architecture.md
│ ├── azurekitlibrary.md
│ ├── customization.md
│ ├── elastickitlibrary.md
│ ├── externalloginconfig.md
│ ├── faq.md
│ ├── features.md
│ ├── index.md
│ ├── multitenant.md
│ ├── oauthonly.md
│ ├── scoringgame.md
│ ├── starthere.md
│ └── versionhistory.md
└── src/
├── .editorconfig
├── PopForums/
│ ├── Composers/
│ │ ├── ForumStateComposer.cs
│ │ ├── PrivateMessageStateComposer.cs
│ │ ├── ResourceComposer.cs
│ │ └── TopicStateComposer.cs
│ ├── Configuration/
│ │ ├── Config.cs
│ │ ├── ConfigContainer.cs
│ │ ├── ConfigLoader.cs
│ │ ├── ErrorLog.cs
│ │ ├── ErrorLogException.cs
│ │ ├── ErrorSeverity.cs
│ │ ├── ICacheHelper.cs
│ │ ├── Settings.cs
│ │ └── SettingsManager.cs
│ ├── Email/
│ │ ├── EmailQueuePayload.cs
│ │ ├── EmailQueuePayloadType.cs
│ │ ├── EmailWorker.cs
│ │ ├── ForgotPasswordMailer.cs
│ │ ├── MailingListComposer.cs
│ │ ├── NewAccountMailer.cs
│ │ ├── SmtpStatusCode.cs
│ │ └── SmtpWrapper.cs
│ ├── Extensions/
│ │ ├── ServiceCollections.cs
│ │ ├── Streams.cs
│ │ ├── Strings.cs
│ │ └── Users.cs
│ ├── ExternalLogin/
│ │ ├── ExternalAuthenticationResult.cs
│ │ ├── ExternalLoginInfo.cs
│ │ ├── ExternalUserAssociation.cs
│ │ ├── ExternalUserAssociationManager.cs
│ │ └── ExternalUserAssociationMatchResult.cs
│ ├── Feeds/
│ │ └── FeedService.cs
│ ├── Global.cs
│ ├── Messaging/
│ │ ├── IBroker.cs
│ │ ├── Models/
│ │ │ ├── AwardData.cs
│ │ │ ├── AwardPayload.cs
│ │ │ ├── QuestionData.cs
│ │ │ ├── ReplyData.cs
│ │ │ ├── ReplyPayload.cs
│ │ │ └── VoteData.cs
│ │ ├── Notification.cs
│ │ ├── NotificationAdapter.cs
│ │ ├── NotificationManager.cs
│ │ ├── NotificationTunnel.cs
│ │ └── NotificationType.cs
│ ├── Models/
│ │ ├── AwardCalculationPayload.cs
│ │ ├── BasicJsonMessage.cs
│ │ ├── BasicServiceResponse.cs
│ │ ├── CategorizedForumContainer.cs
│ │ ├── Category.cs
│ │ ├── CategoryContainerWithForums.cs
│ │ ├── ClientPrivateMessagePost.cs
│ │ ├── DisplayProfile.cs
│ │ ├── EmailMessage.cs
│ │ ├── ErrorLogEntry.cs
│ │ ├── ExpiredUserSession.cs
│ │ ├── FeedEvent.cs
│ │ ├── Forum.cs
│ │ ├── ForumPermissionContainer.cs
│ │ ├── ForumPermissionContext.cs
│ │ ├── ForumState.cs
│ │ ├── ForumTopicContainer.cs
│ │ ├── IPHistoryEvent.cs
│ │ ├── IStreamResponse.cs
│ │ ├── Ignore.cs
│ │ ├── ModerationLogEntry.cs
│ │ ├── ModerationType.cs
│ │ ├── ModifyForumRolesContainer.cs
│ │ ├── ModifyForumRolesType.cs
│ │ ├── NewPost.cs
│ │ ├── PagedListOfT.cs
│ │ ├── PagedTopicContainer.cs
│ │ ├── PagerContext.cs
│ │ ├── PasswordResetContainer.cs
│ │ ├── PermanentRoles.cs
│ │ ├── Post.cs
│ │ ├── PostEdit.cs
│ │ ├── PostImage.cs
│ │ ├── PostImagePersistPayload.cs
│ │ ├── PostItemContainer.cs
│ │ ├── PostWithChildren.cs
│ │ ├── PrivateMessage.cs
│ │ ├── PrivateMessageBoxType.cs
│ │ ├── PrivateMessagePost.cs
│ │ ├── PrivateMessageState.cs
│ │ ├── PrivateMessageUser.cs
│ │ ├── PrivateMessageView.cs
│ │ ├── Profile.cs
│ │ ├── QAPostItemContainer.cs
│ │ ├── QueuedEmailMessage.cs
│ │ ├── ReadStatus.cs
│ │ ├── ResponseOfT.cs
│ │ ├── SearchIndexPayload.cs
│ │ ├── SearchType.cs
│ │ ├── SearchWord.cs
│ │ ├── SecurityLogEntry.cs
│ │ ├── SecurityLogType.cs
│ │ ├── ServiceHeartbeat.cs
│ │ ├── SetupVariables.cs
│ │ ├── SignupData.cs
│ │ ├── SingleString.cs
│ │ ├── SubscribeNotificationPayload.cs
│ │ ├── TimeFormats.cs
│ │ ├── Topic.cs
│ │ ├── TopicContainer.cs
│ │ ├── TopicContainerForQA.cs
│ │ ├── TopicState.cs
│ │ ├── TopicUnsubscribeContainer.cs
│ │ ├── User.cs
│ │ ├── UserEdit.cs
│ │ ├── UserEditProfile.cs
│ │ ├── UserEditSecurity.cs
│ │ ├── UserImage.cs
│ │ ├── UserImageApprovalContainer.cs
│ │ ├── UserResult.cs
│ │ ├── UserSearch.cs
│ │ └── VotePostContainer.cs
│ ├── PopForums.csproj
│ ├── Repositories/
│ │ ├── IAwardCalculationQueueRepository.cs
│ │ ├── IAwardConditionRepository.cs
│ │ ├── IAwardDefinitionRepository.cs
│ │ ├── IBanRepository.cs
│ │ ├── ICategoryRepository.cs
│ │ ├── IEmailQueueRepository.cs
│ │ ├── IErrorLogRepository.cs
│ │ ├── IEventDefinitionRepository.cs
│ │ ├── IExternalUserAssociationRepository.cs
│ │ ├── IFavoriteTopicsRepository.cs
│ │ ├── IFeedRepository.cs
│ │ ├── IForumRepository.cs
│ │ ├── IIgnoreRepository.cs
│ │ ├── ILastReadRepository.cs
│ │ ├── IModerationLogRepository.cs
│ │ ├── INotificationRepository.cs
│ │ ├── IPointLedgerRepository.cs
│ │ ├── IPostImageRepository.cs
│ │ ├── IPostImageTempRepository.cs
│ │ ├── IPostRepository.cs
│ │ ├── IPrivateMessageRepository.cs
│ │ ├── IProfileRepository.cs
│ │ ├── IQueuedEmailMessageRepository.cs
│ │ ├── IRoleRepository.cs
│ │ ├── ISearchIndexQueueRepository.cs
│ │ ├── ISearchRepository.cs
│ │ ├── ISecurityLogRepository.cs
│ │ ├── IServiceHeartbeatRepository.cs
│ │ ├── ISettingsRepository.cs
│ │ ├── ISetupRepository.cs
│ │ ├── ISubscribeNotificationRepository.cs
│ │ ├── ISubscribedTopicsRepository.cs
│ │ ├── ITopicRepository.cs
│ │ ├── ITopicViewLogRepository.cs
│ │ ├── IUserAvatarRepository.cs
│ │ ├── IUserAwardRepository.cs
│ │ ├── IUserImageRepository.cs
│ │ ├── IUserRepository.cs
│ │ └── IUserSessionRepository.cs
│ ├── Resources/
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.de.resx
│ │ ├── Resources.es.resx
│ │ ├── Resources.fr.resx
│ │ ├── Resources.nl.resx
│ │ ├── Resources.resx
│ │ ├── Resources.uk.resx
│ │ └── Resources.zh-TW.resx
│ ├── ScoringGame/
│ │ ├── AwardCalculator.cs
│ │ ├── AwardCalculatorWorker.cs
│ │ ├── AwardCondition.cs
│ │ ├── AwardDefinition.cs
│ │ ├── AwardDefinitionService.cs
│ │ ├── EventDefinition.cs
│ │ ├── EventDefinitionService.cs
│ │ ├── EventPublisher.cs
│ │ ├── PointLedgerEntry.cs
│ │ ├── UserAward.cs
│ │ └── UserAwardService.cs
│ └── Services/
│ ├── BanService.cs
│ ├── CategoryService.cs
│ ├── ClaimsToRoleMapper.cs
│ ├── CloseAgedTopicsWorker.cs
│ ├── FavoriteTopicService.cs
│ ├── ForumPermissionService.cs
│ ├── ForumService.cs
│ ├── IPHistoryService.cs
│ ├── ITopicViewCountService.cs
│ ├── IUserRetrievalShim.cs
│ ├── IgnoreService.cs
│ ├── ImageService.cs
│ ├── LastReadService.cs
│ ├── MailingListService.cs
│ ├── ModerationLogService.cs
│ ├── PostImageCleanupWorker.cs
│ ├── PostImageService.cs
│ ├── PostMasterService.cs
│ ├── PostService.cs
│ ├── PrivateMessageService.cs
│ ├── ProfileService.cs
│ ├── QueuedEmailService.cs
│ ├── ReCaptchaService.cs
│ ├── SearchIndexSubsystem.cs
│ ├── SearchIndexWorker.cs
│ ├── SearchService.cs
│ ├── SecurityLogService.cs
│ ├── ServiceHeartbeatService.cs
│ ├── SetupService.cs
│ ├── SitemapService.cs
│ ├── SubscribeNotificationWorker.cs
│ ├── SubscribedTopicsService.cs
│ ├── TenantService.cs
│ ├── TextParsingService.cs
│ ├── TimeFormatStringService.cs
│ ├── TopicService.cs
│ ├── TopicViewLogService.cs
│ ├── UserEmailReconciler.cs
│ ├── UserNameReconciler.cs
│ ├── UserService.cs
│ ├── UserSessionService.cs
│ └── UserSessionWorker.cs
├── PopForums.AzureKit/
│ ├── Logging/
│ │ └── ErrorLogRepository.cs
│ ├── PopForums.AzureKit.csproj
│ ├── PostImage/
│ │ └── PostImageRepository.cs
│ ├── Queue/
│ │ ├── AwardCalculationQueueRepository.cs
│ │ ├── EmailQueueRepository.cs
│ │ ├── SearchIndexQueueRepository.cs
│ │ └── SubscribeNotificationRepository.cs
│ ├── Redis/
│ │ ├── CacheHelper.cs
│ │ ├── CacheTelemetrySink.cs
│ │ └── ICacheTelemetry.cs
│ ├── Search/
│ │ ├── SearchIndexSubsystem.cs
│ │ ├── SearchRepository.cs
│ │ └── SearchTopic.cs
│ └── ServiceCollectionExtensions.cs
├── PopForums.AzureKit.Functions/
│ ├── .gitignore
│ ├── AwardCalculationProcessor.cs
│ ├── BrokerSink.cs
│ ├── CacheHelper.cs
│ ├── CloseAgedTopicsProcessor.cs
│ ├── EmailProcessor.cs
│ ├── NotificationTunnel.cs
│ ├── PopForums.AzureKit.Functions.csproj
│ ├── PostImageCleanupProcessor.cs
│ ├── Program.cs
│ ├── SearchIndexProcessor.cs
│ ├── SubscribeNotificationProcessor.cs
│ ├── UserSessionProcessor.cs
│ └── host.json
├── PopForums.ElasticKit/
│ ├── PopForums.ElasticKit.csproj
│ ├── Search/
│ │ ├── ElasticSearchClientWrapper.cs
│ │ ├── SearchIndexSubsystem.cs
│ │ ├── SearchRepository.cs
│ │ └── SearchTopic.cs
│ └── ServiceCollectionExtensions.cs
├── PopForums.Mvc/
│ ├── Areas/
│ │ └── Forums/
│ │ ├── Authentication/
│ │ │ ├── PopForumsAuthenticationDefaults.cs
│ │ │ ├── PopForumsAuthenticationIgnoreAttribute.cs
│ │ │ └── PopForumsAuthenticationMiddleware.cs
│ │ ├── Authorization/
│ │ │ ├── OAuthOnlyForbidAttribute.cs
│ │ │ ├── PopForumsPrivateForumsFilter.cs
│ │ │ └── PopForumsUserAttribute.cs
│ │ ├── BackgroundJobs/
│ │ │ ├── AwardCalculatorJob.cs
│ │ │ ├── CloseAgedTopicsJob.cs
│ │ │ ├── EmailJob.cs
│ │ │ ├── PostImageCleanupJob.cs
│ │ │ ├── SearchIndexJob.cs
│ │ │ ├── SubscribeNotificationJob.cs
│ │ │ └── UserSessionJob.cs
│ │ ├── Controllers/
│ │ │ ├── AccountController.cs
│ │ │ ├── AdminApiController.cs
│ │ │ ├── AdminController.cs
│ │ │ ├── ApiController.cs
│ │ │ ├── FavoritesController.cs
│ │ │ ├── ForumController.cs
│ │ │ ├── HomeController.cs
│ │ │ ├── IdentityController.cs
│ │ │ ├── IgnoreController.cs
│ │ │ ├── ImageController.cs
│ │ │ ├── ModeratorController.cs
│ │ │ ├── PrivateMessagesController.cs
│ │ │ ├── ResourcesController.cs
│ │ │ ├── SearchController.cs
│ │ │ ├── SetupController.cs
│ │ │ ├── SitemapController.cs
│ │ │ └── SubscriptionController.cs
│ │ ├── Extensions/
│ │ │ ├── ApplicationBuilders.cs
│ │ │ ├── AuthorizationOptionsExtensions.cs
│ │ │ ├── Logger.cs
│ │ │ ├── LoggerFactories.cs
│ │ │ ├── LoggerProvider.cs
│ │ │ ├── ServiceCollections.cs
│ │ │ └── WebApplications.cs
│ │ ├── ForumRouteConstraint.cs
│ │ ├── Messaging/
│ │ │ ├── Broker.cs
│ │ │ ├── PopForumsHub.cs
│ │ │ └── PopForumsUserIdProvider.cs
│ │ ├── Models/
│ │ │ ├── AwardConditionDeleteContainer.cs
│ │ │ ├── EmailUsersContainer.cs
│ │ │ ├── ExternalLoginState.cs
│ │ │ ├── ExternalLoginTypeMetadata.cs
│ │ │ ├── IPHistoryQuery.cs
│ │ │ ├── ManualEvent.cs
│ │ │ ├── SecurityLogQuery.cs
│ │ │ ├── UserEditPhoto.cs
│ │ │ ├── UserEditWithFiles.cs
│ │ │ └── UserState.cs
│ │ ├── Services/
│ │ │ ├── ExternalLoginRoutingService.cs
│ │ │ ├── ExternalLoginTempService.cs
│ │ │ ├── ForumAdapterFactory.cs
│ │ │ ├── IForumAdapter.cs
│ │ │ ├── OAuthOnlyService.cs
│ │ │ ├── TopicViewCountService.cs
│ │ │ ├── UserRetrievalShim.cs
│ │ │ └── UserStateComposer.cs
│ │ ├── TagHelpers/
│ │ │ ├── ForumReadIndicatorTagHelper.cs
│ │ │ ├── PMReadIndicatorTagHelper.cs
│ │ │ ├── PagerLinksTagHelper.cs
│ │ │ ├── TopicReadIndicatorTagHelper.cs
│ │ │ └── ValidationClassTagHelper.cs
│ │ ├── ViewComponents/
│ │ │ ├── UserNavigationViewComponent.cs
│ │ │ └── UserStateViewComponent.cs
│ │ └── Views/
│ │ ├── Account/
│ │ │ ├── AccountCreated.cshtml
│ │ │ ├── Create.cshtml
│ │ │ ├── EditAccountNoUser.cshtml
│ │ │ ├── EditProfile.cshtml
│ │ │ ├── ExternalLogins.cshtml
│ │ │ ├── Forgot.cshtml
│ │ │ ├── Login.cshtml
│ │ │ ├── ManagePhotos.cshtml
│ │ │ ├── MiniProfile.cshtml
│ │ │ ├── MiniUserNotFound.cshtml
│ │ │ ├── OAuthLogin.cshtml
│ │ │ ├── Posts.cshtml
│ │ │ ├── ResetPassword.cshtml
│ │ │ ├── ResetPasswordSuccess.cshtml
│ │ │ ├── Security.cshtml
│ │ │ ├── Unsubscribe.cshtml
│ │ │ ├── UnsubscribeFailure.cshtml
│ │ │ ├── Verify.cshtml
│ │ │ ├── VerifyFail.cshtml
│ │ │ └── ViewProfile.cshtml
│ │ ├── Admin/
│ │ │ └── App.cshtml
│ │ ├── Favorites/
│ │ │ └── Topics.cshtml
│ │ ├── Forum/
│ │ │ ├── Edit.cshtml
│ │ │ ├── Index.cshtml
│ │ │ ├── IndexQA.cshtml
│ │ │ ├── ModeratorPanel.cshtml
│ │ │ ├── NewComment.cshtml
│ │ │ ├── NewReply.cshtml
│ │ │ ├── NewTopic.cshtml
│ │ │ ├── PostItem.cshtml
│ │ │ ├── QAPost.cshtml
│ │ │ ├── Recent.cshtml
│ │ │ ├── Topic.cshtml
│ │ │ ├── TopicPage.cshtml
│ │ │ ├── TopicQA.cshtml
│ │ │ └── Voters.cshtml
│ │ ├── Home/
│ │ │ └── Index.cshtml
│ │ ├── Identity/
│ │ │ ├── ExternalError.cshtml
│ │ │ └── ExternalLoginCallback.cshtml
│ │ ├── Ignore/
│ │ │ └── List.cshtml
│ │ ├── Moderator/
│ │ │ ├── PostModerationLog.cshtml
│ │ │ └── TopicModerationLog.cshtml
│ │ ├── PrivateMessages/
│ │ │ ├── Archive.cshtml
│ │ │ ├── Create.cshtml
│ │ │ ├── Index.cshtml
│ │ │ └── View.cshtml
│ │ ├── Search/
│ │ │ └── Index.cshtml
│ │ ├── Setup/
│ │ │ ├── Exception.cshtml
│ │ │ ├── Index.cshtml
│ │ │ ├── NoConnection.cshtml
│ │ │ └── Success.cshtml
│ │ ├── Shared/
│ │ │ ├── Components/
│ │ │ │ ├── UserNavigation/
│ │ │ │ │ └── Default.cshtml
│ │ │ │ └── UserState/
│ │ │ │ └── Default.cshtml
│ │ │ ├── Forbidden.cshtml
│ │ │ ├── NotFound.cshtml
│ │ │ └── PopForumsMaster.cshtml
│ │ ├── Subscription/
│ │ │ └── Topics.cshtml
│ │ └── _ViewImports.cshtml
│ ├── Client/
│ │ ├── Components/
│ │ │ ├── AnswerButton.ts
│ │ │ ├── CommentButton.ts
│ │ │ ├── FavoriteButton.ts
│ │ │ ├── FormattedTime.ts
│ │ │ ├── FullText.ts
│ │ │ ├── HomeUpdater.ts
│ │ │ ├── LoginForm.ts
│ │ │ ├── MorePostsBeforeReplyButton.ts
│ │ │ ├── MorePostsButton.ts
│ │ │ ├── NotificationItem.ts
│ │ │ ├── NotificationList.ts
│ │ │ ├── NotificationMarkAllButton.ts
│ │ │ ├── NotificationToggle.ts
│ │ │ ├── PMCount.ts
│ │ │ ├── PMForm.ts
│ │ │ ├── PostMiniProfile.ts
│ │ │ ├── PostModerationLogButton.ts
│ │ │ ├── PreviewButton.ts
│ │ │ ├── PreviousPostsButton.ts
│ │ │ ├── QuoteButton.ts
│ │ │ ├── ReplyButton.ts
│ │ │ ├── ReplyForm.ts
│ │ │ ├── SearchNavForm.ts
│ │ │ ├── SubscribeButton.ts
│ │ │ ├── TopicButton.ts
│ │ │ ├── TopicForm.ts
│ │ │ ├── TopicModerationLogButton.ts
│ │ │ └── VoteCount.ts
│ │ ├── Declarations.ts
│ │ ├── ElementBase.ts
│ │ ├── Models/
│ │ │ ├── Notification.ts
│ │ │ ├── PrivateMessage.ts
│ │ │ └── PrivateMessageUser.ts
│ │ ├── Services/
│ │ │ ├── LocalizationService.ts
│ │ │ ├── MessagingService.ts
│ │ │ └── NotificationService.ts
│ │ ├── State/
│ │ │ ├── ForumState.ts
│ │ │ ├── Localizations.ts
│ │ │ ├── PrivateMessageState.ts
│ │ │ ├── TopicState.ts
│ │ │ └── UserState.ts
│ │ ├── StateBase.ts
│ │ ├── WatchPropertyAttribute.ts
│ │ └── tsconfig.json
│ ├── Global.cs
│ ├── PopForums.Mvc.csproj
│ ├── gulpfile.js
│ ├── package.json
│ └── wwwroot/
│ ├── Admin.js
│ ├── Editor.css
│ └── PopForums.css
├── PopForums.Sql/
│ ├── CacheHelper.cs
│ ├── Extensions.cs
│ ├── Global.cs
│ ├── ISqlObjectFactory.cs
│ ├── JsonElementTypeHandler.cs
│ ├── PopForums.Sql.csproj
│ ├── PopForums.sql
│ ├── PopForums13to14.sql
│ ├── PopForums14to15.sql
│ ├── PopForums15to16.sql
│ ├── PopForums16to21.sql
│ ├── PopForums19to20.sql
│ ├── PopForums20to21.sql
│ ├── PopForums21to22.sql
│ ├── Repositories/
│ │ ├── AwardCalculationQueueRepository.cs
│ │ ├── AwardConditionRepository.cs
│ │ ├── AwardDefinitionRepository.cs
│ │ ├── BanRepository.cs
│ │ ├── CategoryRepository.cs
│ │ ├── EmailQueueRepository.cs
│ │ ├── ErrorLogRepository.cs
│ │ ├── EventDefinitionRepository.cs
│ │ ├── ExternalUserAssociationRepository.cs
│ │ ├── FavoriteTopicsRepository.cs
│ │ ├── FeedRepository.cs
│ │ ├── ForumRepository.cs
│ │ ├── IgnoreRepository.cs
│ │ ├── LastReadRepository.cs
│ │ ├── ModerationLogRepository.cs
│ │ ├── NotificationRepository.cs
│ │ ├── PointLedgerRepository.cs
│ │ ├── PostImageRepository.cs
│ │ ├── PostImageTempRepository.cs
│ │ ├── PostRepository.cs
│ │ ├── PrivateMessageRepository.cs
│ │ ├── ProfileRepository.cs
│ │ ├── QueuedEmailMessageRepository.cs
│ │ ├── RoleRepository.cs
│ │ ├── SearchIndexQueueRepository.cs
│ │ ├── SearchRepository.cs
│ │ ├── SecurityLogRepository.cs
│ │ ├── ServiceHeartbeatRepository.cs
│ │ ├── SettingsRepository.cs
│ │ ├── SetupRepository.cs
│ │ ├── SubscribeNotificationRepository.cs
│ │ ├── SubscribedTopicsRepository.cs
│ │ ├── TopicRepository.cs
│ │ ├── TopicViewLogRepository.cs
│ │ ├── UserAvatarRepository.cs
│ │ ├── UserAwardRepository.cs
│ │ ├── UserImageRepository.cs
│ │ ├── UserRepository.cs
│ │ └── UserSessionRepository.cs
│ ├── SqlObjectFactory.cs
│ └── StreamResponse.cs
├── PopForums.Test/
│ ├── Composers/
│ │ ├── ForumStateComposerTests.cs
│ │ ├── PrivateMessageStateComposerTests.cs
│ │ └── TopicStateComposerTests.cs
│ ├── Configuration/
│ │ └── SettingsTests.cs
│ ├── Email/
│ │ ├── EmailWorkerTests.cs
│ │ └── NewAccountMailerTests.cs
│ ├── Extensions/
│ │ └── StringTests.cs
│ ├── ExternalLogin/
│ │ └── ExternalUserAssociationManagerTests.cs
│ ├── Global.cs
│ ├── Messaging/
│ │ ├── NotificationAdapterTests.cs
│ │ └── NotificationManagerTests.cs
│ ├── Models/
│ │ ├── ForumHomeContainerTests.cs
│ │ ├── UserEditSecurityTests.cs
│ │ └── UserTest.cs
│ ├── Mvc/
│ │ ├── Authorization/
│ │ │ └── PopForumsPrivateForumsFilterTests.cs
│ │ ├── Controllers/
│ │ │ ├── AccountControllerTests.cs
│ │ │ └── AdminApiControllerTests.cs
│ │ └── Services/
│ │ └── OAuthOnlyServiceTests.cs
│ ├── PopForums.Test.csproj
│ ├── ScoringGame/
│ │ ├── AwardCalculatorTests.cs
│ │ ├── AwardCalculatorWorkerTests.cs
│ │ ├── AwardDefinitionServiceTests.cs
│ │ ├── EventDefintionServiceTests.cs
│ │ ├── EventPublisherTests.cs
│ │ ├── FeedServiceTests.cs
│ │ └── UserAwardServiceTests.cs
│ └── Services/
│ ├── BanServiceTests.cs
│ ├── CategoryServiceTests.cs
│ ├── ClaimsToRoleMapperTests.cs
│ ├── CloseAgedTopicsWorkerTests.cs
│ ├── FavoriteTopicServiceTests.cs
│ ├── ForumPermissionServiceTests.cs
│ ├── ForumServiceTests.cs
│ ├── ImageServiceTests.cs
│ ├── LastReadServiceTests.cs
│ ├── PostImageCleanupWorkerTests.cs
│ ├── PostImageServiceTests.cs
│ ├── PostMasterServiceTests.cs
│ ├── PostServiceTests.cs
│ ├── PrivateMessageServiceTests.cs
│ ├── ProfileServiceTests.cs
│ ├── QueuedEmailServiceTests.cs
│ ├── SearchIndexWorkerTests.cs
│ ├── SearchServiceTests.cs
│ ├── SecurityLogServiceTests.cs
│ ├── SetupServiceTests.cs
│ ├── SitemapServiceTests.cs
│ ├── SubscribeNotificationWorkerTests.cs
│ ├── SubscribedTopicsServiceTests.cs
│ ├── TextParsingServiceCleanForumCodeTests.cs
│ ├── TextParsingServiceClientHtmlToForumCodeTests.cs
│ ├── TextParsingServiceForumCodeToHtmlTests.cs
│ ├── TextParsingServiceOtherTests.cs
│ ├── TopicServiceTests.cs
│ ├── TopicViewLogServiceTests.cs
│ ├── UserEmailReconcilerTests.cs
│ ├── UserNameReconcilerTests.cs
│ ├── UserServiceTests.cs
│ ├── UserSessionServiceTests.cs
│ └── UserSessionWorkerTests.cs
└── PopForums.Web/
├── Controllers/
│ └── HomeController.cs
├── PopForums.Web.csproj
├── Program.cs
├── Properties/
│ └── launchSettings.json
├── Views/
│ ├── Home/
│ │ └── Index.cshtml
│ ├── Shared/
│ │ └── _Layout.cshtml
│ ├── _ViewImports.cshtml
│ └── _ViewStart.cshtml
└── appsettings.json
Showing preview only (305K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3436 symbols across 456 files)
FILE: src/PopForums.AzureKit.Functions/AwardCalculationProcessor.cs
class AwardCalculationProcessor (line 15) | public class AwardCalculationProcessor
method AwardCalculationProcessor (line 21) | public AwardCalculationProcessor(IAwardCalculator awardCalculator, ISe...
method Run (line 28) | [Function("AwardCalculationProcessor")]
FILE: src/PopForums.AzureKit.Functions/BrokerSink.cs
class BrokerSink (line 6) | public class BrokerSink : IBroker
method NotifyNewPosts (line 8) | public void NotifyNewPosts(Topic topic, int lasPostID)
method NotifyForumUpdate (line 13) | public void NotifyForumUpdate(Forum forum)
method NotifyTopicUpdate (line 18) | public void NotifyTopicUpdate(Topic topic, Forum forum, string topicLink)
method NotifyNewPost (line 23) | public void NotifyNewPost(Topic topic, int postID)
method NotifyPMCount (line 28) | public void NotifyPMCount(int userID, int pmCount)
method NotifyUser (line 33) | public void NotifyUser(Notification notification)
method NotifyUser (line 38) | public void NotifyUser(Notification notification, string tenantID)
method SendPMMessage (line 43) | public void SendPMMessage(PrivateMessagePost post)
FILE: src/PopForums.AzureKit.Functions/CacheHelper.cs
class CacheHelper (line 7) | public class CacheHelper : ICacheHelper
method SetCacheObject (line 9) | public void SetCacheObject(string key, object value)
method SetCacheObject (line 13) | public void SetCacheObject(string key, object value, double seconds)
method SetLongTermCacheObject (line 17) | public void SetLongTermCacheObject(string key, object value)
method SetPagedListCacheObject (line 21) | public void SetPagedListCacheObject<T>(string rootKey, int page, List<...
method RemoveCacheObject (line 25) | public void RemoveCacheObject(string key)
method GetCacheObject (line 29) | public T GetCacheObject<T>(string key)
method GetPagedListCacheObject (line 34) | public List<T> GetPagedListCacheObject<T>(string rootKey, int page)
method GetEffectiveCacheKey (line 43) | public string GetEffectiveCacheKey(string key)
FILE: src/PopForums.AzureKit.Functions/CloseAgedTopicsProcessor.cs
class CloseAgedTopicsProcessor (line 11) | public class CloseAgedTopicsProcessor
method CloseAgedTopicsProcessor (line 17) | public CloseAgedTopicsProcessor(ITopicService topicService, IServiceHe...
method Run (line 24) | [Function("CloseAgedTopicsProcessor")]
FILE: src/PopForums.AzureKit.Functions/EmailProcessor.cs
class EmailProcessor (line 15) | public class EmailProcessor
method EmailProcessor (line 22) | public EmailProcessor(IQueuedEmailMessageRepository queuedEmailRepo, I...
method RunAsync (line 30) | [Function("EmailProcessor")]
FILE: src/PopForums.AzureKit.Functions/NotificationTunnel.cs
class NotificationTunnel (line 11) | public class NotificationTunnel : INotificationTunnel
method NotificationTunnel (line 15) | public NotificationTunnel(IConfig config)
method SendNotificationForUserAward (line 20) | public void SendNotificationForUserAward(string title, int userID, str...
method SendNotificationForReply (line 32) | public void SendNotificationForReply(string postName, string title, in...
method SendMessage (line 46) | private void SendMessage(string url, object payload)
FILE: src/PopForums.AzureKit.Functions/PostImageCleanupProcessor.cs
class PostImageCleanupProcessor (line 11) | public class PostImageCleanupProcessor
method PostImageCleanupProcessor (line 17) | public PostImageCleanupProcessor(IPostImageService postImageService, I...
method Run (line 24) | [Function("PostImageCleanupProcessor")]
FILE: src/PopForums.AzureKit.Functions/SearchIndexProcessor.cs
class SearchIndexProcessor (line 14) | public class SearchIndexProcessor
method SearchIndexProcessor (line 20) | public SearchIndexProcessor(ISearchIndexSubsystem searchIndexSubsystem...
method RunAsync (line 27) | [Function("SearchIndexProcessor")]
FILE: src/PopForums.AzureKit.Functions/SubscribeNotificationProcessor.cs
class SubscribeNotificationProcessor (line 16) | public class SubscribeNotificationProcessor
method SubscribeNotificationProcessor (line 23) | public SubscribeNotificationProcessor(ISubscribedTopicsService subscri...
method Run (line 31) | [Function("SubscribeNotificationProcessor")]
FILE: src/PopForums.AzureKit.Functions/UserSessionProcessor.cs
class UserSessionProcessor (line 11) | public class UserSessionProcessor
method UserSessionProcessor (line 17) | public UserSessionProcessor(IUserSessionService userSessionService, IS...
method RunAsync (line 24) | [Function("UserSessionProcessor")]
FILE: src/PopForums.AzureKit/Logging/ErrorLogRepository.cs
class ErrorLogRepository (line 12) | public class ErrorLogRepository : IErrorLogRepository
method ErrorLogRepository (line 19) | public ErrorLogRepository(ITenantService tenantService, IConfig config)
method Create (line 25) | public async Task<ErrorLogEntry> Create(DateTime timeStamp, string mes...
method GetTableClient (line 51) | private async Task<TableClient> GetTableClient()
method GetErrorCount (line 61) | public Task<int> GetErrorCount()
method GetErrors (line 66) | public Task<List<ErrorLogEntry>> GetErrors(int startRow, int pageSize)
method DeleteError (line 73) | public Task DeleteError(int errorID)
method DeleteAllErrors (line 78) | public async Task DeleteAllErrors()
FILE: src/PopForums.AzureKit/PostImage/PostImageRepository.cs
class PostImageRepository (line 12) | public class PostImageRepository : IPostImageRepository
method PostImageRepository (line 19) | public PostImageRepository(IConfig config, ITenantService tenantService)
method Persist (line 25) | public async Task<PostImagePersistPayload> Persist(byte[] bytes, strin...
method DeletePostImageData (line 43) | public async Task DeletePostImageData(string id, string tenantID)
method GetWithoutData (line 57) | public Task<Models.PostImage> GetWithoutData(string id)
method Get (line 62) | public Task<Models.PostImage> Get(string id)
method GetImageStream (line 67) | public Task<IStreamResponse> GetImageStream(string id)
FILE: src/PopForums.AzureKit/Queue/AwardCalculationQueueRepository.cs
class AwardCalculationQueueRepository (line 13) | public class AwardCalculationQueueRepository : IAwardCalculationQueueRep...
method AwardCalculationQueueRepository (line 19) | public AwardCalculationQueueRepository(IConfig config, IErrorLog error...
method Enqueue (line 25) | public async Task Enqueue(AwardCalculationPayload payload)
method Dequeue (line 40) | public async Task<KeyValuePair<string, int>> Dequeue()
method GetQueueClient (line 46) | private async Task<QueueClient> GetQueueClient()
FILE: src/PopForums.AzureKit/Queue/EmailQueueRepository.cs
class EmailQueueRepository (line 10) | public class EmailQueueRepository : IEmailQueueRepository
method EmailQueueRepository (line 15) | public EmailQueueRepository(IConfig config)
method Enqueue (line 20) | public async Task Enqueue(EmailQueuePayload payload)
method Dequeue (line 27) | public Task<EmailQueuePayload> Dequeue()
method GetQueueClient (line 32) | private async Task<QueueClient> GetQueueClient()
FILE: src/PopForums.AzureKit/Queue/SearchIndexQueueRepository.cs
class SearchIndexQueueRepository (line 12) | public class SearchIndexQueueRepository : ISearchIndexQueueRepository
method SearchIndexQueueRepository (line 18) | public SearchIndexQueueRepository(IConfig config, IErrorLog errorLog)
method Enqueue (line 24) | public async Task Enqueue(SearchIndexPayload payload)
method Dequeue (line 39) | public async Task<SearchIndexPayload> Dequeue()
method GetQueueClient (line 45) | private async Task<QueueClient> GetQueueClient()
FILE: src/PopForums.AzureKit/Queue/SubscribeNotificationRepository.cs
class SubscribeNotificationRepository (line 12) | public class SubscribeNotificationRepository : ISubscribeNotificationRep...
method SubscribeNotificationRepository (line 18) | public SubscribeNotificationRepository(IConfig config, IErrorLog error...
method Enqueue (line 24) | public async Task Enqueue(SubscribeNotificationPayload payload)
method Dequeue (line 39) | public Task<SubscribeNotificationPayload> Dequeue()
method GetQueueClient (line 45) | private async Task<QueueClient> GetQueueClient()
FILE: src/PopForums.AzureKit/Redis/CacheHelper.cs
class CacheHelper (line 11) | public class CacheHelper : ICacheHelper
class CacheTelemetryNames (line 23) | private static class CacheTelemetryNames
method CacheHelper (line 35) | public CacheHelper(IErrorLog errorLog, ITenantService tenantService, I...
method GetEffectiveCacheKey (line 74) | public string GetEffectiveCacheKey(string key)
method SetupLocalCache (line 80) | private static void SetupLocalCache()
method SetCacheObject (line 89) | public void SetCacheObject(string key, object value)
method SetCacheObject (line 94) | public void SetCacheObject(string key, object value, double seconds)
method SetLongTermCacheObject (line 117) | public void SetLongTermCacheObject(string key, object value)
method SetPagedListCacheObject (line 139) | public void SetPagedListCacheObject<T>(string rootKey, int page, List<...
method RemoveCacheObject (line 155) | public void RemoveCacheObject(string key)
method GetCacheObject (line 172) | public T GetCacheObject<T>(string key)
method GetPagedListCacheObject (line 210) | public List<T> GetPagedListCacheObject<T>(string rootKey, int page)
FILE: src/PopForums.AzureKit/Redis/CacheTelemetrySink.cs
class CacheTelemetrySink (line 3) | public class CacheTelemetrySink : ICacheTelemetry
method Start (line 5) | public void Start()
method End (line 9) | public void End(string eventName, string key)
FILE: src/PopForums.AzureKit/Redis/ICacheTelemetry.cs
type ICacheTelemetry (line 3) | public interface ICacheTelemetry
method Start (line 5) | void Start();
method End (line 6) | void End(string eventName, string key);
FILE: src/PopForums.AzureKit/Search/SearchIndexSubsystem.cs
class SearchIndexSubsystem (line 14) | public class SearchIndexSubsystem : ISearchIndexSubsystem
method SearchIndexSubsystem (line 23) | public SearchIndexSubsystem(ITextParsingService textParsingService, IP...
method DoIndex (line 32) | public void DoIndex(int topicID, string tenantID, bool isForRemoval)
method RemoveIndex (line 84) | public void RemoveIndex(int topicID, string tenantID)
method CreateIndex (line 98) | private void CreateIndex()
FILE: src/PopForums.AzureKit/Search/SearchRepository.cs
class SearchRepository (line 16) | public class SearchRepository : Sql.Repositories.SearchRepository
method SearchRepository (line 22) | public SearchRepository(ISqlObjectFactory sqlObjectFactory, IConfig co...
method GetJunkWords (line 29) | public override async Task<List<string>> GetJunkWords()
method CreateJunkWord (line 34) | public override async Task CreateJunkWord(string word)
method DeleteJunkWord (line 39) | public override async Task DeleteJunkWord(string word)
method DeleteAllIndexedWordsForTopic (line 44) | public override async Task DeleteAllIndexedWordsForTopic(int topicID)
method SaveSearchWord (line 49) | public override async Task SaveSearchWord(int topicID, string word, in...
method SearchTopics (line 54) | public override async Task<Tuple<PopForums.Models.Response<List<Topic>...
FILE: src/PopForums.AzureKit/Search/SearchTopic.cs
class SearchTopic (line 5) | public class SearchTopic
FILE: src/PopForums.AzureKit/ServiceCollectionExtensions.cs
class ServiceCollectionExtensions (line 13) | public static class ServiceCollectionExtensions
method AddPopForumsRedisCache (line 15) | public static IServiceCollection AddPopForumsRedisCache(this IServiceC...
method AddRedisBackplaneForPopForums (line 26) | public static ISignalRServerBuilder AddRedisBackplaneForPopForums(this...
method AddPopForumsAzureSearch (line 34) | public static IServiceCollection AddPopForumsAzureSearch(this IService...
method AddPopForumsAzureFunctionsAndQueues (line 41) | public static IServiceCollection AddPopForumsAzureFunctionsAndQueues(t...
method AddPopForumsAzureBlobStorageForPostImages (line 50) | public static IServiceCollection AddPopForumsAzureBlobStorageForPostIm...
method AddPopForumsTableStorageLogging (line 56) | public static IServiceCollection AddPopForumsTableStorageLogging(this ...
FILE: src/PopForums.ElasticKit/Search/ElasticSearchClientWrapper.cs
type IElasticSearchClientWrapper (line 14) | public interface IElasticSearchClientWrapper
method IndexTopic (line 16) | IndexResponse IndexTopic(SearchTopic searchTopic);
method SearchTopicsWithIDs (line 17) | Response<IEnumerable<int>> SearchTopicsWithIDs(string searchTerm, List...
method VerifyIndexCreate (line 18) | void VerifyIndexCreate();
method RemoveTopic (line 19) | DeleteResponse RemoveTopic(string id);
class ElasticSearchClientWrapper (line 22) | public class ElasticSearchClientWrapper : IElasticSearchClientWrapper
method ElasticSearchClientWrapper (line 30) | public ElasticSearchClientWrapper(IConfig config, IErrorLog errorLog, ...
method IndexTopic (line 51) | public IndexResponse IndexTopic(SearchTopic searchTopic)
method RemoveTopic (line 61) | public DeleteResponse RemoveTopic(string id)
method SearchTopicsWithIDs (line 68) | public Response<IEnumerable<int>> SearchTopicsWithIDs(string searchTer...
method VerifyIndexCreate (line 133) | public void VerifyIndexCreate()
FILE: src/PopForums.ElasticKit/Search/SearchIndexSubsystem.cs
class SearchIndexSubsystem (line 12) | public class SearchIndexSubsystem : ISearchIndexSubsystem
method SearchIndexSubsystem (line 20) | public SearchIndexSubsystem(ITextParsingService textParsingService, IP...
method DoIndex (line 29) | public void DoIndex(int topicID, string tenantID, bool isForRemoval)
method RemoveIndex (line 111) | public void RemoveIndex(int topicID, string tenantID)
FILE: src/PopForums.ElasticKit/Search/SearchRepository.cs
class SearchRepository (line 11) | public class SearchRepository : Sql.Repositories.SearchRepository
method SearchRepository (line 16) | public SearchRepository(ISqlObjectFactory sqlObjectFactory, ITopicRepo...
method GetJunkWords (line 22) | public override async Task<List<string>> GetJunkWords()
method CreateJunkWord (line 27) | public override async Task CreateJunkWord(string word)
method DeleteJunkWord (line 32) | public override async Task DeleteJunkWord(string word)
method DeleteAllIndexedWordsForTopic (line 37) | public override async Task DeleteAllIndexedWordsForTopic(int topicID)
method SaveSearchWord (line 42) | public override async Task SaveSearchWord(int topicID, string word, in...
method SearchTopics (line 47) | public override async Task<Tuple<Response<List<Topic>>, int>> SearchTo...
FILE: src/PopForums.ElasticKit/Search/SearchTopic.cs
class SearchTopic (line 5) | public class SearchTopic
FILE: src/PopForums.ElasticKit/ServiceCollectionExtensions.cs
class ServiceCollectionExtensions (line 10) | public static class ServiceCollectionExtensions
method AddPopForumsElasticSearch (line 12) | public static IServiceCollection AddPopForumsElasticSearch(this IServi...
FILE: src/PopForums.Mvc/Areas/Forums/Authentication/PopForumsAuthenticationDefaults.cs
class PopForumsAuthenticationDefaults (line 3) | public static class PopForumsAuthenticationDefaults
FILE: src/PopForums.Mvc/Areas/Forums/Authentication/PopForumsAuthenticationIgnoreAttribute.cs
class PopForumsAuthenticationIgnoreAttribute (line 3) | public class PopForumsAuthenticationIgnoreAttribute : Attribute
FILE: src/PopForums.Mvc/Areas/Forums/Authentication/PopForumsAuthenticationMiddleware.cs
class PopForumsAuthenticationMiddleware (line 3) | public class PopForumsAuthenticationMiddleware(RequestDelegate next)
method InvokeAsync (line 5) | public async Task InvokeAsync(HttpContext context, IUserService userSe...
FILE: src/PopForums.Mvc/Areas/Forums/Authorization/OAuthOnlyForbidAttribute.cs
class OAuthOnlyForbidAttribute (line 3) | public class OAuthOnlyForbidAttribute(IConfig config) : Attribute, IReso...
method OnResourceExecuting (line 5) | public void OnResourceExecuting(ResourceExecutingContext context)
method OnResourceExecuted (line 11) | public void OnResourceExecuted(ResourceExecutedContext context)
FILE: src/PopForums.Mvc/Areas/Forums/Authorization/PopForumsPrivateForumsFilter.cs
class PopForumsPrivateForumsFilter (line 3) | public class PopForumsPrivateForumsFilter(IUserRetrievalShim userRetriev...
method OnActionExecuting (line 5) | public void OnActionExecuting(ActionExecutingContext context)
method OnActionExecuted (line 13) | public void OnActionExecuted(ActionExecutedContext context)
FILE: src/PopForums.Mvc/Areas/Forums/Authorization/PopForumsUserAttribute.cs
class PopForumsUserAttribute (line 10) | public class PopForumsUserAttribute(IUserSessionService userSessionServi...
method IsGlobalFilter (line 14) | protected virtual bool IsGlobalFilter()
method OnAuthorization (line 19) | public void OnAuthorization(AuthorizationFilterContext context)
method OnActionExecutionAsync (line 38) | public async Task OnActionExecutionAsync(ActionExecutingContext filter...
method IsValidToRunOnController (line 67) | private bool IsValidToRunOnController(TypeInfo controllerType)
FILE: src/PopForums.Mvc/Areas/Forums/BackgroundJobs/AwardCalculatorJob.cs
class AwardCalculatorJob (line 6) | public class AwardCalculatorJob(ISettingsManager settingsManager, IServi...
method ExecuteAsync (line 8) | protected override async Task ExecuteAsync(CancellationToken stoppingT...
method GetLogger (line 39) | private async Task<ILogger<AwardCalculatorJob>> GetLogger()
FILE: src/PopForums.Mvc/Areas/Forums/BackgroundJobs/CloseAgedTopicsJob.cs
class CloseAgedTopicsJob (line 6) | public class CloseAgedTopicsJob(IServiceHeartbeatService serviceHeartbea...
method ExecuteAsync (line 11) | protected override async Task ExecuteAsync(CancellationToken stoppingT...
method GetLogger (line 29) | private async Task<ILogger<CloseAgedTopicsJob>> GetLogger()
FILE: src/PopForums.Mvc/Areas/Forums/BackgroundJobs/EmailJob.cs
class EmailJob (line 6) | public class EmailJob(ISettingsManager settingsManager, IServiceHeartbea...
method ExecuteAsync (line 8) | protected override async Task ExecuteAsync(CancellationToken stoppingT...
method GetLogger (line 41) | private async Task<ILogger<EmailJob>> GetLogger()
FILE: src/PopForums.Mvc/Areas/Forums/BackgroundJobs/PostImageCleanupJob.cs
class PostImageCleanupJob (line 6) | public class PostImageCleanupJob(IServiceHeartbeatService serviceHeartbe...
method ExecuteAsync (line 11) | protected override async Task ExecuteAsync(CancellationToken stoppingT...
method GetLogger (line 29) | private async Task<ILogger<PostImageCleanupJob>> GetLogger()
FILE: src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SearchIndexJob.cs
class SearchIndexJob (line 6) | public class SearchIndexJob(ISettingsManager settingsManager, IServiceHe...
method ExecuteAsync (line 8) | protected override async Task ExecuteAsync(CancellationToken stoppingT...
method GetLogger (line 38) | private async Task<ILogger<SearchIndexJob>> GetLogger()
FILE: src/PopForums.Mvc/Areas/Forums/BackgroundJobs/SubscribeNotificationJob.cs
class SubscribeNotificationJob (line 6) | public class SubscribeNotificationJob(IServiceHeartbeatService serviceHe...
method ExecuteAsync (line 11) | protected override async Task ExecuteAsync(CancellationToken stoppingT...
method GetLogger (line 29) | private async Task<ILogger<PostImageCleanupJob>> GetLogger()
FILE: src/PopForums.Mvc/Areas/Forums/BackgroundJobs/UserSessionJob.cs
class UserSessionJob (line 6) | public class UserSessionJob(IServiceHeartbeatService serviceHeartbeatSer...
method ExecuteAsync (line 11) | protected override async Task ExecuteAsync(CancellationToken stoppingT...
method GetLogger (line 29) | private async Task<ILogger<UserSessionJob>> GetLogger()
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/AccountController.cs
class AccountController (line 6) | [Area("Forums")]
method AccountController (line 9) | public AccountController(IUserService userService, IProfileService pro...
method Create (line 54) | [PopForumsAuthenticationIgnore]
method SetupCreateData (line 73) | private void SetupCreateData()
method Create (line 79) | [PopForumsAuthenticationIgnore]
method ValidateSignupData (line 122) | private async Task ValidateSignupData(SignupData signupData, ModelStat...
method Verify (line 150) | [PopForumsAuthenticationIgnore]
method VerifyCode (line 167) | [PopForumsAuthenticationIgnore]
method RequestCode (line 175) | [PopForumsAuthenticationIgnore]
method Forgot (line 194) | [PopForumsAuthenticationIgnore]
method Forgot (line 200) | [PopForumsAuthenticationIgnore]
method ResetPassword (line 219) | [PopForumsAuthenticationIgnore]
method ResetPassword (line 235) | [PopForumsAuthenticationIgnore]
method ResetPasswordSuccess (line 257) | [PopForumsAuthenticationIgnore]
method EditProfile (line 267) | public async Task<ViewResult> EditProfile()
method EditProfile (line 277) | [HttpPost]
method Security (line 290) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method ChangePassword (line 301) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method ChangeEmail (line 323) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method ManagePhotos (line 353) | public async Task<ViewResult> ManagePhotos()
method ManagePhotos (line 365) | [HttpPost]
method MiniProfile (line 381) | public async Task<ViewResult> MiniProfile(int id)
method ViewProfile (line 398) | public async Task<ActionResult> ViewProfile(int id)
method Posts (line 417) | public async Task<ActionResult> Posts(int id, int pageNumber = 1)
method Login (line 434) | [PopForumsAuthenticationIgnore]
method OAuthLogin (line 451) | [PopForumsAuthenticationIgnore]
method Unsubscribe (line 466) | [PopForumsAuthenticationIgnore]
method ExternalLogins (line 475) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method RemoveExternalLogin (line 486) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method MyProfile (line 496) | public RedirectToActionResult MyProfile()
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/AdminApiController.cs
class AdminApiController (line 5) | [Authorize(Policy = PermanentRoles.Admin, AuthenticationSchemes = PopFor...
method AdminApiController (line 30) | public AdminApiController(ISettingsManager settingsManager, ICategoryS...
method GetSettings (line 54) | [HttpGet("/Forums/AdminApi/GetSettings")]
method SaveSettings (line 61) | [HttpPost("/Forums/AdminApi/SaveSettings")]
method GetCategories (line 71) | [HttpGet("/Forums/AdminApi/GetCategories")]
method AddCategory (line 78) | [HttpPost("/Forums/AdminApi/AddCategory")]
method DeleteCategory (line 86) | [HttpPost("/Forums/AdminApi/DeleteCategory/{id}")]
method MoveCategoryUp (line 94) | [HttpPost("/Forums/AdminApi/MoveCategoryUp/{id}")]
method MoveCategoryDown (line 102) | [HttpPost("/Forums/AdminApi/MoveCategoryDown/{id}")]
method EditCategory (line 110) | [HttpPost("/Forums/AdminApi/EditCategory")]
method GetForums (line 120) | [HttpGet("/Forums/AdminApi/GetForums")]
method MoveForumUp (line 127) | [HttpPost("/Forums/AdminApi/MoveForumUp/{id}")]
method MoveForumDown (line 135) | [HttpPost("/Forums/AdminApi/MoveForumDown/{id}")]
method SaveForum (line 143) | [HttpPost("/Forums/AdminApi/SaveForum")]
method GetForumPermissions (line 163) | [HttpGet("/Forums/AdminApi/GetForumPermissions/{id}")]
method ModifyForumRoles (line 179) | [HttpPost("/Forums/AdminApi/ModifyForumRoles")]
method GetJunkWords (line 188) | [HttpGet("/Forums/AdminApi/GetJunkWords")]
method CreateJunkWord (line 195) | [HttpPost("/Forums/AdminApi/CreateJunkWord/{word}")]
method DeleteJunkWord (line 202) | [HttpPost("/Forums/AdminApi/DeleteJunkWord/{word}")]
method GetRecentUsers (line 211) | [HttpGet("/Forums/AdminApi/GetRecentUsers")]
method EditUserSearch (line 220) | [HttpPost("/Forums/AdminApi/EditUserSearch")]
method GetUser (line 241) | [HttpGet("/Forums/AdminApi/GetUser/{id}")]
method UpdateUserAvatar (line 252) | [HttpPost("/Forums/AdminApi/UpdateUserAvatar/{id}")]
method UpdateUserImage (line 269) | [HttpPost("/Forums/AdminApi/UpdateUserImage/{id}")]
method SaveUser (line 286) | [HttpPost("/Forums/AdminApi/SaveUser")]
method DeleteUser (line 296) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method DeleteAndBanUser (line 304) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method DeleteUser (line 312) | private async Task DeleteUser(int userID, bool isBanned)
method GetAllRoles (line 322) | [HttpGet("/Forums/AdminApi/GetAllRoles")]
method CreateRole (line 329) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method DeleteRole (line 339) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method GetImageApproval (line 353) | [HttpGet("/Forums/AdminApi/GetImageApproval")]
method ApproveUserImage (line 360) | [HttpPost("/Forums/AdminApi/ApproveUserImage/{id}")]
method DeleteUserImage (line 367) | [HttpPost("/Forums/AdminApi/DeleteUserImage/{id}")]
method GetEmailIPBan (line 376) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method BanEmail (line 386) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method RemoveEmail (line 394) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method BanIP (line 402) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method RemoveIP (line 410) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method EmailUsers (line 420) | [TypeFilter(typeof(OAuthOnlyForbidAttribute))]
method GetAllEventDefinitions (line 435) | [HttpGet("/Forums/AdminApi/GetAllEventDefinitions")]
method CreateEvent (line 444) | [HttpPost("/Forums/AdminApi/CreateEvent")]
method DeleteEvent (line 451) | [HttpPost("/Forums/AdminApi/DeleteEvent/{id}")]
method GetAllAwardDefinitions (line 460) | [HttpGet("/Forums/AdminApi/GetAllAwardDefinitions")]
method CreateAward (line 467) | [HttpPost("/Forums/AdminApi/CreateAward")]
method DeleteAward (line 474) | [HttpPost("/Forums/AdminApi/DeleteAward/{id}")]
method GetAward (line 481) | [HttpGet("/Forums/AdminApi/GetAward/{id}")]
method CreateCondition (line 491) | [HttpPost("/Forums/AdminApi/CreateCondition")]
method DeleteCondition (line 498) | [HttpPost("/Forums/AdminApi/DeleteCondition")]
method GetNames (line 507) | [HttpPost("/Forums/AdminApi/GetNames")]
method GetAllEvents (line 515) | [HttpGet("/Forums/AdminApi/GetAllEvents")]
method CreateManualEvent (line 522) | [HttpPost("/Forums/AdminApi/CreateManualEvent")]
method CreateExistingManualEvent (line 536) | [HttpPost("/Forums/AdminApi/CreateExistingManualEvent")]
method QueryIPHistory (line 552) | [HttpPost("/Forums/AdminApi/QueryIPHistory")]
method QuerySecurityLog (line 561) | [HttpPost("/Forums/AdminApi/QuerySecurityLog")]
method QueryModerationLog (line 581) | [HttpPost("/Forums/AdminApi/QueryModerationLog")]
method GetErrorLog (line 590) | [HttpGet("/Forums/AdminApi/GetErrorLog/{pageNumber}")]
method DeleteAllErrors (line 597) | [HttpPost("/Forums/AdminApi/DeleteAllErrors")]
method GetServices (line 606) | [HttpGet("/Forums/AdminApi/GetServices")]
method ClearServices (line 613) | [HttpPost("/Forums/AdminApi/ClearServices")]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/AdminController.cs
class AdminController (line 5) | [Authorize(Policy = PermanentRoles.Admin, AuthenticationSchemes = PopFor...
method App (line 11) | public ViewResult App(string vue = "")
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/ApiController.cs
class ApiController (line 5) | [Area("Forums")]
method ApiController (line 12) | public ApiController(INotificationAdapter notificationAdapter, IConfig...
method NotifyAward (line 18) | [HttpPost("/Forums/Api/NotifyAward")]
method NotifyReply (line 31) | [HttpPost("/Forums/Api/NotifyReply")]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/FavoritesController.cs
class FavoritesController (line 3) | [Area("Forums")]
method FavoritesController (line 7) | public FavoritesController(IFavoriteTopicService favoriteTopicService,...
method Topics (line 24) | public async Task<ViewResult> Topics(int pageNumber = 1)
method RemoveFavorite (line 36) | [HttpPost]
method ToggleFavorite (line 45) | [HttpPost]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/ForumController.cs
class ForumController (line 5) | [Area("Forums")]
method ForumController (line 9) | public ForumController(ISettingsManager settingsManager, IForumService...
method Index (line 44) | public async Task<ActionResult> Index(string urlName, int pageNumber = 1)
method PostTopic (line 76) | public async Task<ActionResult> PostTopic(int id)
method PostTopic (line 92) | [HttpPost]
method GetForumByIdWithPermissionContext (line 110) | private async Task<Tuple<Forum, ForumPermissionContext>> GetForumByIdW...
method GetPermissionContextByTopicID (line 119) | private async Task<Tuple<ForumPermissionContext, Topic>> GetPermission...
method TopicID (line 132) | public async Task<ActionResult> TopicID(int id)
method Topic (line 140) | public async Task<ActionResult> Topic(string id, int pageNumber = 1)
method TopicPage (line 210) | public async Task<ActionResult> TopicPage(int id, int pageNumber, int ...
method PostReply (line 246) | public async Task<ActionResult> PostReply(int id, int replyID = 0)
method PostReply (line 284) | [HttpPost]
method Post (line 299) | public async Task<ActionResult> Post(int id)
method Recent (line 319) | public async Task<ViewResult> Recent(int pageNumber = 1)
method MarkForumRead (line 334) | [HttpPost]
method MarkAllForumsRead (line 347) | [HttpPost]
method PostLink (line 357) | public async Task<ActionResult> PostLink(int id)
method GoToNewestPost (line 379) | public async Task<ActionResult> GoToNewestPost(int id)
method Edit (line 396) | public async Task<ActionResult> Edit(int id)
method Edit (line 408) | [HttpPost]
method DeletePost (line 421) | [HttpPost]
method IsLastPostInTopic (line 438) | public async Task<ContentResult> IsLastPostInTopic(int id, int lastPos...
method TopicPartial (line 446) | public async Task<ActionResult> TopicPartial(int id, int lastPost, int...
method Voters (line 479) | public async Task<ActionResult> Voters(int id)
method ToggleVote (line 488) | [HttpPost]
class PreviewModel (line 508) | public class PreviewModel
method PreviewText (line 514) | [HttpPost]
method ComposeTopicContainer (line 521) | private static TopicContainer ComposeTopicContainer(Topic topic, Forum...
class SetAnswerModel (line 526) | public class SetAnswerModel
method SetAnswer (line 532) | [HttpPost]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/HomeController.cs
class HomeController (line 3) | [Area("Forums")]
method HomeController (line 7) | public HomeController(IForumService forumService, IUserService userSer...
method Index (line 22) | public async Task<ViewResult> Index()
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/IdentityController.cs
class IdentityController (line 11) | [Area("Forums")]
method IdentityController (line 29) | public IdentityController(ILoginLinkFactory loginLinkFactory, IStateHa...
class Credentials (line 49) | public class Credentials
method Login (line 55) | [PopForumsAuthenticationIgnore]
method Logout (line 70) | [HttpGet]
method LogoutAsync (line 88) | [HttpPost]
method ExternalLogin (line 97) | [PopForumsAuthenticationIgnore]
method ExternalLoginCallback (line 137) | [PopForumsAuthenticationIgnore]
method LoginAndAssociate (line 169) | [PopForumsAuthenticationIgnore]
method PerformSignInAsync (line 199) | public static async Task PerformSignInAsync(User user, HttpContext htt...
method PerformSignInAsync (line 205) | public static async Task PerformSignInAsync(User user, HttpContext htt...
method CallbackHandler (line 222) | [PopForumsAuthenticationIgnore]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/IgnoreController.cs
class IgnoreController (line 3) | [Area("Forums")]
method Add (line 8) | [HttpPost]
method Remove (line 18) | [HttpPost]
method RemoveFromList (line 28) | [HttpPost]
method List (line 38) | public async Task<IActionResult> List()
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/ImageController.cs
class ImageController (line 6) | [Area("Forums")]
method ImageController (line 10) | public ImageController(IImageService imageService, IUserRetrievalShim ...
method Avatar (line 23) | [PopForumsAuthenticationIgnore]
method UserImage (line 29) | [PopForumsAuthenticationIgnore]
method SetupImageResult (line 35) | private async Task<ActionResult> SetupImageResult(Func<int, Task<IStre...
method PostImage (line 59) | public async Task<ActionResult> PostImage(string id)
method UploadPostImage (line 84) | [HttpPost]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/ModeratorController.cs
class ModeratorController (line 3) | [Authorize(Policy = PermanentRoles.Moderator)]
method ModeratorController (line 8) | public ModeratorController(ITopicService topicService, IForumService f...
method TogglePin (line 23) | [HttpPost]
method ToggleClosed (line 37) | [HttpPost]
method ToggleDeleted (line 51) | [HttpPost]
method UpdateTopic (line 65) | [HttpPost]
method UndeletePost (line 86) | [HttpPost]
method TopicModerationLog (line 97) | public async Task<ViewResult> TopicModerationLog(int id)
method PostModerationLog (line 106) | public async Task<ViewResult> PostModerationLog(int id)
method DeleteTopicPermanently (line 115) | [HttpPost]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/PrivateMessagesController.cs
class PrivateMessagesController (line 5) | [Area("Forums")]
method PrivateMessagesController (line 9) | public PrivateMessagesController(IPrivateMessageService privateMessage...
method Index (line 24) | public async Task<ActionResult> Index(int pageNumber = 1)
method Archive (line 34) | public async Task<ActionResult> Archive(int pageNumber = 1)
method View (line 44) | public async Task<ActionResult> View(int id)
method Create (line 62) | public async Task<ActionResult> Create(int? id)
method Create (line 79) | [HttpPost]
method GetNames (line 98) | public async Task<JsonResult> GetNames(string id)
method ArchivePM (line 105) | [HttpPost]
method UnarchivePM (line 118) | [HttpPost]
method NewPMCount (line 131) | public async Task<ContentResult> NewPMCount()
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/ResourcesController.cs
class ResourcesController (line 5) | [Area("Forums")]
method ResourcesController (line 10) | public ResourcesController(IResourceComposer resourceComposer)
method Index (line 15) | [ResponseCache(Duration = 600, Location = ResponseCacheLocation.Client)]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/SearchController.cs
class SearchController (line 3) | [Area("Forums")]
method SearchController (line 7) | public SearchController(ISearchService searchService, IForumService fo...
method Index (line 22) | public ViewResult Index()
method Process (line 29) | [HttpPost]
method Result (line 37) | public async Task<ViewResult> Result(string query, SearchType searchTy...
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/SetupController.cs
class SetupController (line 5) | [Area("Forums")]
method SetupController (line 8) | public SetupController(ISetupService setupService, IConfig config)
method Index (line 19) | [PopForumsAuthenticationIgnore]
method OAuthOnlySetup (line 35) | public IActionResult OAuthOnlySetup()
method Index (line 47) | [PopForumsAuthenticationIgnore]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/SitemapController.cs
class SitemapController (line 3) | [Area("Forums")]
method SitemapController (line 11) | public SitemapController(ISitemapService sitemapService)
method Index (line 16) | [HttpGet("/Forums/Sitemap.xml")]
method Page (line 25) | [HttpGet("/Forums/Sitemap.{page}.xml")]
FILE: src/PopForums.Mvc/Areas/Forums/Controllers/SubscriptionController.cs
class SubscriptionController (line 3) | [Area("Forums")]
method SubscriptionController (line 7) | public SubscriptionController(ISubscribedTopicsService subService, ITo...
method Topics (line 28) | public async Task<ViewResult> Topics(int pageNumber = 1)
method Unsubscribe (line 40) | [HttpPost]
method ToggleSubscription (line 49) | [HttpPost]
FILE: src/PopForums.Mvc/Areas/Forums/Extensions/ApplicationBuilders.cs
class ApplicationBuilders (line 5) | public static class ApplicationBuilders
method UsePopForumsAuth (line 10) | public static IApplicationBuilder UsePopForumsAuth(this IApplicationBu...
method UsePopForumsCultures (line 19) | public static IApplicationBuilder UsePopForumsCultures(this IApplicati...
FILE: src/PopForums.Mvc/Areas/Forums/Extensions/AuthorizationOptionsExtensions.cs
class AuthorizationOptionsExtensions (line 5) | public static class AuthorizationOptionsExtensions
method AddPopForumsPolicies (line 11) | public static void AddPopForumsPolicies(this AuthorizationOptions opti...
FILE: src/PopForums.Mvc/Areas/Forums/Extensions/Logger.cs
class Logger (line 5) | public class Logger : ILogger
method Logger (line 11) | public Logger(IErrorLog errorLog, ISettingsManager settingsManager, IH...
method Log (line 18) | public void Log<TState>(LogLevel logLevel, EventId eventId, TState sta...
method IsEnabled (line 59) | public bool IsEnabled(LogLevel logLevel)
method BeginScope (line 64) | public IDisposable BeginScope<TState>(TState state)
class NoopDisposable (line 69) | private class NoopDisposable : IDisposable
method Dispose (line 73) | public void Dispose()
FILE: src/PopForums.Mvc/Areas/Forums/Extensions/LoggerFactories.cs
class LoggerFactories (line 3) | public static class LoggerFactories
method AddPopForumsLogger (line 5) | public static ILoggerFactory AddPopForumsLogger(this ILoggerFactory lo...
FILE: src/PopForums.Mvc/Areas/Forums/Extensions/LoggerProvider.cs
class LoggerProvider (line 3) | public class LoggerProvider : ILoggerProvider
method LoggerProvider (line 9) | public LoggerProvider(IErrorLog errorLog, ISettingsManager settingsMan...
method Dispose (line 16) | public void Dispose()
method CreateLogger (line 20) | public ILogger CreateLogger(string categoryName)
FILE: src/PopForums.Mvc/Areas/Forums/Extensions/ServiceCollections.cs
class ServiceCollections (line 7) | public static class ServiceCollections
method AddPopForumsMvc (line 15) | public static IServiceCollection AddPopForumsMvc(this IServiceCollecti...
method AddPopForumsMvc (line 28) | public static IServiceCollection AddPopForumsMvc(this IServiceCollecti...
method AddPopForumsBackgroundJobs (line 64) | public static IServiceCollection AddPopForumsBackgroundJobs(this IServ...
FILE: src/PopForums.Mvc/Areas/Forums/Extensions/WebApplications.cs
class WebApplications (line 3) | public static class WebApplications
method AddPopForumsEndpoints (line 10) | public static WebApplication AddPopForumsEndpoints(this WebApplication...
FILE: src/PopForums.Mvc/Areas/Forums/ForumRouteConstraint.cs
class ForumRouteConstraint (line 3) | public class ForumRouteConstraint : IRouteConstraint
method ForumRouteConstraint (line 5) | public ForumRouteConstraint(IForumRepository forumRepository)
method Match (line 12) | public bool Match(HttpContext httpContext, IRouter route, string route...
FILE: src/PopForums.Mvc/Areas/Forums/Messaging/Broker.cs
class Broker (line 3) | public class Broker : IBroker
method Broker (line 5) | public Broker(IForumRepository forumRepo, ITenantService tenantService...
method NotifyNewPosts (line 16) | public void NotifyNewPosts(Topic topic, int lasPostID)
method NotifyNewPost (line 22) | public void NotifyNewPost(Topic topic, int postID)
method NotifyForumUpdate (line 28) | public void NotifyForumUpdate(Forum forum)
method NotifyTopicUpdate (line 34) | public void NotifyTopicUpdate(Topic topic, Forum forum, string topicLink)
method NotifyPMCount (line 57) | public async void NotifyPMCount(int userID, int pmCount)
method NotifyUser (line 64) | public async void NotifyUser(Notification notification)
method NotifyUser (line 71) | public async void NotifyUser(Notification notification, string tenantID)
method SendPMMessage (line 77) | public async void SendPMMessage(PrivateMessagePost post)
FILE: src/PopForums.Mvc/Areas/Forums/Messaging/PopForumsHub.cs
class PopForumsHub (line 5) | public class PopForumsHub : Hub
method PopForumsHub (line 14) | public PopForumsHub(ITenantService tenantService, IUserService userSer...
method ListenToAllForums (line 26) | public void ListenToAllForums()
method ListenToForum (line 32) | public void ListenToForum(int forumID)
method ListenRecent (line 40) | public void ListenRecent()
method ListenToTopic (line 56) | public void ListenToTopic(int topicID)
method GetLastPostID (line 62) | public int GetLastPostID(int topicID)
method GetUserID (line 69) | private int GetUserID()
method MarkNotificationRead (line 78) | public async Task MarkNotificationRead(long contextID, int notificatio...
method MarkAllRead (line 85) | public async Task MarkAllRead()
method GetNotifications (line 91) | public async Task<List<Notification>> GetNotifications(DateTime afterD...
method GetNotificationCount (line 98) | public async Task<int> GetNotificationCount()
method GetPMCount (line 105) | public async Task<int> GetPMCount()
method ListenToPm (line 114) | public async Task ListenToPm(int pmID)
method SendPm (line 123) | public async Task SendPm(int pmID, string fullText)
method AckReadPm (line 133) | public async Task AckReadPm(int pmID)
method GetPmPosts (line 139) | public async Task<ClientPrivateMessagePost[]> GetPmPosts(int pmID, Dat...
method GetMostRecentPmPosts (line 151) | public async Task<ClientPrivateMessagePost[]> GetMostRecentPmPosts(int...
FILE: src/PopForums.Mvc/Areas/Forums/Messaging/PopForumsUserIdProvider.cs
class PopForumsUserIdProvider (line 3) | public class PopForumsUserIdProvider : IUserIdProvider
method PopForumsUserIdProvider (line 8) | public PopForumsUserIdProvider(IUserRetrievalShim userRetrievalShim, I...
method GetUserId (line 14) | public string GetUserId(HubConnectionContext connection)
method FormatUserID (line 24) | public static string FormatUserID(string tenantID, int userID)
FILE: src/PopForums.Mvc/Areas/Forums/Models/AwardConditionDeleteContainer.cs
class AwardConditionDeleteContainer (line 3) | public class AwardConditionDeleteContainer
FILE: src/PopForums.Mvc/Areas/Forums/Models/EmailUsersContainer.cs
class EmailUsersContainer (line 3) | public class EmailUsersContainer
FILE: src/PopForums.Mvc/Areas/Forums/Models/ExternalLoginState.cs
class ExternalLoginState (line 5) | public class ExternalLoginState
FILE: src/PopForums.Mvc/Areas/Forums/Models/ExternalLoginTypeMetadata.cs
class ExternalLoginTypeMetadata (line 5) | public class ExternalLoginTypeMetadata
FILE: src/PopForums.Mvc/Areas/Forums/Models/IPHistoryQuery.cs
class IPHistoryQuery (line 3) | public class IPHistoryQuery
FILE: src/PopForums.Mvc/Areas/Forums/Models/ManualEvent.cs
class ManualEvent (line 3) | public class ManualEvent
FILE: src/PopForums.Mvc/Areas/Forums/Models/SecurityLogQuery.cs
class SecurityLogQuery (line 3) | public class SecurityLogQuery
FILE: src/PopForums.Mvc/Areas/Forums/Models/UserEditPhoto.cs
class UserEditPhoto (line 3) | public class UserEditPhoto
method UserEditPhoto (line 5) | public UserEditPhoto() { }
method UserEditPhoto (line 7) | public UserEditPhoto(Profile profile)
FILE: src/PopForums.Mvc/Areas/Forums/Models/UserEditWithFiles.cs
class UserEditWithFiles (line 3) | public class UserEditWithFiles : UserEdit
method UserEditWithFiles (line 5) | public UserEditWithFiles()
method UserEditWithFiles (line 10) | public UserEditWithFiles(User user, Profile profile) : base(user, prof...
FILE: src/PopForums.Mvc/Areas/Forums/Models/UserState.cs
class UserState (line 3) | public class UserState
FILE: src/PopForums.Mvc/Areas/Forums/Services/ExternalLoginRoutingService.cs
type IExternalLoginRoutingService (line 5) | public interface IExternalLoginRoutingService
method GetActiveProviderTypeAndNameDictionary (line 7) | Dictionary<ProviderType, ExternalLoginTypeMetadata> GetActiveProviderT...
class ExternalLoginRoutingService (line 10) | public class ExternalLoginRoutingService : IExternalLoginRoutingService
method ExternalLoginRoutingService (line 14) | public ExternalLoginRoutingService(ISettingsManager settingsManager)
method GetActiveProviderTypeAndNameDictionary (line 19) | public Dictionary<ProviderType, ExternalLoginTypeMetadata> GetActivePr...
FILE: src/PopForums.Mvc/Areas/Forums/Services/ExternalLoginTempService.cs
type IExternalLoginTempService (line 3) | public interface IExternalLoginTempService
method Persist (line 5) | void Persist(ExternalLoginState externalLoginState);
method Read (line 6) | ExternalLoginState Read();
method Remove (line 7) | void Remove();
class ExternalLoginTempService (line 10) | public class ExternalLoginTempService : IExternalLoginTempService
method ExternalLoginTempService (line 16) | public ExternalLoginTempService(IDataProtectionProvider dataProtection...
method Persist (line 22) | public void Persist(ExternalLoginState externalLoginState)
method Read (line 30) | public ExternalLoginState Read()
method Remove (line 43) | public void Remove()
FILE: src/PopForums.Mvc/Areas/Forums/Services/ForumAdapterFactory.cs
class ForumAdapterFactory (line 3) | public class ForumAdapterFactory
method ForumAdapterFactory (line 5) | public ForumAdapterFactory(Forum forum)
FILE: src/PopForums.Mvc/Areas/Forums/Services/IForumAdapter.cs
type IForumAdapter (line 11) | public interface IForumAdapter
method AdaptForum (line 19) | Task AdaptForum(Controller controller, ForumTopicContainer forumTopicC...
method AdaptTopic (line 27) | Task AdaptTopic(Controller controller, TopicContainer topicContainer);
method AdaptPostLink (line 39) | Task<RedirectResult> AdaptPostLink(Controller controller, Post post, T...
FILE: src/PopForums.Mvc/Areas/Forums/Services/OAuthOnlyService.cs
type IOAuthOnlyService (line 6) | public interface IOAuthOnlyService
method GetLoginUrl (line 8) | string GetLoginUrl(string redirectUrl);
method ProcessOAuthLogin (line 9) | Task<CallbackResult> ProcessOAuthLogin(string redirectUrl, string ip);
method AttemptTokenRefresh (line 10) | Task<bool> AttemptTokenRefresh(User user);
class OAuthOnlyService (line 13) | public class OAuthOnlyService : IOAuthOnlyService
method OAuthOnlyService (line 26) | public OAuthOnlyService(IConfig config, IOAuth2LoginUrlGenerator oAuth...
method GetLoginUrl (line 40) | public string GetLoginUrl(string redirectUrl)
method ProcessOAuthLogin (line 48) | public async Task<CallbackResult> ProcessOAuthLogin(string redirectUrl...
method AttemptTokenRefresh (line 124) | public async Task<bool> AttemptTokenRefresh(User user)
FILE: src/PopForums.Mvc/Areas/Forums/Services/TopicViewCountService.cs
class TopicViewCountService (line 3) | public class TopicViewCountService : ITopicViewCountService
method TopicViewCountService (line 5) | public TopicViewCountService(ITopicRepository topicRepository, IHttpCo...
method ProcessView (line 15) | public async Task ProcessView(Topic topic)
method SetViewedTopic (line 31) | public void SetViewedTopic(Topic topic)
FILE: src/PopForums.Mvc/Areas/Forums/Services/UserRetrievalShim.cs
class UserRetrievalShim (line 3) | public class UserRetrievalShim : IUserRetrievalShim
method UserRetrievalShim (line 7) | public UserRetrievalShim(IHttpContextAccessor httpContextAccessor)
method GetUser (line 12) | public User GetUser()
method GetProfile (line 18) | public Profile GetProfile()
FILE: src/PopForums.Mvc/Areas/Forums/Services/UserStateComposer.cs
type IUserStateComposer (line 3) | public interface IUserStateComposer
method GetState (line 5) | Task<UserState> GetState();
class UserStateComposer (line 9) | public class UserStateComposer : IUserStateComposer
method UserStateComposer (line 16) | public UserStateComposer(IUserRetrievalShim userRetrievalShim, IPrivat...
method GetState (line 24) | public async Task<UserState> GetState()
FILE: src/PopForums.Mvc/Areas/Forums/TagHelpers/ForumReadIndicatorTagHelper.cs
class ForumReadIndicatorTagHelper (line 3) | [HtmlTargetElement("pf-forumReadIndicator", Attributes = "forum, categor...
method Process (line 13) | public override void Process(TagHelperContext context, TagHelperOutput...
FILE: src/PopForums.Mvc/Areas/Forums/TagHelpers/PMReadIndicatorTagHelper.cs
class PMReadIndicatorTagHelper (line 3) | [HtmlTargetElement("pf-pmReadIndicator", Attributes = "privateMessage")]
method Process (line 11) | public override void Process(TagHelperContext context, TagHelperOutput...
FILE: src/PopForums.Mvc/Areas/Forums/TagHelpers/PagerLinksTagHelper.cs
class PagerLinksTagHelper (line 3) | [HtmlTargetElement("pf-pagerLinks", Attributes = "controllerName, action...
method PagerLinksTagHelper (line 31) | public PagerLinksTagHelper(IHtmlGenerator htmlGenerator)
method Process (line 36) | public override void Process(TagHelperContext context, TagHelperOutput...
method GetString (line 193) | private static string GetString(IHtmlContent content)
FILE: src/PopForums.Mvc/Areas/Forums/TagHelpers/TopicReadIndicatorTagHelper.cs
class TopicReadIndicatorTagHelper (line 3) | [HtmlTargetElement("pf-topicReadIndicator", Attributes = "topic, pagedTo...
method Process (line 13) | public override void Process(TagHelperContext context, TagHelperOutput...
FILE: src/PopForums.Mvc/Areas/Forums/TagHelpers/ValidationClassTagHelper.cs
class ValidationClassTagHelper (line 3) | [HtmlTargetElement("div", Attributes = ValidationForAttributeName + "," ...
method Process (line 19) | public override void Process(TagHelperContext context, TagHelperOutput...
FILE: src/PopForums.Mvc/Areas/Forums/ViewComponents/UserNavigationViewComponent.cs
class UserNavigationViewComponent (line 4) | public class UserNavigationViewComponent : ViewComponent
method InvokeAsync (line 6) | public async Task<IViewComponentResult> InvokeAsync()
FILE: src/PopForums.Mvc/Areas/Forums/ViewComponents/UserStateViewComponent.cs
class UserStateViewComponent (line 3) | public class UserStateViewComponent : ViewComponent
method UserStateViewComponent (line 7) | public UserStateViewComponent(IUserStateComposer userStateComposer)
method InvokeAsync (line 12) | public async Task<IViewComponentResult> InvokeAsync()
FILE: src/PopForums.Mvc/Client/Components/AnswerButton.ts
class AnswerButton (line 3) | class AnswerButton extends ElementBase<TopicState> {
method constructor (line 4) | constructor() {
method answerstatusclass (line 8) | get answerstatusclass(): string {
method chooseanswertext (line 11) | get chooseanswertext(): string {
method topicid (line 14) | get topicid(): string {
method postid (line 17) | get postid(): string {
method answerpostid (line 20) | get answerpostid(): string {
method userid (line 23) | get userid(): string {
method startedbyuserid (line 26) | get startedbyuserid(): string {
method isfirstintopic (line 29) | get isfirstintopic(): string {
method connectedCallback (line 35) | connectedCallback() {
method getDependentReference (line 49) | getDependentReference(): [TopicState, string] {
method updateUI (line 53) | updateUI(answerPostID: number): void {
FILE: src/PopForums.Mvc/Client/Components/CommentButton.ts
class CommentButton (line 3) | class CommentButton extends ElementBase<TopicState> {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method buttontext (line 12) | get buttontext(): string {
method topicid (line 16) | get topicid(): string {
method postid (line 20) | get postid(): string {
method connectedCallback (line 24) | connectedCallback() {
method getDependentReference (line 38) | getDependentReference(): [TopicState, string] {
method updateUI (line 42) | updateUI(data: number): void {
FILE: src/PopForums.Mvc/Client/Components/FavoriteButton.ts
class FavoriteButton (line 3) | class FavoriteButton extends ElementBase<TopicState> {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method makefavoritetext (line 12) | get makefavoritetext(): string {
method removefavoritetext (line 15) | get removefavoritetext(): string {
method connectedCallback (line 19) | connectedCallback() {
method getDependentReference (line 47) | getDependentReference(): [TopicState, string] {
method updateUI (line 51) | updateUI(data: boolean): void {
FILE: src/PopForums.Mvc/Client/Components/FormattedTime.ts
class FormattedTime (line 3) | class FormattedTime extends HTMLElement {
method constructor (line 4) | constructor() {
method utctime (line 8) | get utctime(): string {
method connectedCallback (line 17) | connectedCallback() {
method ready (line 24) | ready() {
method setBaseTime (line 36) | private setBaseTime() {
method UpdateTimer (line 44) | private UpdateTimer(): void {
method GetDisplayTime (line 51) | private GetDisplayTime(): string {
method observedAttributes (line 75) | static get observedAttributes() { return ["utctime"]; }
method attributeChangedCallback (line 77) | attributeChangedCallback(name: string, oldValue: string, newValue: str...
FILE: src/PopForums.Mvc/Client/Components/FullText.ts
class FullText (line 3) | class FullText extends ElementBase<TopicState> {
method constructor (line 4) | constructor() {
method overridelistener (line 8) | get overridelistener(): string {
method forcenoimage (line 12) | get forcenoimage(): string {
method isshort (line 16) | get isshort(): string {
method formID (line 20) | get formID() { return this.getAttribute("formid") }
method value (line 22) | get value() { return this._value;}
method value (line 23) | set value(v: string) { this._value = v; }
method connectedCallback (line 32) | connectedCallback() {
method getDependentReference (line 138) | getDependentReference(): [TopicState, string] {
method updateUI (line 142) | updateUI(data: any): void {
FILE: src/PopForums.Mvc/Client/Components/HomeUpdater.ts
class HomeUpdater (line 3) | class HomeUpdater extends HTMLElement {
method constructor (line 4) | constructor() {
method connectedCallback (line 8) | async connectedCallback() {
method updateForumStats (line 18) | updateForumStats(data: any) {
FILE: src/PopForums.Mvc/Client/Components/LoginForm.ts
class LoginForm (line 3) | class LoginForm extends HTMLElement {
method constructor (line 4) | constructor() {
method templateid (line 8) | get templateid() {
method isExternalLogin (line 11) | get isExternalLogin() {
method connectedCallback (line 19) | connectedCallback() {
method executeLogin (line 39) | executeLogin() {
FILE: src/PopForums.Mvc/Client/Components/MorePostsBeforeReplyButton.ts
class MorePostsBeforeReplyButton (line 3) | class MorePostsBeforeReplyButton extends ElementBase<TopicState> {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method buttontext (line 11) | get buttontext(): string {
method connectedCallback (line 15) | connectedCallback() {
method getDependentReference (line 27) | getDependentReference(): [TopicState, string] {
method updateUI (line 31) | updateUI(data: boolean): void {
FILE: src/PopForums.Mvc/Client/Components/MorePostsButton.ts
class MorePostsButton (line 3) | class MorePostsButton extends ElementBase<TopicState> {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method buttontext (line 11) | get buttontext(): string {
method connectedCallback (line 15) | connectedCallback() {
method getDependentReference (line 27) | getDependentReference(): [TopicState, string] {
method updateUI (line 31) | updateUI(data: number): void {
FILE: src/PopForums.Mvc/Client/Components/NotificationItem.ts
class NotificationItem (line 3) | class NotificationItem extends HTMLElement {
method constructor (line 4) | constructor(notification: Notification) {
method escapeHtml (line 11) | private escapeHtml(s: string): string {
method connectedCallback (line 15) | connectedCallback() {
method MarkRead (line 66) | MarkRead() {
FILE: src/PopForums.Mvc/Client/Components/NotificationList.ts
class NotificationList (line 3) | class NotificationList extends ElementBase<UserState> {
method constructor (line 4) | constructor() {
method connectedCallback (line 8) | connectedCallback() {
method getDependentReference (line 12) | getDependentReference(): [UserState, string] {
method updateUI (line 16) | updateUI(data: Array<Notification>): void {
FILE: src/PopForums.Mvc/Client/Components/NotificationMarkAllButton.ts
class NotificationMarkAllButton (line 3) | class NotificationMarkAllButton extends HTMLElement {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method buttontext (line 11) | get buttontext(): string {
method connectedCallback (line 15) | connectedCallback() {
FILE: src/PopForums.Mvc/Client/Components/NotificationToggle.ts
class NotificationToggle (line 3) | class NotificationToggle extends ElementBase<UserState> {
method constructor (line 4) | constructor() {
method panelid (line 10) | get panelid(): string {
method notificationlistid (line 14) | get notificationlistid(): string {
method connectedCallback (line 24) | connectedCallback() {
method ready (line 32) | ready() {
method show (line 41) | private async show() {
method getDependentReference (line 50) | getDependentReference(): [UserState, string] {
method updateUI (line 54) | updateUI(data: number): void {
FILE: src/PopForums.Mvc/Client/Components/PMCount.ts
class PMCount (line 3) | class PMCount extends ElementBase<UserState> {
method constructor (line 4) | constructor() {
method getDependentReference (line 11) | getDependentReference(): [UserState, string] {
method updateUI (line 15) | updateUI(data: number): void {
FILE: src/PopForums.Mvc/Client/Components/PMForm.ts
class PMForm (line 3) | class PMForm extends HTMLElement {
method constructor (line 4) | constructor() {
method connectedCallback (line 10) | connectedCallback() {
method ready (line 17) | ready() {
method send (line 33) | private send(textBox: HTMLTextAreaElement) {
FILE: src/PopForums.Mvc/Client/Components/PostMiniProfile.ts
class PostMiniProfile (line 3) | class PostMiniProfile extends HTMLElement {
method constructor (line 4) | constructor() {
method username (line 8) | get username(): string {
method usernameclass (line 11) | get usernameclass(): string {
method userid (line 14) | get userid(): string {
method miniProfileBoxClass (line 17) | get miniProfileBoxClass(): string {
method connectedCallback (line 26) | connectedCallback() {
method toggle (line 39) | private toggle() {
FILE: src/PopForums.Mvc/Client/Components/PostModerationLogButton.ts
class PostModerationLogButton (line 3) | class PostModerationLogButton extends HTMLElement {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method buttontext (line 12) | get buttontext(): string {
method postid (line 16) | get postid(): string {
method parentSelectorToAppendTo (line 20) | get parentSelectorToAppendTo(): string {
method connectedCallback (line 24) | connectedCallback() {
FILE: src/PopForums.Mvc/Client/Components/PreviewButton.ts
class PreviewButton (line 3) | class PreviewButton extends HTMLElement {
method constructor (line 4) | constructor() {
method labelText (line 8) | get labelText(): string {
method textSourceSelector (line 11) | get textSourceSelector(): string {
method isPlainTextSelector (line 14) | get isPlainTextSelector(): string {
method connectedCallback (line 18) | connectedCallback() {
method openModal (line 30) | openModal() {
FILE: src/PopForums.Mvc/Client/Components/PreviousPostsButton.ts
class PreviousPostsButton (line 3) | class PreviousPostsButton extends ElementBase<TopicState> {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method buttontext (line 11) | get buttontext(): string {
method connectedCallback (line 15) | connectedCallback() {
method getDependentReference (line 27) | getDependentReference(): [TopicState, string] {
method updateUI (line 31) | updateUI(data: number): void {
FILE: src/PopForums.Mvc/Client/Components/QuoteButton.ts
class QuoteButton (line 3) | class QuoteButton extends HTMLElement {
method constructor (line 4) | constructor() {
method name (line 8) | get name(): string {
method containerid (line 11) | get containerid(): string {
method buttonclass (line 14) | get buttonclass(): string {
method buttontext (line 17) | get buttontext(): string {
method tip (line 20) | get tip(): string {
method postID (line 23) | get postID(): string {
method connectedCallback (line 29) | connectedCallback() {
FILE: src/PopForums.Mvc/Client/Components/ReplyButton.ts
class ReplyButton (line 3) | class ReplyButton extends ElementBase<TopicState> {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method buttontext (line 12) | get buttontext(): string {
method topicid (line 16) | get topicid(): string {
method postid (line 20) | get postid(): string {
method overridedisplay (line 24) | get overridedisplay(): string {
method connectedCallback (line 28) | connectedCallback() {
method getDependentReference (line 42) | getDependentReference(): [TopicState, string] {
method updateUI (line 46) | updateUI(data: boolean): void {
FILE: src/PopForums.Mvc/Client/Components/ReplyForm.ts
class ReplyForm (line 3) | class ReplyForm extends HTMLElement {
method constructor (line 4) | constructor() {
method templateID (line 8) | get templateID() {
method connectedCallback (line 14) | connectedCallback() {
method submitReply (line 27) | submitReply() {
FILE: src/PopForums.Mvc/Client/Components/SearchNavForm.ts
class SearchNavForm (line 3) | class SearchNavForm extends HTMLElement {
method constructor (line 4) | constructor() {
method templateid (line 8) | get templateid() {
method textboxid (line 11) | get textboxid() {
method dropdownid (line 14) | get dropdownid() {
method connectedCallback (line 21) | connectedCallback() {
FILE: src/PopForums.Mvc/Client/Components/SubscribeButton.ts
class SubscribeButton (line 3) | class SubscribeButton extends ElementBase<TopicState> {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method subscribetext (line 12) | get subscribetext(): string {
method unsubscribetext (line 15) | get unsubscribetext(): string {
method connectedCallback (line 19) | connectedCallback() {
method getDependentReference (line 47) | getDependentReference(): [TopicState, string] {
method updateUI (line 51) | updateUI(data: boolean): void {
FILE: src/PopForums.Mvc/Client/Components/TopicButton.ts
class TopicButton (line 3) | class TopicButton extends ElementBase<ForumState> {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method buttontext (line 12) | get buttontext(): string {
method forumid (line 16) | get forumid(): string {
method connectedCallback (line 20) | connectedCallback() {
method getDependentReference (line 32) | getDependentReference(): [ForumState, string] {
method updateUI (line 36) | updateUI(data: boolean): void {
FILE: src/PopForums.Mvc/Client/Components/TopicForm.ts
class TopicForm (line 3) | class TopicForm extends HTMLElement {
method constructor (line 4) | constructor() {
method templateID (line 8) | get templateID() {
method connectedCallback (line 14) | connectedCallback() {
method submitTopic (line 27) | submitTopic() {
FILE: src/PopForums.Mvc/Client/Components/TopicModerationLogButton.ts
class TopicModerationLogButton (line 3) | class TopicModerationLogButton extends HTMLElement {
method constructor (line 4) | constructor() {
method buttonclass (line 8) | get buttonclass(): string {
method buttontext (line 12) | get buttontext(): string {
method topicid (line 16) | get topicid(): string {
method connectedCallback (line 20) | connectedCallback() {
FILE: src/PopForums.Mvc/Client/Components/VoteCount.ts
class VoteCount (line 3) | class VoteCount extends HTMLElement {
method constructor (line 4) | constructor() {
method votes (line 8) | get votes(): string {
method votes (line 11) | set votes(value:string) {
method postid (line 15) | get postid(): string {
method containerclass (line 19) | get containerclass(): string {
method votescontainerclass (line 23) | get votescontainerclass(): string {
method badgeclass (line 27) | get badgeclass(): string {
method votebuttonclass (line 31) | get votebuttonclass(): string {
method isloggedin (line 35) | get isloggedin(): string {
method isauthor (line 39) | get isauthor(): string {
method isvoted (line 43) | get isvoted(): string {
method connectedCallback (line 52) | connectedCallback() {
method setupVoterPopover (line 96) | private setupVoterPopover(): void {
method applyPopover (line 119) | private applyPopover(): void {
method buttonGenerator (line 130) | private buttonGenerator(): string {
FILE: src/PopForums.Mvc/Client/Declarations.ts
function Ready (line 9) | function Ready(callback: any): void {
class BlobInfo (line 23) | class BlobInfo {
class Tooltip (line 34) | class Tooltip {
class Popover (line 37) | class Popover {
class Offcanvas (line 42) | class Offcanvas extends HTMLElement {
type HttpTransportType (line 49) | enum HttpTransportType {
class HubConnectionBuilder (line 54) | class HubConnectionBuilder {
FILE: src/PopForums.Mvc/Client/ElementBase.ts
method connectedCallback (line 5) | connectedCallback() {
method update (line 18) | update() {
FILE: src/PopForums.Mvc/Client/Models/Notification.ts
class Notification (line 3) | class Notification {
FILE: src/PopForums.Mvc/Client/Models/PrivateMessage.ts
class PrivateMessage (line 3) | class PrivateMessage {
FILE: src/PopForums.Mvc/Client/Models/PrivateMessageUser.ts
class PrivateMessageUser (line 2) | class PrivateMessageUser {
FILE: src/PopForums.Mvc/Client/Services/LocalizationService.ts
class LocalizationService (line 3) | class LocalizationService {
method init (line 4) | static init(): void {
method signal (line 16) | private static signal() {
method subscribe (line 30) | static subscribe(ready: Function): boolean {
FILE: src/PopForums.Mvc/Client/Services/MessagingService.ts
class MessagingService (line 3) | class MessagingService {
method GetService (line 7) | static async GetService(): Promise<MessagingService> {
method start (line 19) | private async start() {
FILE: src/PopForums.Mvc/Client/Services/NotificationService.ts
class NotificationService (line 3) | class NotificationService {
method constructor (line 4) | constructor(userState: UserState) {
method initialize (line 11) | async initialize(): Promise<void> {
method LoadNotifications (line 38) | async LoadNotifications(): Promise<void> {
method MarkRead (line 53) | async MarkRead(contextID: number, notificationType: number) : Promise<...
method MarkAllRead (line 57) | async MarkAllRead() : Promise<void> {
method getNotifications (line 66) | private async getNotifications() {
FILE: src/PopForums.Mvc/Client/State/ForumState.ts
class ForumState (line 3) | class ForumState extends StateBase {
method constructor (line 4) | constructor() {
method setupForum (line 14) | setupForum() {
method loadNewTopic (line 21) | loadNewTopic() {
method forumListen (line 36) | async forumListen() {
method recentListen (line 56) | async recentListen() {
FILE: src/PopForums.Mvc/Client/State/Localizations.ts
class Localizations (line 2) | class Localizations {
FILE: src/PopForums.Mvc/Client/State/PrivateMessageState.ts
class PrivateMessageState (line 3) | class PrivateMessageState extends StateBase {
method constructor (line 4) | constructor() {
method setupPm (line 18) | setupPm() {
method LoadCheck (line 63) | async LoadCheck() {
method GetPosts (line 78) | private async GetPosts() {
method send (line 84) | send(fullText: string) {
method ackRead (line 90) | ackRead() {
method populateMessage (line 94) | populateMessage(data: PrivateMessage) {
FILE: src/PopForums.Mvc/Client/State/TopicState.ts
class TopicState (line 3) | class TopicState extends StateBase {
method constructor (line 4) | constructor() {
method setupTopic (line 36) | setupTopic() {
method loadReply (line 85) | loadReply(topicID:number, replyID:number, setupMorePosts:boolean):void {
method loadComment (line 124) | loadComment(topicID: number, replyID: number): void {
method setAnswer (line 258) | setAnswer(postID: number, topicID: number) {
FILE: src/PopForums.Mvc/Client/State/UserState.ts
class UserState (line 3) | class UserState extends StateBase {
method constructor (line 4) | constructor() {
method initialize (line 27) | async initialize(): Promise<void> {
method LoadNotifications (line 33) | async LoadNotifications(): Promise<void> {
method MarkRead (line 42) | async MarkRead(contextID: number, notificationType: number) : Promise<...
method MarkAllRead (line 46) | async MarkAllRead() : Promise<void> {
method LoadMoreNotifications (line 66) | private async LoadMoreNotifications() {
FILE: src/PopForums.Mvc/Client/StateBase.ts
class StateBase (line 4) | class StateBase {
method constructor (line 5) | constructor() {
method subscribe (line 11) | subscribe(propertyName: string, eventHandler: Function) {
method notify (line 19) | notify(propertyName: string) {
FILE: src/PopForums.Mvc/Client/WatchPropertyAttribute.ts
method set (line 6) | set(this: any, newValue: any) {
method get (line 10) | get() {return currentValue;}
FILE: src/PopForums.Mvc/gulpfile.js
function jsTask (line 37) | function jsTask() {
function cssTask (line 48) | function cssTask() {
FILE: src/PopForums.Mvc/wwwroot/Admin.js
method data (line 5) | data() {
method data (line 21) | data() {
method data (line 49) | data() {
method data (line 83) | data() {
method data (line 155) | data() {
method data (line 219) | data() {
method data (line 275) | data() {
method data (line 322) | data() {
method data (line 340) | data() {
method data (line 368) | data() {
method data (line 446) | data() {
method data (line 492) | data() {
method data (line 533) | data() {
method data (line 596) | data() {
method data (line 635) | data() {
method data (line 696) | data() {
method data (line 755) | data() {
method data (line 813) | data() {
method data (line 882) | data() {
method data (line 907) | data() {
method data (line 932) | data() {
method data (line 957) | data() {
method deleteAll (line 979) | deleteAll() {
method data (line 995) | data() {
FILE: src/PopForums.Sql/CacheHelper.cs
class CacheHelper (line 3) | public class CacheHelper : ICacheHelper
method CacheHelper (line 5) | public CacheHelper(IConfig config, ITenantService tenantService)
method PrefixTenantOnKey (line 20) | private string PrefixTenantOnKey(string key)
method SetCacheObject (line 26) | public void SetCacheObject(string key, object value)
method SetCacheObject (line 33) | public void SetCacheObject(string key, object value, double seconds)
method SetLongTermCacheObject (line 40) | public void SetLongTermCacheObject(string key, object value)
method SetPagedListCacheObject (line 47) | public void SetPagedListCacheObject<T>(string rootKey, int page, List<...
method RemoveCacheObject (line 60) | public void RemoveCacheObject(string key)
method GetCacheObject (line 67) | public T GetCacheObject<T>(string key)
method GetPagedListCacheObject (line 74) | public List<T> GetPagedListCacheObject<T>(string rootKey, int page)
method GetEffectiveCacheKey (line 87) | public string GetEffectiveCacheKey(string key)
FILE: src/PopForums.Sql/Extensions.cs
class Extensions (line 3) | public static class Extensions
method Command (line 5) | public static DbCommand Command(this DbConnection connection, ISqlObje...
method AddParameter (line 11) | public static DbCommand AddParameter(this DbCommand command, ISqlObjec...
method Using (line 18) | public static void Using(this DbConnection connection, Action<DbConnec...
method UsingAsync (line 35) | public static async Task UsingAsync(this DbConnection connection, Func...
method AddPopForumsSql (line 52) | public static void AddPopForumsSql(this IServiceCollection services)
method GetObjectOrDbNull (line 97) | public static object GetObjectOrDbNull(this object value)
method NullIntDbHelper (line 102) | public static int? NullIntDbHelper(this DbDataReader reader, int index)
method NullStringDbHelper (line 108) | public static string NullStringDbHelper(this DbDataReader reader, int ...
method NullGuidDbHelper (line 114) | public static Guid? NullGuidDbHelper(this IDataReader reader, int index)
method NullToEmpty (line 120) | public static string NullToEmpty(this string text)
FILE: src/PopForums.Sql/ISqlObjectFactory.cs
type ISqlObjectFactory (line 3) | public interface ISqlObjectFactory
method GetConnection (line 5) | DbConnection GetConnection();
method GetCommand (line 6) | DbCommand GetCommand();
method GetCommand (line 7) | DbCommand GetCommand(string sql);
method GetCommand (line 8) | DbCommand GetCommand(string sql, DbConnection connection);
method GetParameter (line 9) | DbParameter GetParameter(string parameterName, object value);
FILE: src/PopForums.Sql/JsonElementTypeHandler.cs
class JsonElementTypeHandler (line 3) | public class JsonElementTypeHandler : SqlMapper.TypeHandler<JsonElement>
method SetValue (line 5) | public override void SetValue(IDbDataParameter parameter, JsonElement ...
method Parse (line 12) | public override JsonElement Parse(object value)
FILE: src/PopForums.Sql/PopForums.sql
type dbo (line 3) | CREATE TABLE [dbo].[pf_PopForumsUser](
type IX_PopForumsUser_UserName (line 15) | CREATE UNIQUE NONCLUSTERED INDEX [IX_PopForumsUser_UserName] ON [dbo].[p...
type dbo (line 23) | CREATE TABLE [dbo].[pf_Profile](
FILE: src/PopForums.Sql/PopForums13to14.sql
type dbo (line 3) | CREATE TABLE [dbo].[pf_EmailQueue](
FILE: src/PopForums.Sql/PopForums14to15.sql
type IX_pf_Topic_ForumID (line 1) | CREATE CLUSTERED INDEX [IX_pf_Topic_ForumID] ON [dbo].[pf_Topic]
FILE: src/PopForums.Sql/PopForums16to21.sql
type IX_pf_SecurityLog_TargetUserID_SecurityLogType (line 4) | CREATE NONCLUSTERED INDEX IX_pf_SecurityLog_TargetUserID_SecurityLogType
type dbo (line 39) | CREATE TABLE [dbo].[pf_Notifications]
type IX_pf_Notifications_UserID_TimeStamp (line 52) | CREATE CLUSTERED INDEX [IX_pf_Notifications_UserID_TimeStamp] ON [dbo].[...
type IX_pf_Notifications_Context (line 59) | CREATE INDEX [IX_pf_Notifications_Context] ON [dbo].[pf_Notifications]
type IX_pf_SubscribeTopic_UserID_TopicID (line 88) | CREATE UNIQUE CLUSTERED INDEX [IX_pf_SubscribeTopic_UserID_TopicID] ON [...
type IX_pf_SubscribeTopic_UserID (line 96) | CREATE INDEX [IX_pf_SubscribeTopic_UserID] ON [dbo].[pf_SubscribeTopic]
type dbo (line 106) | CREATE TABLE [dbo].[pf_PostImage]
type IX_pf_PostImage_TenantID (line 117) | CREATE INDEX [IX_pf_PostImage_TenantID] ON [dbo].[pf_PostImage] ([Tenant...
type dbo (line 124) | CREATE TABLE [dbo].[pf_PostImageTemp](
type dbo (line 158) | CREATE TABLE [dbo].[pf_SubNotifyQueue](
type IX_pf_SubNotifyQueue_ID (line 165) | CREATE CLUSTERED INDEX IX_pf_SubNotifyQueue_ID ON pf_SubNotifyQueue (ID)
FILE: src/PopForums.Sql/PopForums21to22.sql
type dbo (line 3) | CREATE TABLE [dbo].[pf_Ignore](
type IX_pf_Ignore_UserID (line 14) | CREATE CLUSTERED INDEX IX_pf_Ignore_UserID ON pf_Ignore (UserID, IgnoreU...
FILE: src/PopForums.Sql/Repositories/AwardCalculationQueueRepository.cs
class AwardCalculationQueueRepository (line 3) | public class AwardCalculationQueueRepository : IAwardCalculationQueueRep...
method AwardCalculationQueueRepository (line 5) | public AwardCalculationQueueRepository(ISqlObjectFactory sqlObjectFact...
method Enqueue (line 12) | public async Task Enqueue(AwardCalculationPayload payload)
method Dequeue (line 19) | public async Task<KeyValuePair<string, int>> Dequeue()
FILE: src/PopForums.Sql/Repositories/AwardConditionRepository.cs
class AwardConditionRepository (line 3) | public class AwardConditionRepository : IAwardConditionRepository
method AwardConditionRepository (line 5) | public AwardConditionRepository(ISqlObjectFactory sqlObjectFactory)
method GetConditions (line 12) | public async Task<List<AwardCondition>> GetConditions(string awardDefi...
method DeleteConditions (line 21) | public async Task DeleteConditions(string awardDefinitionID)
method DeleteCondition (line 27) | public async Task DeleteCondition(string awardDefinitionID, string eve...
method DeleteConditionsByEventDefinitionID (line 33) | public async Task DeleteConditionsByEventDefinitionID(string eventDefi...
method SaveConditions (line 39) | public async Task SaveConditions(List<AwardCondition> conditions)
FILE: src/PopForums.Sql/Repositories/AwardDefinitionRepository.cs
class AwardDefinitionRepository (line 3) | public class AwardDefinitionRepository : IAwardDefinitionRepository
method AwardDefinitionRepository (line 5) | public AwardDefinitionRepository(ISqlObjectFactory sqlObjectFactory)
method Get (line 12) | public async Task<AwardDefinition> Get(string awardDefinitionID)
method GetAll (line 20) | public async Task<List<AwardDefinition>> GetAll()
method GetByEventDefinitionID (line 29) | public async Task<List<AwardDefinition>> GetByEventDefinitionID(string...
method Create (line 38) | public async Task Create(string awardDefinitionID, string title, strin...
method Delete (line 44) | public async Task Delete(string awardDefinitionID)
FILE: src/PopForums.Sql/Repositories/BanRepository.cs
class BanRepository (line 3) | public class BanRepository : IBanRepository
method BanRepository (line 5) | public BanRepository(ISqlObjectFactory sqlObjectFactory)
method BanIP (line 12) | public async Task BanIP(string ip)
method RemoveIPBan (line 18) | public async Task RemoveIPBan(string ip)
method GetIPBans (line 24) | public async Task<List<string>> GetIPBans()
method IPIsBanned (line 33) | public async Task<bool> IPIsBanned(string ip)
method BanEmail (line 42) | public async Task BanEmail(string email)
method RemoveEmailBan (line 48) | public async Task RemoveEmailBan(string email)
method GetEmailBans (line 54) | public async Task<List<string>> GetEmailBans()
method EmailIsBanned (line 63) | public async Task<bool> EmailIsBanned(string email)
FILE: src/PopForums.Sql/Repositories/CategoryRepository.cs
class CategoryRepository (line 3) | public class CategoryRepository : ICategoryRepository
method CategoryRepository (line 5) | public CategoryRepository(ISqlObjectFactory sqlObjectFactory)
method Get (line 12) | public async Task<Category> Get(int categoryID)
method GetAll (line 20) | public async Task<List<Category>> GetAll()
method Create (line 29) | public async Task<Category> Create(string newTitle, int sortOrder)
method Delete (line 38) | public async Task Delete(int categoryID)
method Update (line 47) | public async Task Update(Category category)
FILE: src/PopForums.Sql/Repositories/EmailQueueRepository.cs
class EmailQueueRepository (line 3) | public class EmailQueueRepository : IEmailQueueRepository
method EmailQueueRepository (line 7) | public EmailQueueRepository(ISqlObjectFactory sqlObjectFactory)
method Enqueue (line 12) | public async Task Enqueue(EmailQueuePayload payload)
method Dequeue (line 19) | public async Task<EmailQueuePayload> Dequeue()
FILE: src/PopForums.Sql/Repositories/ErrorLogRepository.cs
class ErrorLogRepository (line 3) | public class ErrorLogRepository : IErrorLogRepository
method ErrorLogRepository (line 5) | public ErrorLogRepository(ISqlObjectFactory sqlObjectFactory)
method Create (line 12) | public async Task<ErrorLogEntry> Create(DateTime timeStamp, string mes...
method GetErrorCount (line 37) | public async Task<int> GetErrorCount()
method GetErrors (line 45) | public async Task<List<ErrorLogEntry>> GetErrors(int startRow, int pag...
method DeleteError (line 71) | public async Task DeleteError(int errorID)
method DeleteAllErrors (line 77) | public async Task DeleteAllErrors()
FILE: src/PopForums.Sql/Repositories/EventDefinitionRepository.cs
class EventDefinitionRepository (line 3) | public class EventDefinitionRepository : IEventDefinitionRepository
method EventDefinitionRepository (line 5) | public EventDefinitionRepository(ISqlObjectFactory sqlObjectFactory)
method Get (line 12) | public async Task<EventDefinition> Get(string eventDefinitionID)
method GetAll (line 20) | public async Task<List<EventDefinition>> GetAll()
method Create (line 28) | public async Task Create(EventDefinition eventDefinition)
method Delete (line 34) | public void Delete(string eventDefinitionID)
FILE: src/PopForums.Sql/Repositories/ExternalUserAssociationRepository.cs
class ExternalUserAssociationRepository (line 3) | public class ExternalUserAssociationRepository : IExternalUserAssociatio...
method ExternalUserAssociationRepository (line 5) | public ExternalUserAssociationRepository(ISqlObjectFactory sqlObjectFa...
method Get (line 12) | public async Task<ExternalUserAssociation> Get(string issuer, string p...
method Get (line 20) | public async Task<ExternalUserAssociation> Get(int externalUserAssocia...
method GetByUser (line 28) | public async Task<List<ExternalUserAssociation>> GetByUser(int userID)
method Save (line 36) | public async Task Save(int userID, string issuer, string providerKey, ...
method Delete (line 42) | public async Task Delete(int externalUserAssociationID)
FILE: src/PopForums.Sql/Repositories/FavoriteTopicsRepository.cs
class FavoriteTopicsRepository (line 3) | public class FavoriteTopicsRepository : IFavoriteTopicsRepository
method FavoriteTopicsRepository (line 5) | public FavoriteTopicsRepository(ISqlObjectFactory sqlObjectFactory)
method GetFavoriteTopics (line 12) | public async Task<List<Topic>> GetFavoriteTopics(int userID, int start...
method GetFavoriteTopicCount (line 42) | public async Task<int> GetFavoriteTopicCount(int userID)
method IsTopicFavorite (line 50) | public async Task<bool> IsTopicFavorite(int userID, int topicID)
method AddFavoriteTopic (line 58) | public async Task AddFavoriteTopic(int userID, int topicID)
method RemoveFavoriteTopic (line 64) | public async Task RemoveFavoriteTopic(int userID, int topicID)
FILE: src/PopForums.Sql/Repositories/FeedRepository.cs
class FeedRepository (line 3) | public class FeedRepository : IFeedRepository
method FeedRepository (line 5) | public FeedRepository(ISqlObjectFactory sqlObjectFactory)
method GetFeed (line 12) | public async Task<List<FeedEvent>> GetFeed(int userID, int itemCount)
method GetFeed (line 20) | public async Task<List<FeedEvent>> GetFeed(int itemCount)
method PublishEvent (line 28) | public async Task PublishEvent(int userID, string message, int points,...
method GetOldestTime (line 34) | public async Task<DateTime> GetOldestTime(int userID, int takeCount)
method DeleteOlderThan (line 43) | public async Task DeleteOlderThan(int userID, DateTime timeCutOff)
FILE: src/PopForums.Sql/Repositories/ForumRepository.cs
class ForumRepository (line 3) | public class ForumRepository : IForumRepository
method ForumRepository (line 5) | public ForumRepository(ICacheHelper cacheHelper, ISqlObjectFactory sql...
class CacheKeys (line 15) | public class CacheKeys
method Get (line 25) | public async Task<Forum> Get(int forumID)
method Get (line 33) | public async Task<Forum> Get(string urlName)
method Create (line 41) | public async Task<Forum> Create(int? categoryID, string title, string ...
method GetForumsInCategory (line 73) | public async Task<List<Forum>> GetForumsInCategory(int? categoryID)
method GetUrlNamesThatStartWith (line 85) | public async Task<List<string>> GetUrlNamesThatStartWith(string urlName)
method Update (line 93) | public async Task Update(int forumID, int? categoryID, string title, s...
method UpdateSortOrder (line 103) | public async Task UpdateSortOrder(int forumID, int newSortOrder)
method UpdateCategoryAssociation (line 109) | public async Task UpdateCategoryAssociation(int forumID, int? categoryID)
method UpdateLastTimeAndUser (line 115) | public async Task UpdateLastTimeAndUser(int forumID, DateTime lastTime...
method UpdateTopicAndPostCounts (line 121) | public async Task UpdateTopicAndPostCounts(int forumID, int topicCount...
method IncrementPostCount (line 127) | public async Task IncrementPostCount(int forumID)
method IncrementPostAndTopicCount (line 133) | public async Task IncrementPostAndTopicCount(int forumID)
method GetAll (line 139) | public async Task<IEnumerable<Forum>> GetAll()
method GetAllVisible (line 147) | public async Task<IEnumerable<Forum>> GetAllVisible()
method GetForumPostRoles (line 155) | public async Task<List<string>> GetForumPostRoles(int forumID)
method GetForumViewRoles (line 162) | public async Task<List<string>> GetForumViewRoles(int forumID)
method GetForumPostRestrictionRoleGraph (line 169) | public async Task<Dictionary<int, List<string>>> GetForumPostRestricti...
method GetForumViewRestrictionRoleGraph (line 179) | public async Task<Dictionary<int, List<string>>> GetForumViewRestricti...
method GetForumRestrictionRoleGraph (line 189) | private async Task<Dictionary<int, List<string>>> GetForumRestrictionR...
class RoleGraph (line 206) | private class RoleGraph
method ModifyForumRole (line 212) | private async Task ModifyForumRole(int forumID, string role, string sql)
method ModifyForumRole (line 218) | private async Task ModifyForumRole(int forumID, string sql)
method AddPostRole (line 224) | public async Task AddPostRole(int forumID, string role)
method RemovePostRole (line 231) | public async Task RemovePostRole(int forumID, string role)
method AddViewRole (line 237) | public async Task AddViewRole(int forumID, string role)
method RemoveViewRole (line 244) | public async Task RemoveViewRole(int forumID, string role)
method RemoveAllPostRoles (line 250) | public async Task RemoveAllPostRoles(int forumID)
method RemoveAllViewRoles (line 256) | public async Task RemoveAllViewRoles(int forumID)
method GetAllForumUrlNames (line 262) | public async Task<IEnumerable<string>> GetAllForumUrlNames()
method GetAllForumTitles (line 274) | public Dictionary<int, string> GetAllForumTitles()
method GetAggregateTopicCount (line 286) | public async Task<int> GetAggregateTopicCount()
method GetAggregatePostCount (line 298) | public async Task<int> GetAggregatePostCount()
FILE: src/PopForums.Sql/Repositories/IgnoreRepository.cs
class IgnoreRepository (line 3) | public class IgnoreRepository(ISqlObjectFactory sqlObjectFactory) : IIgn...
method AddIgnore (line 5) | public async Task AddIgnore(int userID, int ignoreUserID)
method DeleteIgnore (line 15) | public async Task DeleteIgnore(int userID, int ignoreUserID)
method GetIgnoreList (line 25) | public async Task<IList<IgnoreWithName>> GetIgnoreList(int userID)
method GetIgnoredUserIdsInList (line 33) | public async Task<List<int>> GetIgnoredUserIdsInList(int userID, List<...
FILE: src/PopForums.Sql/Repositories/LastReadRepository.cs
class LastReadRepository (line 3) | public class LastReadRepository : ILastReadRepository
method LastReadRepository (line 5) | public LastReadRepository(ISqlObjectFactory sqlObjectFactory)
method SetForumRead (line 12) | public async Task SetForumRead(int userID, int forumID, DateTime readT...
method DeleteTopicReadsInForum (line 18) | public async Task DeleteTopicReadsInForum(int userID, int forumID)
method SetAllForumsRead (line 24) | public async Task SetAllForumsRead(int userID, DateTime readTime)
method DeleteAllTopicReads (line 30) | public async Task DeleteAllTopicReads(int userID)
method SetTopicRead (line 36) | public async Task SetTopicRead(int userID, int topicID, DateTime readT...
method GetLastReadTimesForForums (line 44) | public async Task<Dictionary<int, DateTime>> GetLastReadTimesForForums...
method GetLastReadTimesForForum (line 52) | public async Task<DateTime?> GetLastReadTimesForForum(int userID, int ...
method GetLastReadTimesForTopics (line 60) | public async Task<Dictionary<int, DateTime>> GetLastReadTimesForTopics...
method GetLastReadTimeForTopic (line 88) | public async Task<DateTime?> GetLastReadTimeForTopic(int userID, int t...
FILE: src/PopForums.Sql/Repositories/ModerationLogRepository.cs
class ModerationLogRepository (line 3) | public class ModerationLogRepository : IModerationLogRepository
method ModerationLogRepository (line 5) | public ModerationLogRepository(ISqlObjectFactory sqlObjectFactory)
method Log (line 12) | public async Task Log(DateTime timeStamp, int userID, string userName,...
method GetLog (line 18) | public async Task<List<ModerationLogEntry>> GetLog(DateTime start, Dat...
method GetLog (line 26) | public async Task<List<ModerationLogEntry>> GetLog(int topicID, bool e...
method GetLog (line 38) | public async Task<List<ModerationLogEntry>> GetLog(int postID)
FILE: src/PopForums.Sql/Repositories/NotificationRepository.cs
class NotificationRepository (line 5) | public class NotificationRepository : INotificationRepository
method NotificationRepository (line 10) | public NotificationRepository(ISqlObjectFactory sqlObjectFactory, ICac...
method GetCacheKey (line 17) | private string GetCacheKey(int userID)
method RemoveCache (line 22) | private void RemoveCache(int userID)
method UpdateNotification (line 28) | public async Task<int> UpdateNotification(Notification notification)
method CreateNotification (line 37) | public async Task CreateNotification(Notification notification)
method MarkNotificationRead (line 44) | public async Task MarkNotificationRead(int userID, NotificationType no...
method GetNotifications (line 51) | public async Task<List<Notification>> GetNotifications(int userID, Dat...
method GetPageCount (line 60) | public async Task<int> GetPageCount(int userID, int pageSize)
method GetUnreadNotificationCount (line 72) | public async Task<int> GetUnreadNotificationCount(int userID)
method MarkAllRead (line 85) | public async Task MarkAllRead(int userID)
method DeleteOlderThan (line 92) | public async Task DeleteOlderThan(int userID, DateTime timeCutOff)
FILE: src/PopForums.Sql/Repositories/PointLedgerRepository.cs
class PointLedgerRepository (line 3) | public class PointLedgerRepository : IPointLedgerRepository
method PointLedgerRepository (line 5) | public PointLedgerRepository(ISqlObjectFactory sqlObjectFactory)
method RecordEntry (line 12) | public virtual async Task RecordEntry(PointLedgerEntry entry)
method GetPointTotal (line 18) | public async Task<int> GetPointTotal(int userID)
method GetEntryCount (line 26) | public async Task<int> GetEntryCount(int userID, string eventDefinitio...
FILE: src/PopForums.Sql/Repositories/PostImageRepository.cs
class PostImageRepository (line 3) | public class PostImageRepository : IPostImageRepository
method PostImageRepository (line 8) | public PostImageRepository(ISqlObjectFactory sqlObjectFactory, ITenant...
method Persist (line 14) | public async Task<PostImagePersistPayload> Persist(byte[] bytes, strin...
method DeletePostImageData (line 33) | public async Task DeletePostImageData(string id, string tenantID)
method GetWithoutData (line 39) | public async Task<PostImage> GetWithoutData(string id)
method Get (line 47) | [Obsolete("Use the combination of GetWithoutData(int) and GetImageStre...
method GetImageStream (line 56) | public async Task<IStreamResponse> GetImageStream(string id)
FILE: src/PopForums.Sql/Repositories/PostImageTempRepository.cs
class PostImageTempRepository (line 3) | public class PostImageTempRepository : IPostImageTempRepository
method PostImageTempRepository (line 7) | public PostImageTempRepository(ISqlObjectFactory sqlObjectFactory)
method Save (line 12) | public async Task Save(Guid postImageTempID, DateTime timeStamp, strin...
method Delete (line 18) | public async Task Delete(Guid id)
method GetOld (line 24) | public async Task<List<Guid>> GetOld(DateTime olderThan)
FILE: src/PopForums.Sql/Repositories/PostRepository.cs
class PostRepository (line 3) | public class PostRepository : IPostRepository
method PostRepository (line 5) | public PostRepository(ISqlObjectFactory sqlObjectFactory, ICacheHelper...
class CacheKeys (line 11) | public class CacheKeys
method Create (line 20) | public virtual async Task<int> Create(int topicID, int parentPostID, s...
method Update (line 30) | public async Task<bool> Update(Post post)
method Get (line 40) | public async Task<List<Post>> Get(int topicID, bool includeDeleted, in...
method Get (line 81) | public async Task<List<Post>> Get(int topicID, bool includeDeleted)
method GetLastInTopic (line 90) | public async Task<Post> GetLastInTopic(int topicID)
method GetReplyCount (line 98) | public async Task<int> GetReplyCount(int topicID, bool includeDeleted)
method Get (line 109) | public async Task<Post> Get(int postID)
method GetPostIDsWithTimes (line 117) | public async Task<Dictionary<int, DateTime>> GetPostIDsWithTimes(int t...
method GetPostCount (line 130) | public async Task<int> GetPostCount(int userID)
method GetIPHistory (line 138) | public async Task<List<IPHistoryEvent>> GetIPHistory(string ip, DateTi...
method GetLastPostID (line 149) | public async Task<int> GetLastPostID(int topicID)
method GetVoteCount (line 158) | public async Task<int> GetVoteCount(int postID)
method CalculateVoteCount (line 167) | public async Task<int> CalculateVoteCount(int postID)
method SetVoteCount (line 176) | public async Task SetVoteCount(int postID, int votes)
method VotePost (line 183) | public async Task VotePost(int postID, int userID)
method GetVotes (line 190) | public async Task<Dictionary<int, string>> GetVotes(int postID)
method GetVotedPostIDs (line 200) | public async Task<List<int>> GetVotedPostIDs(int userID, List<int> pos...
method DeleteVote (line 215) | public async Task DeleteVote(int postID, int userID)
FILE: src/PopForums.Sql/Repositories/PrivateMessageRepository.cs
class PrivateMessageRepository (line 3) | public class PrivateMessageRepository : IPrivateMessageRepository
method PrivateMessageRepository (line 5) | public PrivateMessageRepository(ICacheHelper cacheHelper, ISqlObjectFa...
class CacheKeys (line 15) | public class CacheKeys
method PMCount (line 17) | public static string PMCount(int userID)
method Get (line 23) | public async Task<PrivateMessage> Get(int pmID, int userID)
method GetExistingFromIDs (line 31) | public async Task<int> GetExistingFromIDs(List<int> ids)
method GetPosts (line 46) | public async Task<List<PrivateMessagePost>> GetPosts(int pmID, DateTim...
method GetPosts (line 55) | public async Task<List<PrivateMessagePost>> GetPosts(int pmID, DateTim...
method CreatePrivateMessage (line 65) | public virtual async Task<int> CreatePrivateMessage(PrivateMessage pm)
method AddUsers (line 74) | public async Task AddUsers(int pmID, List<int> userIDs, DateTime viewD...
method AddPost (line 84) | public virtual async Task<int> AddPost(PrivateMessagePost post)
method GetUsers (line 96) | public async Task<List<PrivateMessageUser>> GetUsers(int pmID)
method SetLastViewTime (line 104) | public async Task SetLastViewTime(int pmID, int userID, DateTime viewD...
method SetArchive (line 111) | public async Task SetArchive(int pmID, int userID, bool isArchived)
method GetPrivateMessages (line 118) | public async Task<List<PrivateMessage>> GetPrivateMessages(int userID,...
method GetBoxCount (line 146) | public async Task<int> GetBoxCount(int userID, PrivateMessageBoxType b...
method GetUnreadCount (line 156) | public async Task<int> GetUnreadCount(int userID)
method UpdateLastPostTime (line 168) | public async Task UpdateLastPostTime(int pmID, DateTime lastPostTime)
method GetFirstUnreadPostID (line 174) | public async Task<int?> GetFirstUnreadPostID(int pmID, DateTime lastRe...
FILE: src/PopForums.Sql/Repositories/ProfileRepository.cs
class ProfileRepository (line 3) | public class ProfileRepository : IProfileRepository
method ProfileRepository (line 5) | public ProfileRepository(ICacheHelper cacheHelper, ISqlObjectFactory s...
class CacheKeys (line 14) | public class CacheKeys
method UserProfile (line 16) | public static string UserProfile(int userID)
method GetProfile (line 22) | public async Task<Profile> GetProfile(int userID)
method Create (line 36) | public async Task Create(Profile profile)
method Update (line 42) | public async Task<bool> Update(Profile profile)
method GetLastPostID (line 51) | public async Task<int?> GetLastPostID(int userID)
method SetLastPostID (line 59) | public async Task<bool> SetLastPostID(int userID, int postID)
method GetSignatures (line 67) | public async Task<Dictionary<int, string>> GetSignatures(List<int> use...
method GetAvatars (line 81) | public async Task<Dictionary<int, int>> GetAvatars(List<int> userIDs)
method SetCurrentImageIDToNull (line 95) | public async Task SetCurrentImageIDToNull(int userID)
method UpdatePoints (line 102) | public async Task UpdatePoints(int userID, int points)
FILE: src/PopForums.Sql/Repositories/QueuedEmailMessageRepository.cs
class QueuedEmailMessageRepository (line 3) | public class QueuedEmailMessageRepository : IQueuedEmailMessageRepository
method QueuedEmailMessageRepository (line 5) | public QueuedEmailMessageRepository(ISqlObjectFactory sqlObjectFactory)
method CreateMessage (line 12) | public async Task<int> CreateMessage(QueuedEmailMessage message)
method DeleteMessage (line 22) | public async Task DeleteMessage(int messageID)
method GetMessage (line 28) | public async Task<QueuedEmailMessage> GetMessage(int messageID)
FILE: src/PopForums.Sql/Repositories/RoleRepository.cs
class RoleRepository (line 3) | public class RoleRepository : IRoleRepository
method RoleRepository (line 5) | public RoleRepository(ICacheHelper cacheHelper, ISqlObjectFactory sqlO...
class CacheKeys (line 14) | public class CacheKeys
method UserRole (line 17) | public static string UserRole(int userID)
method CreateRole (line 23) | public async Task CreateRole(string role)
method DeleteRole (line 35) | public async Task<bool> DeleteRole(string role)
method GetAllRoles (line 44) | public async Task<List<string>> GetAllRoles()
method GetUserRoles (line 56) | public async Task<List<string>> GetUserRoles(int userID)
method AddUserToRole (line 69) | private async Task AddUserToRole(int userID, string role)
method RemoveUserFromRole (line 77) | private async Task RemoveUserFromRole(int userID, string role)
method ReplaceUserRoles (line 84) | public async Task ReplaceUserRoles(int userID, string[] roles)
FILE: src/PopForums.Sql/Repositories/SearchIndexQueueRepository.cs
class SearchIndexQueueRepository (line 3) | public class SearchIndexQueueRepository : ISearchIndexQueueRepository
method SearchIndexQueueRepository (line 7) | public SearchIndexQueueRepository(ISqlObjectFactory sqlObjectFactory)
method Enqueue (line 12) | public async Task Enqueue(SearchIndexPayload payload)
method Dequeue (line 19) | public async Task<SearchIndexPayload> Dequeue()
FILE: src/PopForums.Sql/Repositories/SearchRepository.cs
class SearchRepository (line 3) | public class SearchRepository : ISearchRepository
method SearchRepository (line 5) | public SearchRepository(ISqlObjectFactory sqlObjectFactory)
method GetJunkWords (line 12) | public virtual async Task<List<string>> GetJunkWords()
method CreateJunkWord (line 20) | public virtual async Task CreateJunkWord(string word)
method DeleteJunkWord (line 31) | public virtual async Task DeleteJunkWord(string word)
method DeleteAllIndexedWordsForTopic (line 37) | public virtual async Task DeleteAllIndexedWordsForTopic(int topicID)
method SaveSearchWord (line 48) | public virtual async Task SaveSearchWord(int topicID, string word, int...
method SearchTopics (line 54) | public virtual async Task<Tuple<Response<List<Topic>>, int>> SearchTop...
FILE: src/PopForums.Sql/Repositories/SecurityLogRepository.cs
class SecurityLogRepository (line 3) | public class SecurityLogRepository : ISecurityLogRepository
method SecurityLogRepository (line 5) | public SecurityLogRepository(ISqlObjectFactory sqlObjectFactory)
method Create (line 12) | public async Task Create(SecurityLogEntry logEntry)
method GetByUserID (line 18) | public async Task<List<SecurityLogEntry>> GetByUserID(int userID, Date...
method GetIPHistory (line 26) | public async Task<List<IPHistoryEvent>> GetIPHistory(string ip, DateTi...
FILE: src/PopForums.Sql/Repositories/ServiceHeartbeatRepository.cs
class ServiceHeartbeatRepository (line 3) | public class ServiceHeartbeatRepository : IServiceHeartbeatRepository
method ServiceHeartbeatRepository (line 5) | public ServiceHeartbeatRepository(ISqlObjectFactory sqlObjectFactory)
method RecordHeartbeat (line 12) | public async Task RecordHeartbeat(string serviceName, string machineNa...
method GetAll (line 21) | public async Task<List<ServiceHeartbeat>> GetAll()
method ClearAll (line 29) | public async Task ClearAll()
FILE: src/PopForums.Sql/Repositories/SettingsRepository.cs
class SettingsRepository (line 3) | public class SettingsRepository : ISettingsRepository
method SettingsRepository (line 5) | public SettingsRepository(ISqlObjectFactory sqlObjectFactory, ICacheHe...
method Get (line 23) | public Dictionary<string, string> Get()
method Save (line 35) | public void Save(Dictionary<string, object> dictionary)
FILE: src/PopForums.Sql/Repositories/SetupRepository.cs
class SetupRepository (line 3) | public class SetupRepository : ISetupRepository
method SetupRepository (line 5) | public SetupRepository(ISqlObjectFactory sqlObjectFactory)
method IsConnectionPossible (line 12) | public bool IsConnectionPossible()
method IsDatabaseSetup (line 27) | public virtual bool IsDatabaseSetup()
method SetupDatabase (line 43) | public void SetupDatabase()
FILE: src/PopForums.Sql/Repositories/SubscribeNotificationRepository.cs
class SubscribeNotificationRepository (line 3) | public class SubscribeNotificationRepository : ISubscribeNotificationRep...
method SubscribeNotificationRepository (line 7) | public SubscribeNotificationRepository(ISqlObjectFactory sqlObjectFact...
method Enqueue (line 12) | public async Task Enqueue(SubscribeNotificationPayload payload)
method Dequeue (line 19) | public async Task<SubscribeNotificationPayload> Dequeue()
FILE: src/PopForums.Sql/Repositories/SubscribedTopicsRepository.cs
class SubscribedTopicsRepository (line 3) | public class SubscribedTopicsRepository : ISubscribedTopicsRepository
method SubscribedTopicsRepository (line 5) | public SubscribedTopicsRepository(ISqlObjectFactory sqlObjectFactory)
method GetSubscribedTopics (line 12) | public async Task<List<Topic>> GetSubscribedTopics(int userID, int sta...
method GetSubscribedTopicCount (line 42) | public async Task<int> GetSubscribedTopicCount(int userID)
method GetSubscribedUserIDs (line 50) | public async Task<List<int>> GetSubscribedUserIDs(int topicID)
method IsTopicSubscribed (line 58) | public async Task<bool> IsTopicSubscribed(int userID, int topicID)
method AddSubscribedTopic (line 66) | public async Task AddSubscribedTopic(int userID, int topicID)
method RemoveSubscribedTopic (line 72) | public async Task RemoveSubscribedTopic(int userID, int topicID)
FILE: src/PopForums.Sql/Repositories/TopicRepository.cs
class TopicRepository (line 3) | public class TopicRepository : ITopicRepository
method TopicRepository (line 5) | public TopicRepository(ISqlObjectFactory sqlObjectFactory, ICacheHelpe...
method GetLastUpdatedTopic (line 15) | public async Task<Topic> GetLastUpdatedTopic(int forumID)
method GetTopicCount (line 25) | public async Task<int> GetTopicCount(int forumID, bool includeDelete)
method GetTopicCountByUser (line 36) | public async Task<int> GetTopicCountByUser(int userID, bool includeDel...
method GetTopicCount (line 48) | public async Task<int> GetTopicCount(bool includeDeleted, List<int> ex...
method GenerateExcludedForumSql (line 62) | private static string GenerateExcludedForumSql(string sql, List<int> e...
method GetPostCount (line 78) | public async Task<int> GetPostCount(int forumID, bool includeDelete)
method Get (line 89) | public async Task<Topic> Get(int topicID)
method Get (line 97) | public async Task<Topic> Get(string urlName)
method Get (line 105) | public async Task<List<Topic>> Get(int forumID, bool includeDeleted, i...
method GetTopicsByUser (line 135) | public async Task<List<Topic>> GetTopicsByUser(int userID, bool includ...
method Get (line 172) | public async Task<List<Topic>> Get(bool includeDeleted, List<int> excl...
method Get (line 202) | public async Task<List<Topic>> Get(IEnumerable<int> topicIDs)
method Get (line 234) | public async Task<List<Topic>> Get(int forumID, bool includeDeleted, L...
method GetUrlNamesThatStartWith (line 248) | public async Task<List<string>> GetUrlNamesThatStartWith(string urlName)
method Create (line 256) | public virtual async Task<int> Create(int forumID, string title, int r...
method IncrementReplyCount (line 264) | public async Task IncrementReplyCount(int topicID)
method IncrementViewCount (line 270) | public async Task IncrementViewCount(int topicID)
method UpdateLastTimeAndUser (line 276) | public async Task UpdateLastTimeAndUser(int topicID, int userID, strin...
method CloseTopic (line 282) | public async Task CloseTopic(int topicID)
method OpenTopic (line 288) | public async Task OpenTopic(int topicID)
method PinTopic (line 294) | public async Task PinTopic(int topicID)
method UnpinTopic (line 300) | public async Task UnpinTopic(int topicID)
method DeleteTopic (line 306) | public async Task DeleteTopic(int topicID)
method UndeleteTopic (line 314) | public async Task UndeleteTopic(int topicID)
method HardDeleteTopic (line 320) | public async Task HardDeleteTopic(int topicID)
method UpdateTitleAndForum (line 328) | public async Task UpdateTitleAndForum(int topicID, int forumID, string...
method UpdateReplyCount (line 334) | public async Task UpdateReplyCount(int topicID, int replyCount)
method GetLastPostTime (line 340) | public async Task<DateTime?> GetLastPostTime(int topicID)
method UpdateAnswerPostID (line 348) | public async Task UpdateAnswerPostID(int topicID, int? postID)
method CloseTopicsOlderThan (line 354) | public async Task<IEnumerable<int>> CloseTopicsOlderThan(DateTime cuto...
method GetUrlNames (line 367) | public async Task<List<Tuple<string, DateTime>>> GetUrlNames(bool incl...
FILE: src/PopForums.Sql/Repositories/TopicViewLogRepository.cs
class TopicViewLogRepository (line 3) | public class TopicViewLogRepository : ITopicViewLogRepository
method TopicViewLogRepository (line 7) | public TopicViewLogRepository(ISqlObjectFactory sqlObjectFactory)
method Log (line 12) | public async Task Log(int? userID, int topicID, DateTime timeStamp)
FILE: src/PopForums.Sql/Repositories/UserAvatarRepository.cs
class UserAvatarRepository (line 3) | public class UserAvatarRepository : IUserAvatarRepository
method UserAvatarRepository (line 5) | public UserAvatarRepository(ISqlObjectFactory sqlObjectFactory)
method GetImageData (line 12) | [Obsolete("Use GetImageStream(int) instead.")]
method GetImageStream (line 21) | public async Task<IStreamResponse> GetImageStream(int userAvatarID)
method GetUserAvatarIDs (line 37) | public async Task<List<int>> GetUserAvatarIDs(int userID)
method SaveNewAvatar (line 46) | public async Task<int> SaveNewAvatar(int userID, byte[] imageData, Dat...
method DeleteAvatarsByUserID (line 54) | public async Task DeleteAvatarsByUserID(int userID)
method GetLastModificationDate (line 60) | public async Task<DateTime?> GetLastModificationDate(int userAvatarID)
FILE: src/PopForums.Sql/Repositories/UserAwardRepository.cs
class UserAwardRepository (line 3) | public class UserAwardRepository : IUserAwardRepository
method UserAwardRepository (line 5) | public UserAwardRepository(ISqlObjectFactory sqlObjectFactory)
method IssueAward (line 12) | public virtual async Task IssueAward(int userID, string awardDefinitio...
method IsAwarded (line 22) | public async Task<bool> IsAwarded(int userID, string awardDefinitionID)
method GetAwards (line 30) | public async Task<List<UserAward>> GetAwards(int userID)
FILE: src/PopForums.Sql/Repositories/UserImageRepository.cs
class UserImageRepository (line 3) | public class UserImageRepository : IUserImageRepository
method UserImageRepository (line 5) | public UserImageRepository(ISqlObjectFactory sqlObjectFactory)
method GetImageData (line 12) | [Obsolete("Use GetImageStream(int) instead.")]
method GetImageStream (line 21) | public async Task<IStreamResponse> GetImageStream(int userImageID)
method GetUserImages (line 37) | public async Task<List<UserImage>> GetUserImages(int userID)
method SaveNewImage (line 45) | public async Task<int> SaveNewImage(int userID, int sortOrder, bool is...
method DeleteImagesByUserID (line 53) | public async Task DeleteImagesByUserID(int userID)
method GetLastModificationDate (line 59) | public async Task<DateTime?> GetLastModificationDate(int userImageID)
method GetUnapprovedUserImages (line 67) | public async Task<List<UserImage>> GetUnapprovedUserImages()
method IsUserImageApproved (line 75) | public async Task<bool?> IsUserImageApproved(int userImageID)
method ApproveUserImage (line 83) | public async Task ApproveUserImage(int userImageID)
method DeleteUserImage (line 89) | public async Task DeleteUserImage(int userImageID)
method Get (line 95) | public async Task<UserImage> Get(int userImageID)
FILE: src/PopForums.Sql/Repositories/UserRepository.cs
class UserRepository (line 3) | public class UserRepository : IUserRepository
method UserRepository (line 5) | public UserRepository(ICacheHelper cacheHelper, ISqlObjectFactory sqlO...
class CacheKeys (line 14) | public class CacheKeys
method CacheUser (line 23) | private void CacheUser(User user)
method RemoveCacheUser (line 30) | private void RemoveCacheUser(string name)
method GetCachedUserByName (line 36) | private User GetCachedUserByName(string name)
method SetHashedPassword (line 42) | public async Task SetHashedPassword(User user, string hashedPassword, ...
method GetHashedPasswordByEmail (line 48) | public async Task<Tuple<string, Guid?>> GetHashedPasswordByEmail(strin...
method GetUsersFromIDs (line 64) | public async Task<List<User>> GetUsersFromIDs(IList<int> ids)
method GetTotalUsers (line 78) | public async Task<int> GetTotalUsers()
method GetUser (line 90) | private async Task<User> GetUser(string sql, object parameters)
method GetUser (line 98) | public async Task<User> GetUser(int userID)
method GetUserByName (line 103) | public async Task<User> GetUserByName(string name)
method GetUserByEmail (line 115) | public async Task<User> GetUserByEmail(string email)
method GetUserByAuthorizationKey (line 120) | public async Task<User> GetUserByAuthorizationKey(Guid key)
method CreateUser (line 125) | public virtual async Task<User> CreateUser(string name, string email, ...
method UpdateLastActivityDate (line 135) | public async Task UpdateLastActivityDate(User user, DateTime newDate)
method UpdateLastLoginDate (line 141) | public async Task UpdateLastLoginDate(User user, DateTime newDate)
method UpdateRefreshToken (line 147) | public async Task UpdateRefreshToken(User user, string refreshToken)
method GetRefreshToken (line 153) | public async Task<string> GetRefreshToken(User user)
method ChangeName (line 161) | public async Task ChangeName(User user, string newName)
method ChangeEmail (line 169) | public async Task ChangeEmail(User user, string newEmail)
method UpdateIsApproved (line 176) | public async Task UpdateIsApproved(User user, bool isApproved)
method UpdateAuthorizationKey (line 183) | public async Task UpdateAuthorizationKey(User user, Guid key)
method UpdateTokenExpiration (line 190) | public async Task UpdateTokenExpiration(User user, DateTime? tokenExpi...
method SearchByEmail (line 197) | public async Task<List<User>> SearchByEmail(string email)
method SearchByName (line 203) | public async Task<List<User>> SearchByName(string name)
method SearchByRole (line 209) | public async Task<List<User>> SearchByRole(string role)
method GetUsersOnline (line 215) | public async Task<List<User>> GetUsersOnline()
method GetSubscribedUsers (line 228) | public async Task<List<User>> GetSubscribedUsers()
method GetUsersByPointTotals (line 236) | public Dictionary<int, (User, int)> GetUsersByPointTotals(int top)
method DeleteUser (line 255) | public async Task DeleteUser(User user)
method GetList (line 262) | private async Task<List<User>> GetList(string sql, object parameters)
method GetRecentUsers (line 272) | public async Task<List<UserResult>> GetRecentUsers()
method GetUserNamesThatStartWith (line 282) | public async Task<IEnumerable<string>> GetUserNamesThatStartWith(strin...
FILE: src/PopForums.Sql/Repositories/UserSessionRepository.cs
class UserSessionRepository (line 3) | public class UserSessionRepository : IUserSessionRepository
method UserSessionRepository (line 5) | public UserSessionRepository(ICacheHelper cacheHelper, ISqlObjectFacto...
class CacheKeys (line 14) | public class CacheKeys
method CreateSession (line 19) | public async Task CreateSession(int sessionID, int? userID, DateTime l...
method UpdateSession (line 25) | public async Task<bool> UpdateSession(int sessionID, DateTime lastTime)
method IsSessionAnonymous (line 33) | public async Task<bool> IsSessionAnonymous(int sessionID)
method GetAndDeleteExpiredSessions (line 41) | public async Task<List<ExpiredUserSession>> GetAndDeleteExpiredSession...
method GetSessionIDByUserID (line 51) | public async Task<ExpiredUserSession> GetSessionIDByUserID(int userID)
method DeleteSessions (line 59) | public async Task DeleteSessions(int? userID, int sessionID)
method GetTotalSessionCount (line 69) | public async Task<int> GetTotalSessionCount()
FILE: src/PopForums.Sql/SqlObjectFactory.cs
class SqlObjectFactory (line 3) | public class SqlObjectFactory : ISqlObjectFactory
method SqlObjectFactory (line 7) | public SqlObjectFactory(IConfig config)
method GetConnection (line 12) | public DbConnection GetConnection()
method GetCommand (line 20) | public DbCommand GetCommand()
method GetCommand (line 25) | public DbCommand GetCommand(string sql)
method GetCommand (line 30) | public DbCommand GetCommand(string sql, DbConnection connection)
method GetParameter (line 35) | public DbParameter GetParameter(string parameterName, object value)
FILE: src/PopForums.Sql/StreamResponse.cs
class StreamResponse (line 3) | public class StreamResponse(Stream stream, SqlConnection connection, Sql...
method Dispose (line 7) | public void Dispose()
FILE: src/PopForums.Test/Composers/ForumStateComposerTests.cs
class ForumStateComposerTests (line 5) | public class ForumStateComposerTests
method GetComposer (line 7) | protected ForumStateComposer GetComposer()
class GetState (line 12) | public class GetState : ForumStateComposerTests
method MapsCorrectly (line 14) | [Fact]
FILE: src/PopForums.Test/Composers/PrivateMessageStateComposerTests.cs
class PrivateMessageStateComposerTests (line 7) | public class PrivateMessageStateComposerTests
method GetComposer (line 9) | protected PrivateMessageStateComposer GetComposer()
class GetState (line 17) | public class GetState : PrivateMessageStateComposerTests
method MessagesMappedWithBuffer (line 19) | [Fact]
method NewestPostIDSet (line 60) | [Fact]
method PMIDSet (line 81) | [Fact]
method PMUsersJsonSet (line 96) | [Fact]
method IsUserNotFoundSetToFalse (line 111) | [Fact]
method IsUserNotFoundSetToTrue (line 130) | [Fact]
FILE: src/PopForums.Test/Composers/TopicStateComposerTests.cs
class TopicStateComposerTests (line 5) | public class TopicStateComposerTests
method GetComposer (line 7) | protected TopicStateComposer GetComposer()
class GetState (line 21) | public class GetState : TopicStateComposerTests
method MapsCorrectlyWithoutUser (line 23) | [Fact]
method MapsCorrectlyWithUser (line 42) | [Fact]
FILE: src/PopForums.Test/Configuration/SettingsTests.cs
class SettingsTests (line 3) | public class SettingsTests
method LoadDefaults (line 5) | [Fact]
method LoadFromRepo (line 22) | [Fact]
method LoadFromRepoThenCache (line 52) | [Fact]
method LoadFromRepoWhenStale (line 69) | [Fact]
method DoNotLoadFromRepoWhenNotStale (line 83) | [Fact]
method SaveCurrent (line 96) | [Fact]
FILE: src/PopForums.Test/Email/EmailWorkerTests.cs
class EmailWorkerTests (line 6) | public class EmailWorkerTests
method GetWorker (line 14) | private IEmailWorker GetWorker()
method DoNothingWhenNoPayload (line 25) | [Fact]
method LogExceptionWhenEmailQueuePayloadTypeIsDeleteMassMessage (line 39) | [Fact]
method ProcessAMessage (line 51) | [Fact]
method DoNothingWhenQueuedMessageIsNull (line 69) | [Fact]
method LogExceptionWhenSmtpSendFails (line 84) | [Fact]
FILE: src/PopForums.Test/Email/NewAccountMailerTests.cs
class NewAccountMailerTests (line 3) | public class NewAccountMailerTests
method SendCallsSmtpWrapper (line 5) | [Fact]
FILE: src/PopForums.Test/Extensions/StringTests.cs
class StringTests (line 3) | public class StringTests
method GetSHA256HashString (line 5) | [Fact]
method GetMD5HashString (line 12) | [Fact]
method IsEmailTest (line 19) | [Fact]
method IsNoteEmailTest (line 30) | [Fact]
method UrlNameTest (line 41) | [Fact]
method UrlNameUniqueTest (line 51) | [Fact]
method UrlNameUniqueTestForPlantedDupe (line 60) | [Fact]
method UrlNameUniqueTestForDoubleDigits (line 69) | [Fact]
method TrimmerTest (line 78) | [Fact]
FILE: src/PopForums.Test/ExternalLogin/ExternalUserAssociationManagerTests.cs
class ExternalUserAssociationManagerTests (line 3) | public class ExternalUserAssociationManagerTests
method GetManager (line 5) | private ExternalUserAssociationManager GetManager()
method ExternalUserAssociationCheckThrowsWithNullArg (line 17) | [Fact]
method ExternalUserAssociationCheckResultFalseWithNullsIfNoMatchingAssociation (line 25) | [Fact]
method ExternalUserAssociationCheckResultFalseWithNullsIfNoMatchingUser (line 38) | [Fact]
method ExternalUserAssociationCheckResultTrueWithHydratedResultIfMatchingAssociationAndUser (line 52) | [Fact]
method ExternalUserAssociationCheckResultTrueCallsSecurityLog (line 69) | [Fact]
method ExternalUserAssociationCheckResultFalseNoMatchCallsSecurityLog (line 85) | [Fact]
method ExternalUserAssociationCheckResultFalseNoUserCallsSecurityLog (line 98) | [Fact]
method AssociateThrowsWithNullUser (line 113) | [Fact]
method AssociateNeverCallsRepoWithNullExternalAuthResult (line 121) | [Fact]
method AssociateThrowsWithNoProviderKey (line 131) | [Fact]
method AssociateMapsObjectsToRepoCall (line 139) | [Fact]
method AssociateSuccessCallsSecurityLog (line 151) | [Fact]
method GetExternalUserAssociationsCallsRepoByUserID (line 164) | [Fact]
method GetExternalUserAssociationsReturnsCollectionFromRepo (line 176) | [Fact]
method RemoveAssociationNeverCallsRepoIfNoAssociationIsFound (line 189) | [Fact]
method RemoveAssociationLogsTheRemoval (line 200) | [Fact]
method RemoveAssociationThrowsIfUserIDsDontMatch (line 214) | [Fact]
method RemoveAssociationCallsRepoOnSuccessfulMatch (line 225) | [Fact]
method GetExternalUserAssociationsThrowsIfAssociationDoesntMatchUser (line 238) | [Fact]
method GetExternalUserAssociationsCallsRepoWithMatchingUserIDs (line 249) | [Fact]
FILE: src/PopForums.Test/Messaging/NotificationAdapterTests.cs
class NotificationAdapterTests (line 5) | public class NotificationAdapterTests
method GetAdapter (line 7) | protected NotificationAdapter GetAdapter()
class Reply (line 15) | public class Reply : NotificationAdapterTests
method ManagerCalledWithCorrectValues (line 17) | [Fact]
class Vote (line 38) | public class Vote : NotificationAdapterTests
method ManagerCalledWithCorrectValues (line 40) | [Fact]
class QuestionAnswer (line 60) | public class QuestionAnswer : NotificationAdapterTests
method ManagerCalledWithCorrectValues (line 62) | [Fact]
class Award (line 82) | public class Award : NotificationAdapterTests
method ManagerCalledWithCorrectValues (line 84) | [Fact]
FILE: src/PopForums.Test/Messaging/NotificationManagerTests.cs
class NotificationManagerTests (line 5) | public class NotificationManagerTests
method GetManager (line 7) | protected NotificationManager GetManager()
class ProcessNotification (line 17) | public class ProcessNotification : NotificationManagerTests
method FieldsMapToUpdate (line 19) | [Fact]
method CreateNotCalledOnSuccessfulUpdate (line 43) | [Fact]
method FieldsMapToCreate (line 54) | [Fact]
method FieldsMapToNotifyUser (line 76) | [Fact]
class GetUnreadNotificationCount (line 99) | public class GetUnreadNotificationCount : NotificationManagerTests
method Over100Returns100 (line 101) | [Fact]
method Under100ReturnsRepoValue (line 113) | [Fact]
method The100Returns100 (line 125) | [Fact]
FILE: src/PopForums.Test/Models/ForumHomeContainerTests.cs
class ForumHomeContainerTests (line 3) | public class ForumHomeContainerTests
method UncategorizedForumsShowUpOnProperty (line 5) | [Fact]
method UncategorizedInCorrectOrder (line 23) | [Fact]
method CategoriesInCorrectOrder (line 36) | [Fact]
method AllCollectionsPersist (line 53) | [Fact]
method ForumsAppearInCategories (line 68) | [Fact]
method CategoryWithNoForumsDoesNotAppear (line 85) | [Fact]
FILE: src/PopForums.Test/Models/UserEditSecurityTests.cs
class UserEditSecurityTests (line 3) | public class UserEditSecurityTests
method PasswordsMatch (line 5) | [Fact]
method PasswordsNoMatch (line 14) | [Fact]
method EmailMatch (line 23) | [Fact]
method EmailNoMatch (line 32) | [Fact]
method IsNewUserApprovedMapped (line 41) | [Fact]
FILE: src/PopForums.Test/Models/UserTest.cs
class UserTest (line 3) | public class UserTest
method IsRoleWiredToRoles (line 5) | [Fact]
method GetTestUser (line 13) | public static User GetTestUser()
FILE: src/PopForums.Test/Mvc/Authorization/PopForumsPrivateForumsFilterTests.cs
class PopForumsPrivateForumsFilterTests (line 9) | public class PopForumsPrivateForumsFilterTests
method GetFilter (line 11) | private PopForumsPrivateForumsFilter GetFilter()
method GetContext (line 19) | private ActionExecutingContext GetContext()
class OnActionExecuting (line 28) | public class OnActionExecuting : PopForumsPrivateForumsFilterTests
method DoesNothingIfSettingIsFalseAndOAuthOnlyIsFalse (line 30) | [Fact]
method DoesNothingIfSettingIsTrueAndUserPresent (line 44) | [Fact]
method DoesNothingIfOAuthOnlyIsTrueAndUserPresent (line 60) | [Fact]
method RedirectIfSettingIsTrueAndNoUserPresent (line 76) | [Fact]
method RedirectIfOAuthOnlyIsTrueAndNoUserPresent (line 90) | [Fact]
FILE: src/PopForums.Test/Mvc/Controllers/AccountControllerTests.cs
class AccountControllerTests (line 8) | public class AccountControllerTests
method GetController (line 29) | private AccountController GetController()
class Create (line 58) | public class Create : AccountControllerTests
method PopulatesDefaultValues (line 60) | [Fact]
method PopulatesValuesFromExternalLogin (line 71) | [Fact]
class Verify (line 95) | public class Verify : AccountControllerTests
method ReturnVerifyFailViewWhenNonGuidCode (line 97) | [Fact]
method ReturnDefaultViewWhenNoCode (line 107) | [Fact]
method ReturnVerifyFailViewWhenGuidMatchesNoUser (line 117) | [Fact]
method SuccessReturnViewWithMessage (line 128) | [Fact]
method SuccessLoginUser (line 141) | [Fact]
class VerifyCode (line 154) | public class VerifyCode : AccountControllerTests
method RedirectsToVerify (line 156) | [Fact]
FILE: src/PopForums.Test/Mvc/Controllers/AdminApiControllerTests.cs
class AdminApiControllerTests (line 3) | public class AdminApiControllerTests
method GetController (line 24) | private AdminApiController GetController()
class SaveForum (line 47) | public class SaveForum : AdminApiControllerTests
method CallsCreateIfForumIDIsZero (line 49) | [Fact]
method CallsUpdateIfForumIDIsNotZero (line 61) | [Fact]
method ReturnsNotFoundIfForumIsNotReal (line 74) | [Fact]
class GetForumPermissions (line 88) | public class GetForumPermissions : AdminApiControllerTests
method ContainerIsComposed (line 90) | [Fact]
class EditUserSearch (line 112) | public class EditUserSearch : AdminApiControllerTests
method NameSearchCallsNameSearch (line 114) | [Fact]
method EmailSearchCallsEmailSearch (line 128) | [Fact]
method RoleSearchCallsRoleSearch (line 142) | [Fact]
FILE: src/PopForums.Test/Mvc/Services/OAuthOnlyServiceTests.cs
class OAuthOnlyServiceTests (line 7) | public class OAuthOnlyServiceTests
method GetService (line 20) | private OAuthOnlyService GetService()
class GetLoginUrl (line 35) | public class GetLoginUrl : OAuthOnlyServiceTests
method ConfigParameterAndHashValuesCalledToLoginGen (line 37) | [Fact]
method GeneratedUrlReturned (line 53) | [Fact]
class ProcessOAuthLogin (line 66) | public class ProcessOAuthLogin : OAuthOnlyServiceTests
method FailedCallbackReturnsFail (line 68) | [Fact]
method CallbackValuesMappedToExternalCheck (line 81) | [Fact]
method ExistingUserMappedToClaims (line 102) | [Fact]
method ExistingUserNameUnchangedNotChanged (line 121) | [Fact]
method ExistingUserNameChangedIsChanged (line 140) | [Fact]
method NewUserMappedToClaims (line 159) | [Fact]
method UnmatchedUserIsCreatedAndAssociated (line 181) | [Fact]
class AttemptTokenRefresh (line 221) | public class AttemptTokenRefresh : OAuthOnlyServiceTests
method FailedCallbackMakesNoUpdates (line 223) | [Fact]
method GoodTokenUpdatesStuff (line 235) | [Fact]
FILE: src/PopForums.Test/ScoringGame/AwardCalculatorTests.cs
class AwardCalculatorTests (line 3) | public class AwardCalculatorTests
method GetCalc (line 5) | private AwardCalculator GetCalc()
method EnqueueDoesWhatItSaysItShould (line 27) | [Fact]
method ProcessLogsAndDoesNothingWithNullEventDef (line 43) | [Fact]
method ProcessNeverCallsIssueIfAwardedAndSingleAward (line 56) | [Fact]
method ProcessNeverCallsIfEventCountNotHighEnough (line 72) | [Fact]
method ProcessIssuesAwardWhenConditionsEqualOrGreater (line 96) | [Fact]
method ProcessIssuesSecondAwardWhenConditionsEqualOrGreater (line 120) | [Fact]
FILE: src/PopForums.Test/ScoringGame/AwardCalculatorWorkerTests.cs
class AwardCalculatorWorkerTests (line 5) | public class AwardCalculatorWorkerTests
method GetWorker (line 11) | private IAwardCalculatorWorker GetWorker()
method DoNothingWhenNoPayload (line 19) | [Fact]
method CallProcessPayloadWithPayloadValues (line 31) | [Fact]
method LogWhenDequeueThrows (line 43) | [Fact]
method LogWhenProcessCalculationThrows (line 55) | [Fact]
FILE: src/PopForums.Test/ScoringGame/AwardDefinitionServiceTests.cs
class AwardDefinitionServiceTests (line 3) | public class AwardDefinitionServiceTests
method GetService (line 5) | public AwardDefinitionService GetService()
method CreateMapsObjectToRepo (line 15) | [Fact]
method SaveConditionsDeletesOldOnes (line 24) | [Fact]
method SaveConditionsSetsAllAwardDefIDs (line 33) | [Fact]
FILE: src/PopForums.Test/ScoringGame/EventDefintionServiceTests.cs
class EventDefintionServiceTests (line 3) | public class EventDefintionServiceTests
method GetService (line 5) | private EventDefinitionService GetService()
method GetReturnsFromRepo (line 15) | [Fact]
method GetStaticPostVoteReturnsStaticObject (line 25) | [Fact]
method GetAllMergesStaticWithRepo (line 33) | [Fact]
method GetAllMergesAndOrders (line 48) | [Fact]
method CreatePassesToRepo (line 64) | [Fact]
method DeleteCallsEventDefRepoAndAwardConditionRepo (line 73) | [Fact]
FILE: src/PopForums.Test/ScoringGame/EventPublisherTests.cs
class EventPublisherTests (line 3) | public class EventPublisherTests
method GetPublisher (line 5) | private EventPublisher GetPublisher()
method ProcessEventPublishesToLedger (line 21) | [Fact]
method ProcessEventPublishesToFeedService (line 37) | [Fact]
method ProcessEventDoesNotPublishToFeedServiceWhenEventDefSaysNo (line 49) | [Fact]
method ProcessEventCallsCalculator (line 61) | [Fact]
method ProcessEventUpdatesProfilePointTotal (line 72) | [Fact]
method ProcessManualEventPublishesToLedger (line 83) | [Fact]
method ProcessManualEventPublishesToFeedService (line 98) | [Fact]
method ProcessManualEventUpdatesProfilePointTotal (line 109) | [Fact]
FILE: src/PopForums.Test/ScoringGame/FeedServiceTests.cs
class FeedServiceTests (line 3) | public class FeedServiceTests
method GetService (line 5) | private FeedService GetService()
method PublishSavesToRepo (line 15) | [Fact]
method PublishDeletesOlderThan50 (line 27) | [Fact]
method PublishDoesNothingIfUserIsNull (line 40) | [Fact]
method GetFeedGets50ItemsMaxFromRepo (line 48) | [Fact]
FILE: src/PopForums.Test/ScoringGame/UserAwardServiceTests.cs
class UserAwardServiceTests (line 3) | public class UserAwardServiceTests
method GetService (line 5) | public UserAwardService GetService()
method IssueMapsFieldsToRepoCall (line 17) | [Fact]
method IsAwardedMapsAndReturnsRightValue (line 27) | [Fact]
method GetAwardsMapsUserIDAndReturnsList (line 38) | [Fact]
FILE: src/PopForums.Test/Services/BanServiceTests.cs
class BanServiceTests (line 3) | public class BanServiceTests
method GetService (line 7) | private IBanService GetService()
method IPTrimmedOnSave (line 13) | [Fact]
method EmailTrimmedOnSave (line 21) | [Fact]
FILE: src/PopForums.Test/Services/CategoryServiceTests.cs
class CategoryServiceTests (line 3) | public class CategoryServiceTests
method GetService (line 8) | private ICategoryService GetService()
method GetAll (line 16) | [Fact]
method Create (line 27) | [Fact]
method Delete (line 52) | [Fact]
method DeleteByIdThrowsIfNotFound (line 61) | [Fact]
method DeleteResetsForumCatIDsToNull (line 70) | [Fact]
method UpdateTitle (line 86) | [Fact]
method UpdateTitleByIdThrowsIfNotFound (line 100) | [Fact]
method MoveUp (line 109) | [Fact]
method MoveDown (line 132) | [Fact]
method MoveUpByIdThrowsIfNotFound (line 155) | [Fact]
method MoveDownByIdThrowsIfNotFound (line 164) | [Fact]
FILE: src/PopForums.Test/Services/ClaimsToRoleMapperTests.cs
class ClaimsToRoleMapperTests (line 5) | public class ClaimsToRoleMapperTests
method GetService (line 10) | private ClaimsToRoleMapper GetService()
class MapRoles (line 17) | public class MapRoles : ClaimsToRoleMapperTests
method NoMappingWithNoClaims (line 19) | [Fact]
method NoMappingWithNoMatchingClaims (line 35) | [Fact]
method NoMappingWithNoMatchingClaimsValues (line 53) | [Fact]
method AdminNameNoValueMapsAdminRole (line 75) | [Fact]
method AdminNameWithValueMapsAdminRole (line 94) | [Fact]
method ModNameNoValueMapsModRole (line 113) | [Fact]
method ModNameWithValueMapsModRole (line 132) | [Fact]
FILE: src/PopForums.Test/Services/CloseAgedTopicsWorkerTests.cs
class CloseAgedTopicsWorkerTests (line 5) | public class CloseAgedTopicsWorkerTests
method GetWorker (line 10) | private CloseAgedTopicsWorker GetWorker()
method NoErrorNoLog (line 17) | [Fact]
method LogWhenThrows (line 28) | [Fact]
FILE: src/PopForums.Test/Services/FavoriteTopicServiceTests.cs
class FavoriteTopicServiceTests (line 3) | public class FavoriteTopicServiceTests
method GetService (line 8) | private FavoriteTopicService GetService()
method GetTopicsFromRepo (line 15) | [Fact]
method AddFaveTopic (line 28) | [Fact]
method RemoveFaveTopic (line 38) | [Fact]
method GetTopicsStartRowCalcd (line 48) | [Fact]
FILE: src/PopForums.Test/Services/ForumPermissionServiceTests.cs
class ForumPermissionServiceTests (line 3) | public class ForumPermissionServiceTests
method GetService (line 5) | private ForumPermissionService GetService()
method GetUser (line 13) | private User GetUser()
method NoViewRestrictionWithUser (line 20) | [Fact]
method NoViewRestrictionWithoutUser (line 31) | [Fact]
method ViewRestrictionUserNotInRole (line 41) | [Fact]
method ViewRestrictionUserCantPostEither (line 51) | [Fact]
method ViewRestrictionNoUser (line 62) | [Fact]
method ViewRestrictionUserInRole (line 72) | [Fact]
method PostRestrictionNoUser (line 84) | [Fact]
method PostRestrictionUserInRole (line 94) | [Fact]
method PostRestrictionUserNotApproved (line 107) | [Fact]
method PostRestrictionUserNotInRole (line 120) | [Fact]
method ModerateNoUser (line 131) | [Fact]
method ModerateUserIsAdmin (line 141) | [Fact]
method ModerateUserIsModerator (line 153) | [Fact]
method TopicClosed (line 165) | [Fact]
method TopicOpen (line 176) | [Fact]
method WithUserTopicDeleted (line 187) | [Fact]
method AnonTopicDeleted (line 198) | [Fact]
method ModOnTopicDeleted (line 208) | [Fact]
method ForumNotArchived (line 220) | [Fact]
method ForumIsArchived (line 231) | [Fact]
FILE: src/PopForums.Test/Services/ForumServiceTests.cs
class ForumServiceTests (line 3) | public class ForumServiceTests
method GetService (line 11) | private ForumService GetService()
method Get (line 21) | [Fact]
method Create (line 32) | [Fact]
method CreateMakesUrlTitle (line 57) | [Fact]
method CreateMakesUrlTitleWithAppendage (line 77) | [Fact]
method UpdateLast (line 97) | [Fact]
method UpdateLastWithValues (line 113) | [Fact]
method GetForumsWithCategories (line 142) | [Fact]
method MoveUp (line 158) | [Fact]
method MoveDown (line 182) | [Fact]
method MoveForumUpThrowsIfNoForum (line 206) | [Fact]
method MoveForumDownThrowsIfNoForum (line 215) | [Fact]
method PostRestrictions (line 224) | [Fact]
method ViewRestrictions (line 236) | [Fact]
method GetViewableForumIDsFromViewRestrictedForumsReturnsEmptyDictionaryWithoutUser (line 248) | [Fact]
method GetViewableForumIDsFromViewRestrictedForumsDoesntIncludeForumsWithNoViewRestrictions (line 268) | [Fact]
method GetViewableForumIDsFromViewRestrictedForumsReturnsIDsWithMatchingUserRoles (line 285) | [Fact]
method GetNonViewableDoesntIncludeForumsWithNoViewRestrictions (line 309) | [Fact]
method GetNonViewableDoesntIncludeForumsWithRoleMatchingViewRestrictions (line 323) | [Fact]
method GetNonViewableIncludesForumsWithNoMatchingViewRestrictions (line 337) | [Fact]
method GetNonViewableExcludesViewRestrictionsForNoUser (line 351) | [Fact]
method GetCategorizedForUserHasOnlyViewableForums (line 366) | [Fact]
method GetCategorizedForUserPopulatesReadStatus (line 384) | [Fact]
method GetCategoryContainersWithForumsMapsCatsWithUnCatForums (line 397) | [Fact]
method GetCategoryContainersWithForumsMapsCatsWithoutUnCatForums (line 427) | [Fact]
method GetCategoryContainersWithForumsMapsForums (line 455) | [Fact]
method MapTopicContainerForQAMapsBaseProperties (line 489) | [Fact]
method MapTopicContainerGrabsFirstPostForQuestion (line 517) | [Fact]
method MapTopicContainerThrowsWithNoFirstInTopicPost (line 531) | [Fact]
method MapTopicContainerThrowsWithMoreThanOneFirstInTopicPost (line 544) | [Fact]
method MapTopicContainerSetsQuestionsWithNoParentAsAnswers (line 557) | [Fact]
method MapTopicContainerMapsCommentsToParentQuestionsAndAnswers (line 573) | [Fact]
method MapTopicContainerMapsCommentsToQuestion (line 594) | [Fact]
method MapTopicContainerOrdersAnswersByVoteThenDate (line 613) | [Fact]
method MapTopicContainerOrdersAnswersByAnswerThenVoteThenDate (line 636) | [Fact]
method MapTopicContainerDoesNotMapCommentsForTopQuestionAsReplies (line 659) | [Fact]
method MapTopicContainerMapsLastReadTimeToQuestionAndAnswerSets (line 676) | [Fact]
class ModifyForumRoles (line 696) | public class ModifyForumRoles : ForumServiceTests
method ThrowsIfNoForumMatch (line 698) | [Fact]
method CallSetup (line 707) | private async Task<Tuple<int, string>> CallSetup(ModifyForumRolesTyp...
method AddPostCallsRepo (line 717) | [Fact]
method RemovePostCallsRepo (line 725) | [Fact]
method AddViewCallsRepo (line 733) | [Fact]
method RemoveViewCallsRepo (line 741) | [Fact]
method RemoveAllPostCallsRepo (line 749) | [Fact]
method RemoveAllViewCallsRepo (line 757) | [Fact]
FILE: src/PopForums.Test/Services/ImageServiceTests.cs
class ImageServiceTests (line 3) | public class ImageServiceTests
method GetService (line 11) | private ImageService GetService()
method GetAvatar (line 21) | [Fact]
method GetUserImage (line 33) | [Fact]
FILE: src/PopForums.Test/Services/LastReadServiceTests.cs
class LastReadServiceTests (line 3) | public class LastReadServiceTests
method GetService (line 5) | private LastReadService GetService()
method MarkForumReadSetsReadTime (line 15) | [Fact]
method MarkForumReadDeletesOldTopicReadTimes (line 25) | [Fact]
method MarkTopicReadThrowsWithoutUser (line 35) | [Fact]
method MarkTopicReadThrowsWithoutTopic (line 42) | [Fact]
method MarkAllForumReadThrowsWithoutUser (line 49) | [Fact]
method MarkForumReadThrowsWithoutUser (line 56) | [Fact]
method MarkForumReadThrowsWithoutForum (line 63) | [Fact]
method MarkAllForumReadSetsReadTimes (line 70) | [Fact]
method MarkAllForumReadDeletesAllOldTopicReadTimes (line 79) | [Fact]
method ForumReadStatusForNoUser (line 88) | [Fact]
method ForumReadStatusUserNewPosts (line 103) | [Fact]
method ForumReadStatusUserNewPostsButNoTopicRecords (line 116) | [Fact]
method ForumReadStatusUserNewPostsNoLastReadRecords (line 130) | [Fact]
method ForumReadStatusUserNoNewPosts (line 143) | [Fact]
method ForumReadStatusUserNewPostsArchived (line 156) | [Fact]
method ForumReadStatusUserNoNewPostsArchived (line 169) | [Fact]
method TopicReadStatusForNoUser (line 182) | [Fact]
method TopicReadStatusWithUserNewNoForumRecordNoTopicRecord (line 195) | [Fact]
method TopicReadStatusWithUserNewNoForumRecordWithTopicRecord (line 210) | [Fact]
method TopicReadStatusWithUserNewWithForumRecordNoTopicRecord (line 225) | [Fact]
method TopicReadStatusWithUserNewWithForumRecordWithTopicRecord (line 240) | [Fact]
method TopicReadStatusWithUserNotNewWithForumRecordNoTopicRecord (line 255) | [Fact]
method TopicReadStatusWithUserNotNewNoForumRecordWithTopicRecord (line 270) | [Fact]
method TopicReadStatusWithUserNotNewWithForumRecordWithTopicRecordForumNewer (line 285) | [Fact]
method TopicReadStatusWithUserNotNewWithForumRecordWithTopicRecordTopicNewer (line 300) | [Fact]
method TopicReadStatusWithUserOpenNewPinned (line 315) | [Fact]
method TopicReadStatusWithUserOpenNewNotPinned (line 330) | [Fact]
method TopicReadStatusWithUserOpenNotNewPinned (line 345) | [Fact]
method TopicReadStatusWithUserOpenNotNewNotPinned (line 360) | [Fact]
method TopicReadStatusWithUserClosedNewPinned (line 375) | [Fact]
method TopicReadStatusWithUserClosedNewNotPinned (line 390) | [Fact]
method TopicReadStatusWithUserClosedNoNewPinned (line 405) | [Fact]
method TopicReadStatusWithUserClosedNoNewNotPinned (line 420) | [Fact]
method MarkTopicReadCallsRepo (line 433) | [Fact]
method GetLastReadTimeReturnsTopicTimeWhenAvailable (line 443) | [Fact]
method GetLastReadTimeReturnsForumTimeWhenNoTopicTimeAvailable (line 458) | [Fact]
FILE: src/PopForums.Test/Services/PostImageCleanupWorkerTests.cs
class PostImageCleanupWorkerTests (line 5) | public class PostImageCleanupWorkerTests
method GetWorker (line 10) | private PostImageCleanupWorker GetWorker()
method NoErrorNoLog (line 17) | [Fact]
method LogWhenThrows (line 28) | [Fact]
FILE: src/PopForums.Test/Services/PostImageServiceTests.cs
class PostImageServiceTests (line 3) | public class PostImageServiceTests
method GetService (line 11) | protected PostImageService GetService()
class ProcessImageIsOk (line 21) | public class ProcessImageIsOk : PostImageServiceTests
method ImageIsTooBig (line 23) | [Fact]
method ImageIsBadContentType (line 37) | [Fact]
method ImageIsRightSizeJpeg (line 51) | [Fact]
method ImageIsRightSizeGif (line 65) | [Fact]
method ImageIsResized (line 78) | [Fact]
class PersistAndGetPayload (line 97) | public class PersistAndGetPayload : PostImageServiceTests
method ThrowsWithNoContentType (line 99) | [Fact]
method ThrowsWhenNotOkContentType (line 109) | [Fact]
method ThrowsWhenNotOkBytes (line 119) | [Fact]
method PersistsImageAndTempRecordAndReturnsPayload (line 129) | [Fact]
class DeleteTempRecord (line 152) | public class DeleteTempRecord : PostImageServiceTests
method TempRepoCalledWithGuid (line 154) | [Fact]
class DeleteTempRecords (line 167) | public class DeleteTempRecords : PostImageServiceTests
method TempRepoCalledWithGuidsFoundInText (line 169) | [Fact]
method TempRepoCalledExcludingGuidsNotFoundInText (line 188) | [Fact]
class DeleteOldPostImages (line 209) | public class DeleteOldPostImages : PostImageServiceTests
method PostImageRepoCalledForEachEntry (line 211) | [Fact]
method PostImageTempRepoCalledForEachEntry (line 226) | [Fact]
FILE: src/PopForums.Test/Services/PostMasterServiceTests.cs
class PostMasterServiceTests (line 3) | public class PostMasterServiceTests
method GetService (line 5) | private PostMasterService GetService()
method DoUpNewTopic (line 41) | private async Task<User> DoUpNewTopic()
method GetUser (line 63) | private User GetUser()
class PostNewTopicTests (line 70) | public class PostNewTopicTests : PostMasterServiceTests
method NoUserReturnsFalseIsSuccess (line 72) | [Fact]
method UserWithoutPostPermissionReturnsFalseIsSuccess (line 82) | [Fact]
method UserWithoutViewPermissionReturnsFalseIsSuccess (line 96) | [Fact]
method NoForumMatchThrows (line 110) | [Fact]
method CallsPostRepoCreateWithPlainText (line 119) | [Fact]
method CallsPostRepoCreateWithHtmlText (line 144) | [Fact]
method CallsPostRepoWithTopicID (line 169) | [Fact]
method CallsSubscribeServiceWithUserAndTopicIfEnabled (line 194) | [Fact]
method CallsPostImageServiceWithIDs (line 220) | [Fact]
method DupeOfLastPostReturnsFalseIsSuccess (line 247) | [Fact]
method MinimumTimeBetweenPostsNotMetReturnsFalseIsSuccess (line 268) | [Fact]
method CallsTopicRepoCreate (line 289) | [Fact]
method TitleIsParsed (line 312) | [Fact]
method CallsForumTopicPostIncrement (line 335) | [Fact]
method CallsForumUpdateLastUser (line 342) | [Fact]
method CallsProfileSetLastPost (line 349) | [Fact]
method PublishesNewTopicEvent (line 356) | [Fact]
method PublishesNewPostEvent (line 363) | [Fact]
method CallsBroker (line 370) | [Fact]
method QueuesTopicForIndexing (line 378) | [Fact]
method DoesNotPublishToFeedIfForumHasViewRestrictions (line 386) | [Fact]
method ReturnsTopic (line 410) | [Fact]
class PostReplyTests (line 447) | public class PostReplyTests : PostMasterServiceTests
method NoUserReturnsFalseIsSuccessful (line 449) | [Fact]
method NoTopicReturnsFalseIsSuccessful (line 459) | [Fact]
method NoForumThrows (line 471) | [Fact]
method NoViewPermissionReturnsFalseIsSuccessful (line 481) | [Fact]
method NoPostPermissionReturnsFalseIsSuccessful (line 499) | [Fact]
method ClosedTopicReturnsFalseIsSuccessful (line 517) | [Fact]
method UsesPlainTextParsed (line 529) | [Fact]
method UsesRichTextParsed (line 551) | [Fact]
method DupeOfLastPostFails (line 573) | [Fact]
method MinTimeSinceLastPostTooShortFails (line 597) | [Fact]
method EmptyPostFails (line 621) | [Fact]
method HitsRepo (line 644) | [Fact]
method HitsSubscribedService (line 666) | [Fact]
method HitsSubscribeAddWhenProfileCallsForIt (line 689) | [Fact]
method IncrementsTopicReplyCount (line 711) | [Fact]
method IncrementsForumPostCount (line 732) | [Fact]
method UpdatesTopicLastInfo (line 753) | [Fact]
method UpdatesForumLastInfo (line 774) | [Fact]
method PostQueuesMarksTopicForIndexing (line 795) | [Fact]
method NotifiesBroker (line 817) | [Fact]
method SetsProfileLastPostID (line 842) | [Fact]
method CallsPostImageServiceWithIDs (line 863) | [Fact]
method PublishesEvent (line 885) | [Fact]
method DoesNotPublishEventOnViewRestrictedForum (line 906) | [Fact]
method ReturnsHydratedObject (line 927) | [Fact]
class EditPostTests (line 965) | public class EditPostTests : PostMasterServiceTests
method GetUser (line 967) | private new User GetUser()
method FailsBecauseNoUserMatch (line 972) | [Fact]
method CensorsTitle (line 984) | [Fact]
method NoTitleUpdateWhenNotFirstPostInTopic (line 993) | [Fact]
method NoTitleUpdateWhenTitleHasNotChanged (line 1005) | [Fact]
method NoEditWhenTitleIsEmpty (line 1017) | [Fact]
method TitleUpdateWhenFirstPostInTopicAndTitleChanged (line 1030) | [Fact]
method PlainTextParsed (line 1045) | [Fact]
method RichTextParsed (line 1054) | [Fact]
method SavesMappedValues (line 1065) | [Fact]
method ModeratorLogged (line 1090) | [Fact]
method QueuesTopicForIndexing (line 1105) | [Fact]
method ModeratorCanEdit (line 1120) | [Fact]
FILE: src/PopForums.Test/Services/PostServiceTests.cs
class PostServiceTests (line 3) | public class PostServiceTests
method GetService (line 19) | private PostService GetService()
method GetPostsPageSizeAndStartRowCalcdCorrectly (line 38) | [Fact]
method GetPostsReplyCountCalledOnIncludeDeleted (line 51) | [Fact]
method GetPostsPagerContextConstructed (line 63) | [Fact]
method GetPostsHitsRepo (line 74) | [Fact]
method GetCallsRepoAndReturns (line 86) | [Fact]
method GetPostCountCallsRepo (line 98) | [Fact]
method GetPostForEditPlainText (line 109) | [Fact]
method GetPostForEditNotPlainText (line 126) | [Fact]
method DeleteThrowsForNonAuthorAndNonMod (line 143) | [Fact]
method DeleteCallDeleteTopicIfFirstInTopic (line 152) | [Fact]
method DeleteCallLogs (line 166) | [Fact]
method DeleteSetsEditFields (line 180) | [Fact]
method DeleteCallSetsIsDeletedAndUpdates (line 198) | [Fact]
method DeleteCallFiresRecalcs (line 215) | [Fact]
method UndeleteThrowsForNonMod (line 238) | [Fact]
method UndeleteCallLogs (line 247) | [Fact]
method UndeleteSetsEditFields (line 261) | [Fact]
method UndeleteCallSetsIsDeletedAndUpdates (line 279) | [Fact]
method UndeleteCallFiresRecalcs (line 296) | [Fact]
method GetPostsToEndSkipsLoadedPosts (line 319) | [Fact]
method GetPostsToEndCalcsCorrectPagerContext (line 332) | [Fact]
method ToggleVoteCallsRepoWithPostIDAndUserID (line 344) | [Fact]
method ToggleVoteCalcsAndSetsCount (line 355) | [Fact]
method GetVoteCountCallsRepoAndReturns (line 368) | [Fact]
method GetVotersReturnsContainerWithPostID (line 379) | [Fact]
method GetVotersReturnsContainerWithTotalVotes (line 389) | [Fact]
method GetVotersFiltersNullNames (line 400) | [Fact]
method GetVotedIDsPassesUserID (line 412) | [Fact]
method GetVotedIDsPassesPostIDList (line 421) | [Fact]
method GetVotedIDsReturnsRepoObject (line 436) | [Fact]
method GetVotedIDsReturnsEmptyListWithNullUser (line 446) | [Fact]
method ToggleVoteDoesntCallPublisherWhenUserFromPostDoesNotExist (line 454) | [Fact]
method ToggleVoteCallsEventPub (line 464) | [Fact]
method ToggleVoteCallsNotification (line 475) | [Fact]
method ToggleVoteDoesNotCallWhenUserIsPoster (line 489) | [Fact]
method ToggleVotePassesPubStringWithFormattedStuff (line 500) | [Fact]
method GenerateParsedTextPreviewCallsForumCodeForPlainText (line 518) | [Fact]
method GenerateParsedTextPreviewCallsHtmlForRichText (line 530) | [Fact]
FILE: src/PopForums.Test/Services/PrivateMessageServiceTests.cs
class PrivateMessageServiceTests (line 3) | public class PrivateMessageServiceTests
method GetService (line 5) | private PrivateMessageService GetService()
method CreateNullTextThrows (line 20) | [Fact]
method CreateEmptyTextThrows (line 27) | [Fact]
method CreateNullUserThrows (line 34) | [Fact]
method CreateNullToUsersThrows (line 41) | [Fact]
method CreateZeroToUsersThrows (line 48) | [Fact]
method CreateSerializedUser (line 55) | [Fact]
method CreateSerializedUsers (line 64) | [Fact]
method CreateCallsNotificationBroker (line 75) | [Fact]
method CreatePMPersistedIDReturned (line 86) | [Fact]
method CreateAllUsersPresisted (line 97) | [Fact]
method CreatePostPersist (line 119) | [Fact]
method ReplyNullPMThrows (line 137) | [Fact]
method ReplyNoIdPMThrows (line 144) | [Fact]
method ReplyNullTextThrows (line 151) | [Fact]
method ReplyEmptyTextThrows (line 158) | [Fact]
method ReplyNullUserThrows (line 165) | [Fact]
method ReplyMapsAndPresistsPost (line 172) | [Fact]
method ReplyThrowsIfUserIsntOnPM (line 194) | [Fact]
method IsUserInPMTrue (line 203) | [Fact]
method IsUserInPMFalse (line 213) | [Fact]
FILE: src/PopForums.Test/Services/ProfileServiceTests.cs
class ProfileServiceTests (line 3) | public class ProfileServiceTests
method GetService (line 9) | private ProfileService GetService()
method GetProfile (line 17) | [Fact]
method GetProfileReturnsNullForNullUser (line 29) | [Fact]
method GetProfileForEditParsesSigRichText (line 37) | [Fact]
method GetProfileForEditParsesSigPlainText (line 51) | [Fact]
method EditUserProfilePlainText (line 65) | [Fact]
method EditUserProfileRichText (line 107) | [Fact]
method GetProfileForEditParsesSigGuardForNull (line 137) | [Fact]
method CreateFromProfileObject (line 152) | [Fact]
method CreateFromProfileThrowsWithoutUserID (line 161) | [Fact]
method Update (line 170) | [Fact]
method UpdateTrimsSig (line 180) | [Fact]
method UpdateThrowsWithNoProfile (line 191) | [Fact]
method GetSigsOnlyTakesPostsWithShowSig (line 201) | [Fact]
method GetSigsDoesntSendDupeUserIDs (line 223) | [Fact]
method GetAvatarsDoesntSendDupeUserIDs (line 244) | [Fact]
method UpdatePointsUpdatesPoints (line 266) | [Fact]
FILE: src/PopForums.Test/Services/QueuedEmailServiceTests.cs
class QueuedEmailServiceTests (line 3) | public class QueuedEmailServiceTests
method GetService (line 9) | private QueuedEmailService GetService()
method CreateAndQueueEmailCallsRepoWithMessage (line 17) | [Fact]
method CreateAndQueueEmailCallsEmailQueueWithCorrectPayload (line 30) | [Fact]
FILE: src/PopForums.Test/Services/SearchIndexWorkerTests.cs
class SearchIndexWorkerTests (line 6) | public class SearchIndexWorkerTests
method GetWorker (line 12) | private ISearchIndexWorker GetWorker()
method DoNothingWhenNoPayload (line 20) | [Fact]
method CallSearchIndexSubsystemWhenPayload (line 32) | [Fact]
method LogWhenGetNextTopicForIndexingThrows (line 45) | [Fact]
method LogWhenDoIndexThrows (line 57) | [Fact]
FILE: src/PopForums.Test/Services/SearchServiceTests.cs
class SearchServiceTests (line 3) | public class SearchServiceTests
method GetService (line 11) | private SearchService GetService()
method GetJunkWords (line 21) | [Fact]
method CreateWord (line 32) | [Fact]
method DeleteWord (line 40) | [Fact]
method GetTopicsReturnsValidResponseWithNoResultsWhenSearchTermIsNull (line 48) | [Fact]
method GetTopicsReturnsValidResponseWithNoResultsWhenSearchTermIsEmpty (line 61) | [Fact]
method GetTopicsIsCalledWithTheRightParameters (line 74) | [Fact]
method GetTopicsOutsCorrectPagerContextAndValidResult (line 90) | [Fact]
method GetTopicsReturnsEmptyResultIsValidFalseAndAnemicPagerContext (line 112) | [Fact]
FILE: src/PopForums.Test/Services/SecurityLogServiceTests.cs
class SecurityLogServiceTests (line 3) | public class SecurityLogServiceTests
method GetService (line 8) | private SecurityLogService GetService()
method GetEntriesByUserID (line 15) | [Fact]
method GetEntriesByUserName (line 24) | [Fact]
method CreateNullIp (line 35) | [Fact]
method CreateNullMessage (line 42) | [Fact]
method Create (line 49) | [Fact]
FILE: src/PopForums.Test/Services/SetupServiceTests.cs
class SetupServiceTests (line 3) | public class SetupServiceTests
method GetService (line 10) | private SetupService GetService()
class IsRuntimeConnectionAndSetupGoodTests (line 23) | public class IsRuntimeConnectionAndSetupGoodTests : SetupServiceTests
method GoodConnectionAndSetupAlwaysReturnsTrue (line 25) | [Fact]
method GoodConnectionAndSetupOnlyCallsReposOnce (line 39) | [Fact]
method BadConnectionReturnsFalse (line 56) | [Fact]
method GoodConnectionButNotSetupReturnsFalse (line 67) | [Fact]
FILE: src/PopForums.Test/Services/SitemapServiceTests.cs
class SitemapServiceTests (line 3) | public class SitemapServiceTests
method GetService (line 5) | private SitemapService GetService()
class GetSitemapPageCount (line 15) | public class GetSitemapPageCount : SitemapServiceTests
method ZeroTopicsReturns1 (line 17) | [Fact]
method MaxTopicsReturns1 (line 30) | [Fact]
method MaxPlusOneTopicsReturns2 (line 43) | [Fact]
method NonViewableListPassedToTopicRepoForCount (line 56) | [Fact]
FILE: src/PopForums.Test/Services/SubscribeNotificationWorkerTests.cs
class SubscribeNotificationWorkerTests (line 5) | public class SubscribeNotificationWorkerTests
method GetWorker (line 12) | private SubscribeNotificationWorker GetWorker()
method NoPaylodNoOtherCalls (line 21) | [Fact]
method PayloadValuesCallNotificationAdapter (line 35) | [Fact]
FILE: src/PopForums.Test/Services/SubscribedTopicsServiceTests.cs
class SubscribedTopicsServiceTests (line 3) | public class SubscribedTopicsServiceTests
method GetService (line 10) | private SubscribedTopicsService GetService()
method AddSubTopic (line 19) | [Fact]
method DoNotAddSubTopicIfAlreadySub (line 32) | [Fact]
method RemoveSubTopic (line 45) | [Fact]
method TryRemoveSubTopic (line 55) | [Fact]
method TryRemoveSubTopicNullTopic (line 65) | [Fact]
method TryRemoveSubTopicNullUser (line 74) | [Fact]
method GetTopicsFromRepo (line 83) | [Fact]
method GetTopicsStartRowCalcd (line 96) | [Fact]
FILE: src/PopForums.Test/Services/TextParsingServiceCleanForumCodeTests.cs
class TextParsingServiceCleanForumCodeTests (line 3) | public class TextParsingServiceCleanForumCodeTests
method GetService (line 5) | private TextParsingService GetService()
method FilterDupeLineBreaks (line 16) | [Fact]
method LeaveNormalLineBreaks (line 24) | [Fact]
method ConvertLonelyCarriageReturn (line 32) | [Fact]
method RemoveImageTagIfImagesDisallowed (line 40) | [Fact]
method AllowWellFormedImageTag (line 49) | [Fact]
method RemoveMalFormedImageTag (line 58) | [Fact]
method CloseUnclosedTag (line 67) | [Fact]
method CloseMultipleUnclosedTags (line 75) | [Fact]
method CleanUpOverlappingTags (line 83) | [Fact]
method CleanUpOverlappingTags2 (line 91) | [Fact]
method ClosingTagWithoutOpener (line 99) | [Fact]
method ClosingTagWithoutOpener2 (line 107) | [Fact]
method UrlTagOk (line 115) | [Fact]
method IgnoreInvalidTag (line 123) | [Fact]
method TagUrlWithProtocol (line 131) | [Fact]
method TagLongUrlWithProtocol (line 139) | [Fact]
method TagWwwUrl (line 147) | [Fact]
method TagLongWwwUrl (line 155) | [Fact]
method TagEmailUrl (line 163) | [Fact]
method EscapeHtml (line 171) | [Fact]
method DontCreateUrlOpenForOrphanCloser (line 179) | [Fact]
method DoubleHttpArchiveUrl (line 187) | [Fact]
method DoubleHttpArchiveUrl2 (line 195) | [Fact]
method YouTubeHttpOnYouTubeDomain (line 203) | [Fact]
method YouTubeHttpOnWwwYouTubeDomain (line 212) | [Fact]
method YouTubeHttpsOnYouTubeDomain (line 221) | [Fact]
method YouTubeHttpsOnWwwYouTubeDomain (line 230) | [Fact]
method YouTubeHttpOnShortYouTubeDomain (line 239) | [Fact]
method YouTubeHttpsOnShortYouTubeDomain (line 248) | [Fact]
method YouTubeDoesntEmbedWhenUrlIsForShorts (line 257) | [Fact]
method YouTubeDoesntEmbedWhenUrlIsForChannel (line 266) | [Fact]
method YouTubeDoesntEmbedWhenUrlIsForPost (line 275) | [Fact]
method YouTubeLinkParsedToLinkWithImagesOff (line 284) | [Fact]
method YouTubeLinkInUrlTagNotParsed (line 293) | [Fact]
FILE: src/PopForums.Test/Services/TextParsingServiceClientHtmlToForumCodeTests.cs
class TextParsingServiceClientHtmlToForumCodeTests (line 5) | public class TextParsingServiceClientHtmlToForumCodeTests
method GetService (line 7) | private TextParsingService GetService()
method RemoveLineBreaks (line 18) | [Fact]
method RemoveEmptyLinesWithOnlySpace (line 26) | [Fact]
method DitchStartAndEndPara (line 34) | [Fact]
method PutQuoteOnItsOwnLines (line 42) | [Fact]
method StartAndEndParaWithBreaks (line 50) | [Fact]
method SingleLineBreaks (line 58) | [Fact]
method LineBreakInAndOutOfQuote (line 66) | [Fact]
method ItalicVariations (line 74) | [Fact]
method BoldVariations (line 82) | [Fact]
method Code (line 90) | [Fact]
method Pre (line 98) | [Fact]
method Li (line 106) | [Fact]
method Ol (line 114) | [Fact]
method Ul (line 122) | [Fact]
method AnchorToUrl (line 130) | [Fact]
method AnchorToUrlWithTarget (line 138) | [Fact]
method AnchorWithDoubleProtocol (line 146) | [Fact]
method AnchorToUrlWithTargetNoQuotes (line 154) | [Fact]
method ImageNoClose (line 162) | [Fact]
method ImageNoCloseNoSpace (line 170) | [Fact]
method ImageNoCloseSpace (line 178) | [Fact]
method ImageOtherAttribute (line 186) | [Fact]
method ImageOtherAttributeAfterSrc (line 196) | [Fact]
method ImageOtherAttributeBeforeAndAfterSrc (line 205) | [Fact]
method NukeInvalidHtml (line 213) | [Fact]
method NukeInvalidHtml2 (line 221) | [Fact]
method ConvertHtmlEscapes (line 229) | [Fact]
method RemoveLineBreaksInList (line 237) | [Fact]
method YouTubeUnparse (line 245) | [Fact]
method YouTubeUnparseHttps (line 253) | [Fact]
method ParseImageWithExtraAttributesLikeAlt (line 261) | [Fact]
method ParseSequentialImages (line 269) | [Fact]
method ParseNonSequentialImages (line 277) | [Fact]
FILE: src/PopForums.Test/Services/TextParsingServiceForumCodeToHtmlTests.cs
class TextParsingServiceForumCodeToHtmlTests (line 3) | public class TextParsingServiceForumCodeToHtmlTests
method GetService (line 5) | private TextParsingService GetService()
method UrlWithQuotes (line 16) | [Fact]
method UrlWithoutQuotes (line 24) | [Fact]
method MailLinkWithQuotes (line 32) | [Fact]
method MailLinkWithoutQuotes (line 40) | [Fact]
method DitchNaughtyJavascriptLinkWithQuotes (line 48) | [Fact]
method DitchNaughtyJavascriptLinkWithoutQuotes (line 56) | [Fact]
method DitchNaughtyJavascriptLinkUpperCase (line 64) | [Fact]
method DitchNaughtyJavascriptLinkMixedCase (line 72) | [Fact]
method ReplaceImageTagsWithQuotes (line 80) | [Fact]
method ReplaceImageTagsWithoutQuotes (line 89) | [Fact]
method RemoveImageTagsWithQuotes (line 98) | [Fact]
method RemoveImageTagsWithoutQuotes (line 107) | [Fact]
method ParseClassicImgTags (line 116) | [Fact]
method ParseAllThreeImageVariants (line 125) | [Fact]
method ReplaceItalic (line 134) | [Fact]
method ReplaceBold (line 142) | [Fact]
method ReplaceCode (line 150) | [Fact]
method ReplacePre (line 158) | [Fact]
method ReplaceLi (line 166) | [Fact]
method ReplaceOl (line 174) | [Fact]
method ReplaceUl (line 182) | [Fact]
method SurroundWithPara (line 190) | [Fact]
method NoParaIfStartsOrEndWithQuote (line 198) | [Fact]
method ReplaceQuote (line 206) | [Fact]
method DoubleLineBreakToParaEndStart (line 214) | [Fact]
method NoDoubleLineBreakToParaEndStartIfAtQuoteEnd (line 222) | [Fact]
method NoDoubleLineBreakToParaEndStartIfAtQuoteStart (line 230) | [Fact]
method EliminateLineBreaksBetweenEndParaAndQuote (line 238) | [Fact]
method EliminateLineBreaksBetweenEndQuoteAndQuote (line 246) | [Fact]
method EliminateLineBreaksBetweenStartAndQuote (line 254) | [Fact]
method CloseParaBeforeQuote (line 262) | [Fact]
method StartInsideOfQuoteWithParaUnlessFirstThingIsSubQuoteOrPara (line 270) | [Fact]
method EndInsideOfQuoteWithParaUnlessFirstThingIsSubQuote (line 278) | [Fact]
method StartParaAfterQuote (line 286) | [Fact]
method RemoveTrailingLineBreaksBetweenEndsOfQuotes (line 294) | [Fact]
method EndParaInQuote (line 302) | [Fact]
method StartParaAfterQuote2 (line 310) | [Fact]
method SingleLineBreak (line 318) | [Fact]
method DoubleHttpArchiveUrl (line 326) | [Fact]
method HttpsAndHttpArchiveUrlWithTextLink (line 334) | [Fact]
method YouTubeTagMainDomainConvertedToIframe (line 342) | [Fact]
method YouTubeTagMainDomainHttpsConvertedToIframe (line 353) | [Fact]
method YouTubeTagShortDomainConvertedToIframe (line 364) | [Fact]
method YouTubeTagShortDomainHttpsConvertedToIframe (line 375) | [Fact]
method YouTubeTagConvertedToIframe (line 386) | [Fact]
method YouTubeTagHttpsConvertedToIframe (line 397) | [Fact]
method YouTubePostUrlParsedAsRegularLink (line 408) | [Fact]
method UrlWithBangParsesCorrectly (line 419) | [Fact]
method UrlWithParenthesesParsesCorrectly (line 427) | [Fact]
method DontParagraphAnEmptyString (line 435) | [Fact]
method UrlWithParenthesesParsed (line 443) | [Fact]
FILE: src/PopForums.Test/Services/TextParsingServiceOtherTests.cs
class TextParsingServiceOtherTests (line 3) | public class TextParsingServiceOtherTests
method GetService (line 5) | private TextParsingService GetService()
method ConvertHtmlQuoteToForumCodeQuote (line 16) | [Fact]
method RemoveAnchorTargets (line 25) | [Fact]
method RemoveYouTubeIframe (line 33) | [Fact]
method RemoveYouTubeIframeHttps (line 41) | [Fact]
method CensorTheNaughty (line 49) | [Fact]
method CensorTheNaughtyCaseInsensitive (line 59) | [Fact]
method CensorEmptyReturnsEmpty (line 69) | [Fact]
method CensorNullReturnsEmpty (line 77) | [Fact]
method ForumCodeToHtmlReturnsEmptyInsteadOfParaTags (line 85) | [Fact]
method ParsedUrlWithParenthesesUnparsed (line 93) | [Fact]
FILE: src/PopForums.Test/Services/TopicServiceTests.cs
class TopicServiceTests (line 3) | public class TopicServiceTests
method GetTopicService (line 17) | private TopicService GetTopicService()
method GetUser (line 33) | private static User GetUser()
method GetTopicsFromRepo (line 38) | [Fact]
method GetTopicsStartRowCalcd (line 51) | [Fact]
method GetTopicsIncludeDeletedCallsRepoCount (line 62) | [Fact]
method GetTopicsNotIncludeDeletedNotCallRepoCount (line 74) | [Fact]
method GetTopicsPagerContextIncludesPageIndexAndCalcdTotalPages (line 85) | [Fact]
method CloseTopicThrowsWithNonMod (line 107) | [Fact]
method CloseTopicClosesWithMod (line 116) | [Fact]
method OpenTopicThrowsWithNonMod (line 128) | [Fact]
method OpenTopicOpensWithMod (line 137) | [Fact]
method PinTopicThrowsWithNonMod (line 149) | [Fact]
method PinTopicPinsWithMod (line 158) | [Fact]
method UnpinTopicThrowsWithNonMod (line 170) | [Fact]
method UnpinTopicUnpinsWithMod (line 179) | [Fact]
method DeleteTopicThrowsWithNonMod (line 191) | [Fact]
method DeleteTopicDeletesWithMod (line 200) | [Fact]
method DeleteTopicUpdatesCounts (line 212) | [Fact]
method DeleteTopicQueuesIndexRemoval (line 225) | [Fact]
method DeleteTopicUpdatesLast (line 245) | [Fact]
method DeleteTopicUpdatesReplyCount (line 258) | [Fact]
method DeleteTopicDeletesWithStarter (line 270) | [Fact]
method UndeleteTopicThrowsWithNonMod (line 281) | [Fact]
method UndeleteTopicUndeletesWithMod (line 290) | [Fact]
method UndeleteTopicUpdatesCounts (line 302) | [Fact]
method UndeleteTopicUpdatesLast (line 315) | [Fact]
method UndeleteQueuesReindex (line 328) | [Fact]
method UndeleteTopicUpdatesReplyCount (line 348) | [Fact]
method UpdateTopicThrowsWithNonMod (line 360) | [Fact]
method UpdateTopicUpdatesTitleWithMod (line 369) | [Fact]
method UpdateTopicQueuesTopicForIndexingWithMod (line 384) | [Fact]
method UpdateTopicMovesTopicWithMod (line 399) | [Fact]
method UpdateTopicWithNewTitleChangesUrlNameOnTopicParameter (line 414) | [Fact]
method UpdateTopicMovesUpdatesCountAndLastOnOldForum (line 428) | [Fact]
method UpdateTopicMovesUpdatesCountAndLastOnNewForum (line 445) | [Fact]
method UpdateLastSetsFieldsFromLastPost (line 462) | [Fact]
method HardDeleteThrowsIfUserNotAdmin (line 473) | [Fact]
method HardDeleteCallsModerationService (line 482) | [Fact]
method HardDeleteCallsSearchIndexRepo (line 492) | [Fact]
method HardDeleteCallsTopiRepoToDeleteTopic (line 510) | [Fact]
method HardDeleteCallsForumServiceToUpdateLastAndCounts (line 520) | [Fact]
method SetAnswerThrowsWhenUserNotTopicStarter (line 533) | [Fact]
method SetAnswerThrowsIfPostIDOfAnswerDoesntExist (line 542) | [Fact]
method SetAnswerThrowsIfPostIsNotPartOfTopic (line 552) | [Fact]
method SetAnswerCallsTopicRepoWithUpdatedValue (line 563) | [Fact]
method SetAnswerCallsEventPubWhenThereIsNoPreviousAnswerOnTheTopic (line 578) | [Fact]
method SetAnswerDoesNotCallEventPubWhenTheAnswerUserDoesNotExist (line 592) | [Fact]
method SetAnswerDoesNotCallEventPubWhenTheTopicAlreadyHasAnAnswer (line 605) | [Fact]
method SetAnswerDoesNotCallEventPubWhenTopicUserIDIsSameAsAnswerUserID (line 619) | [Fact]
method CloseAgedTopicsDoesNothingWhenSettingIsOff (line 632) | [Fact]
method CloseAgedTopicsCallsRepoWhenSettingIsOn (line 643) | [Fact]
method CloseAgedTopicsLogsTopicModeration (line 655) | [Fact]
FILE: src/PopForums.Test/Services/TopicViewLogServiceTests.cs
class TopicViewLogServiceTests (line 3) | public class TopicViewLogServiceTests
method GetService (line 5) | private TopicViewLogService GetService()
method LogViewDoesNotCallRepoWhenConfigIsFalse (line 15) | [Fact]
method LogViewDoesCallsRepoWhenConfigIsTrue (line 26) | [Fact]
FILE: src/PopForums.Test/Services/UserEmailReconcilerTests.cs
class UserEmailReconcilerTests (line 3) | public class UserEmailReconcilerTests
method GetService (line 7) | private UserEmailReconciler GetService()
class GetUniqueEmail (line 13) | public class GetUniqueEmail : UserEmailReconcilerTests
method UnmatchedReturnsSameEmail (line 15) | [Fact]
method MatchedReturnsUniqueEmail (line 27) | [Fact]
FILE: src/PopForums.Test/Services/UserNameReconcilerTests.cs
class UserNameReconcilerTests (line 3) | public class UserNameReconcilerTests
method GetService (line 7) | private UserNameReconciler GetService()
class GetUniqueNameForNewUser (line 13) | public class GetUniqueNameForNewUser : UserNameReconcilerTests
method NoMatchesReturnsSameName (line 15) | [Fact]
method OneMatchesReturnsAppendedName (line 27) | [Fact]
method ThreeMatchesReturnsAppendedName (line 39) | [Fact]
method ThreeMatchesWithOneExtraReturnsAppendedName (line 51) | [Fact]
FILE: src/PopForums.Test/Services/UserServiceTests.cs
class UserServiceTests (line 3) | public class UserServiceTests
method GetMockedUserService (line 18) | private UserService GetMockedUserService()
method SetPassword (line 36) | [Fact]
method CheckPassword (line 50) | [Fact]
method CheckPasswordFail (line 61) | [Fact]
method CheckPasswordHasSalt (line 72) | [Fact]
method CheckPasswordHasSaltFail (line 84) | [Fact]
method CheckPasswordPassesWithoutSaltOnMD5Fallback (line 96) | [Fact]
method CheckPasswordPassesWithSaltOnMD5Fallback (line 108) | [Fact]
method CheckPasswordFailsOnMD5FallbackNoMatch (line 120) | [Fact]
method CheckPasswordFailsMD5FallbackDoesNotCallUpdate (line 132) | [Fact]
method CheckPasswordPassesWithSaltOnMD5FallbackCallsUpdate (line 148) | [Fact]
method GetUser (line 164) | [Fact]
method GetUserFail (line 179) | [Fact]
method GetUserByName (line 190) | [Fact]
method GetUserByNameFail (line 204) | [Fact]
method GetUserByNameReturnsNullWithNullOrEmptyName (line 215) | [Fact]
method GetUserByEmail (line 223) | [Fact]
method GetUserByEmailFail (line 237) | [Fact]
method GetDummyUser (line 248) | public static User GetDummyUser(string name, string email)
method NameIsInUse (line 253) | [Fact]
method EmailIsInUse (line 266) | [Fact]
method EmailInUserByAnotherTrue (line 278) | [Fact]
method EmailInUserByAnotherFalseBecauseSameUser (line 289) | [Fact]
method EmailInUserByAnotherFalseBecauseNoUser (line 300) | [Fact]
method CreateUser (line 311) | [Fact]
method CreateUserFromSignup (line 332) | [Fact]
method CreateInvalidEmail (line 352) | [Fact]
method CreateUsedName (line 360) | [Fact]
method CreateNameNull (line 373) | [Fact]
method CreateNameEmpty (line 380) | [Fact]
method CreateUsedEmail (line 387) | [Fact]
method CreateEmailBanned (line 397) | [Fact]
method CreateIPBanned (line 407) | [Fact]
method UpdateLastActivityDate (line 417) | [Fact]
method ChangeEmailSuccess (line 426) | [Fact]
method ChangeEmailAlreadyInUse (line 444) | [Fact]
method ChangeEmailBad (line 460) | [Fact]
method ChangeEmailMapsIsApprovedFromSettingsToUserRepoCall (line 471) | [Fact]
method ChangeNameSuccess (line 488) | [Fact]
method ChangeNameFailUsed (line 505) | [Fact]
method ChangeNameNull (line 520) | [Fact]
method ChangeNameEmpty (line 529) | [Fact]
method Logout (line 539) | [Fact]
method LoginSuccess (line 548) | [Fact]
method LoginSuccessNoSalt (line 569) | [Fact]
method LoginFail (line 592) | [Fact]
method LoginWithUser (line 609) | [Fact]
method LoginWithUserPersistCookie (line 622) | [Fact]
method GetAllRoles (line 635) | [Fact]
method CreateRole (line 646) | [Fact]
method DeleteRole (line 658) | [Fact]
method DeleteRoleThrowsOnAdminOrMod (line 668) | [Fact]
method UpdateIsApproved (line 679) | [Fact]
method UpdateIsApprovedFalse (line 690) | [Fact]
method UpdateAuthKey (line 701) | [Fact]
method VerifyUserByAuthKey (line 711) | [Fact]
method VerifyUserByAuthKeyFail (line 726) | [Fact]
method SearchByEmail (line 736) | [Fact]
method SearchByName (line 747) | [Fact]
method SearchByRole (line 758) | [Fact]
method GetUserEdit (line 769) | [Fact]
method EditUserProfileOnly (line 781) | [Fact]
method GetReturnedProfile (line 801) | private Profile GetReturnedProfile(UserEdit userEdit)
method EditUserApprovalChange (line 819) | [Fact]
method EditUserNewEmail (line 831) | [Fact]
method EditUserNewPassword (line 843) | [Fact]
method EditUserAddRole (line 855) | [Fact]
method EditUserRemoveRole (line 869) | [Fact]
method EditUserDeleteAvatar (line 883) | [Fact]
method EditUserNoDeleteAvatar (line 899) | [Fact]
method EditUserDeletePhoto (line 916) | [Fact]
method EditUserNoDeletePhoto (line 933) | [Fact]
method EditUserNewAvatar (line 950) | [Fact]
method EditUserNewPhoto (line 968) | [Fact]
method UserEditPhotosDeleteAvatar (line 986) | [Fact]
method UserEditPhotosNoDeleteAvatar (line 1003) | [Fact]
method UserEditPhotosDeletePhoto (line 1020) | [Fact]
method UserEditPhotosNoDeletePhoto (line 1037) | [Fact]
method GetUsersOnlineCallsRepo (line 1054) | [Fact]
method DeleteUserLogs (line 1065) | [Fact]
method DeleteUserCallsRepo (line 1075) | [Fact]
method DeleteUserCallsBanRepoIfBanIsTrue (line 1085) | [Fact]
method DeleteUserDoesNotCallBanRepoIfBanIsFalse (line 1095) | [Fact]
method ForgotPasswordCallsMailerForGoodUser (line 1105) | [Fact]
method ForgotPasswordGeneratesNewAuthKey (line 1115) | [Fact]
method ForgotPasswordThrowsForNoUser (line 1125) | [Fact]
FILE: src/PopForums.Test/Services/UserSessionServiceTests.cs
class UserSessionServiceTests (line 3) | public class UserSessionServiceTests
method GetService (line 10) | private UserSessionService GetService()
method AnonUserNoCookieGetsCookieAndSessionStart (line 20) | [Fact]
method AnonUserWithCookieUpdateSession (line 38) | [Fact]
method UserWithAnonCookieStartsLoggedInSession (line 58) | [Fact]
method AnonUserWithLoggedInSessionEndsOldOneStartsNewOne (line 83) | [Fact]
method UserWithNoCookieGetsCookieAndSessionStart (line 106) | [Fact]
method UserWithCookieUpdateSession (line 126) | [Fact]
method UserSessionNoCookieButHasOldSessionEndsOldSessionStartsNewOne (line 147) | [Fact]
method UserSessionWithNoMatchingIDEndsOldSessionStartsNewOne (line 168) | [Fact]
method CleanExpiredSessions (line 190) | [Fact]
FILE: src/PopForums.Test/Services/UserSessionWorkerTests.cs
class UserSessionWorkerTests (line 5) | public class UserSessionWorkerTests
method GetWorker (line 10) | private UserSessionWorker GetWorker()
method NoErrorNoLog (line 17) | [Fact]
method LogWhenThrows (line 28) | [Fact]
FILE: src/PopForums.Web/Controllers/HomeController.cs
class HomeController (line 5) | public class HomeController : Controller
method Index (line 7) | public IActionResult Index()
FILE: src/PopForums/Composers/ForumStateComposer.cs
type IForumStateComposer (line 3) | public interface IForumStateComposer
method GetState (line 5) | ForumState GetState(Forum forum, PagerContext pagerContext);
class ForumStateComposer (line 8) | public class ForumStateComposer : IForumStateComposer
method GetState (line 10) | public ForumState GetState(Forum forum, PagerContext pagerContext)
FILE: src/PopForums/Composers/PrivateMessageStateComposer.cs
type IPrivateMessageStateComposer (line 3) | public interface IPrivateMessageStateComposer
method GetState (line 5) | Task<PrivateMessageState> GetState(PrivateMessage pm);
class PrivateMessageStateComposer (line 8) | public class PrivateMessageStateComposer : IPrivateMessageStateComposer
method PrivateMessageStateComposer (line 12) | public PrivateMessageStateComposer(IPrivateMessageService privateMessa...
method GetState (line 17) | public async Task<PrivateMessageState> GetState(PrivateMessage pm)
FILE: src/PopForums/Composers/ResourceComposer.cs
type IResourceComposer (line 3) | public interface IResourceComposer
method GetForCurrentThread (line 5) | dynamic GetForCurrentThread();
class ResourceComposer (line 8) | public class ResourceComposer : IResourceComposer
method GetForCurrentThread (line 10) | public dynamic GetForCurrentThread()
FILE: src/PopForums/Composers/TopicStateComposer.cs
type ITopicStateComposer (line 3) | public interface ITopicStateComposer
method GetState (line 5) | Task<TopicState> GetState(Topic topic, int? pageIndex, int? pageCount,...
class TopicStateComposer (line 8) | public class TopicStateComposer : ITopicStateComposer
method TopicStateComposer (line 15) | public TopicStateComposer(IUserRetrievalShim userRetrievalShim, ISetti...
method GetState (line 23) | public async Task<TopicState> GetState(Topic topic, int? pageIndex, in...
FILE: src/PopForums/Configuration/Config.cs
type IConfig (line 3) | public interface IConfig
class Config (line 35) | public class Config : IConfig
method Config (line 37) | public Config(IConfiguration configuration)
FILE: src/PopForums/Configuration/ConfigContainer.cs
class ConfigContainer (line 3) | public class ConfigContainer
FILE: src/PopForums/Configuration/ConfigLoader.cs
class ConfigLoader (line 3) | public class ConfigLoader
method GetConfig (line 5) | public ConfigContainer GetConfig(IConfiguration configuration)
FILE: src/PopForums/Configuration/ErrorLog.cs
type IErrorLog (line 3) | public interface IErrorLog
method Log (line 5) | void Log(Exception exception, ErrorSeverity severity);
method Log (line 6) | void Log(Exception exception, ErrorSeverity severity, string additiona...
method GetErrors (line 7) | List<ErrorLogEntry> GetErrors(int pageIndex, int pageSize, out PagerCo...
method GetErrors (line 8) | PagedList<ErrorLogEntry> GetErrors(int pageIndex, int pageSize);
method DeleteError (line 9) | Task DeleteError(int errorID);
method DeleteAllErrors (line 10) | Task DeleteAllErrors();
class ErrorLog (line 13) | public class ErrorLog : IErrorLog
method ErrorLog (line 15) | public ErrorLog(IErrorLogRepository errorLogRepository)
method Log (line 22) | public void Log(Exception exception, ErrorSeverity severity)
method Log (line 27) | public void Log(Exception exception, ErrorSeverity severity, string ad...
method GetErrors (line 67) | public List<ErrorLogEntry> GetErrors(int pageIndex, int pageSize, out ...
method GetErrors (line 77) | public PagedList<ErrorLogEntry> GetErrors(int pageIndex, int pageSize)
method DeleteError (line 84) | public async Task DeleteError(int errorID)
method DeleteAllErrors (line 89) | public async Task DeleteAllErrors()
FILE: src/PopForums/Configuration/ErrorLogException.cs
class ErrorLogException (line 3) | public class ErrorLogException : Exception
method ErrorLogException (line 5) | public ErrorLogException(string message) : base(message)
FILE: src/PopForums/Configuration/ErrorSeverity.cs
type ErrorSeverity (line 3) | public enum ErrorSeverity
FILE: src/PopForums/Configuration/ICacheHelper.cs
type ICacheHelper (line 3) | public interface ICacheHelper
method SetCacheObject (line 10) | void SetCacheObject(string key, object value);
method SetCacheObject (line 17) | void SetCacheObject(string key, object value, double seconds);
method SetLongTermCacheObject (line 24) | void SetLongTermCacheObject(string key, object value);
method SetPagedListCacheObject (line 33) | void SetPagedListCacheObject<T>(string rootKey, int page, List<T> value);
method RemoveCacheObject (line 38) | void RemoveCacheObject(string key);
method GetCacheObject (line 46) | T GetCacheObject<T>(string key);
method GetPagedListCacheObject (line 48) | List<T> GetPagedListCacheObject<T>(string rootKey, int page);
method GetEffectiveCacheKey (line 58) | string GetEffectiveCacheKey(string key);
FILE: src/PopForums/Configuration/Settings.cs
class Settings (line 3) | public class Settings
method Settings (line 5) | public Settings()
FILE: src/PopForums/Configuration/SettingsManager.cs
type ISettingsManager (line 3) | public interface ISettingsManager
method SaveCurrent (line 6) | void SaveCurrent();
method Save (line 7) | void Save(Settings settings);
class SettingsManager (line 10) | public class SettingsManager : ISettingsManager
method SettingsManager (line 12) | public SettingsManager(ISettingsRepository settingsRepository, IErrorL...
method LoadSettings (line 36) | private void LoadSettings()
method Save (line 74) | public void Save(Settings settings)
method SaveCurrent (line 80) | public void SaveCurrent()
FILE: src/PopForums/Email/EmailQueuePayload.cs
class EmailQueuePayload (line 3) | public class EmailQueuePayload
FILE: src/PopForums/Email/EmailQueuePayloadType.cs
type EmailQueuePayloadType (line 3) | public enum EmailQueuePayloadType
FILE: src/PopForums/Email/EmailWorker.cs
type IEmailWorker (line 3) | public interface IEmailWorker
method Execute (line 5) | Task Execute();
class EmailWorker (line 8) | public class EmailWorker(ISettingsManager settingsManager, ISmtpWrapper ...
method Execute (line 10) | public async Task Execute()
FILE: src/PopForums/Email/ForgotPasswordMailer.cs
type IForgotPasswordMailer (line 3) | public interface IForgotPasswordMailer
method ComposeAndQueue (line 5) | Task ComposeAndQueue(User user, string resetLink);
class ForgotPasswordMailer (line 8) | public class ForgotPasswordMailer : IForgotPasswordMailer
method ForgotPasswordMailer (line 10) | public ForgotPasswordMailer(ISettingsManager settingsManager, IQueuedE...
method ComposeAndQueue (line 19) | public async Task ComposeAndQueue(User user, string resetLink)
FILE: src/PopForums/Email/MailingListComposer.cs
type IMailingListComposer (line 3) | public interface IMailingListComposer
method ComposeAndQueue (line 5) | void ComposeAndQueue(User user, string subject, string body, string ht...
class MailingListComposer (line 8) | public class MailingListComposer : IMailingListComposer
method MailingListComposer (line 10) | public MailingListComposer(ISettingsManager settingsManager, IQueuedEm...
method ComposeAndQueue (line 19) | public void ComposeAndQueue(User user, string subject, string body, st...
FILE: src/PopForums/Email/NewAccountMailer.cs
type INewAccountMailer (line 3) | public interface INewAccountMailer
method Send (line 5) | SmtpStatusCode? Send(User user, string verifyUrl);
class NewAccountMailer (line 31) | public class NewAccountMailer : INewAccountMailer
method NewAccountMailer (line 33) | public NewAccountMailer(ISettingsManager settingsManager, ISmtpWrapper...
method Send (line 42) | public SmtpStatusCode? Send(User user, string verifyUrl)
FILE: src/PopForums/Email/SmtpStatusCode.cs
type SmtpStatusCode (line 3) | public enum SmtpStatusCode
FILE: src/PopForums/Email/SmtpWrapper.cs
type ISmtpWrapper (line 7) | public interface ISmtpWrapper
method Send (line 9) | SmtpStatusCode? Send(EmailMessage message);
class SmtpWrapper (line 12) | public class SmtpWrapper : ISmtpWrapper
method SmtpWrapper (line 14) | public SmtpWrapper(ISettingsManager settingsManager, IErrorLog errorLog)
method Send (line 23) | public SmtpStatusCode? Send(EmailMessage message)
method ConvertEmailMessage (line 62) | private MimeMessage ConvertEmailMessage(EmailMessage forumMessage)
FILE: src/PopForums/Extensions/ServiceCollections.cs
class ServiceCollections (line 3) | public static class ServiceCollections
method AddPopForumsBase (line 5) | public static void AddPopForumsBase(this IServiceCollection services)
FILE: src/PopForums/Extensions/Streams.cs
class Streams (line 3) | public static class Streams
method ToBytes (line 5) | public static byte[] ToBytes(this Stream stream)
FILE: src/PopForums/Extensions/Strings.cs
class Strings (line 3) | public static class Strings
method GetSHA256Hash (line 5) | public static string GetSHA256Hash(this string text)
method GetSHA256Hash (line 19) | public static string GetSHA256Hash(this string text, Guid salt)
method GetMD5Hash (line 25) | public static string GetMD5Hash(this string text)
method GetMD5Hash (line 39) | public static string GetMD5Hash(this string text, Guid salt)
method IsEmailAddress (line 45) | public static bool IsEmailAddress(this string text)
method ToUrlName (line 50) | public static string ToUrlName(this string text)
method ToUniqueUrlName (line 60) | public static string ToUniqueUrlName(this string name, List<string> ma...
method ToUniqueName (line 66) | public static string ToUniqueName(this string name, List<string> match...
method Trimmer (line 83) | public static string Trimmer(this string stringToTrim, int maxLength)
FILE: src/PopForums/Extensions/Users.cs
class Users (line 3) | public static class Users
method IsPostEditable (line 5) | public static bool IsPostEditable(this User user, Post post)
FILE: src/PopForums/ExternalLogin/ExternalAuthenticationResult.cs
class ExternalAuthenticationResult (line 3) | public class ExternalAuthenticationResult
FILE: src/PopForums/ExternalLogin/ExternalLoginInfo.cs
class ExternalLoginInfo (line 3) | public class ExternalLoginInfo
method ExternalLoginInfo (line 5) | public ExternalLoginInfo(string loginProvider, string providerKey,
FILE: src/PopForums/ExternalLogin/ExternalUserAssociation.cs
class ExternalUserAssociation (line 3) | public class ExternalUserAssociation
FILE: src/PopForums/ExternalLogin/ExternalUserAssociationManager.cs
type IExternalUserAssociationManager (line 3) | public interface IExternalUserAssociationManager
method ExternalUserAssociationCheck (line 5) | Task<ExternalUserAssociationMatchResult> ExternalUserAssociationCheck(...
method Associate (line 6) | Task Associate(User user, ExternalLoginInfo externalLoginInfo, string ...
method GetExternalUserAssociations (line 7) | Task<List<ExternalUserAssociation>> GetExternalUserAssociations(User u...
method RemoveAssociation (line 8) | Task RemoveAssociation(User user, int externalUserAssociationID, strin...
class ExternalUserAssociationManager (line 11) | public class ExternalUserAssociationManager : IExternalUserAssociationMa...
method ExternalUserAssociationManager (line 13) | public ExternalUserAssociationManager(IExternalUserAssociationReposito...
method ExternalUserAssociationCheck (line 24) | public async Task<ExternalUserAssociationMatchResult> ExternalUserAsso...
method Associate (line 50) | public async Task Associate(User user, ExternalLoginInfo externalLogin...
method GetExternalUserAssociations (line 67) | public async Task<List<ExternalUserAssociation>> GetExternalUserAssoci...
method RemoveAssociation (line 72) | public async Task RemoveAssociation(User user, int externalUserAssocia...
FILE: src/PopForums/ExternalLogin/ExternalUserAssociationMatchResult.cs
class ExternalUserAssociationMatchResult (line 3) | public class ExternalUserAssociationMatchResult
FILE: src/PopForums/Feeds/FeedService.cs
type IFeedService (line 3) | public interface IFeedService
method PublishToFeed (line 5) | Task PublishToFeed(User user, string message, int points, DateTime tim...
method GetFeed (line 6) | Task<List<FeedEvent>> GetFeed(User user);
class FeedService (line 9) | public class FeedService : IFeedService
method FeedService (line 12) | public FeedService(IFeedRepository feedRepository, IBroker broker)
method PublishToFeed (line 23) | public async Task PublishToFeed(User user, string message, int points,...
method GetFeed (line 32) | public async Task<List<FeedEvent>> GetFeed(User user)
FILE: src/PopForums/Messaging/IBroker.cs
type IBroker (line 3) | public interface IBroker
method NotifyNewPosts (line 5) | void NotifyNewPosts(Topic topic, int lasPostID);
method NotifyForumUpdate (line 6) | void NotifyForumUpdate(Forum forum);
method NotifyTopicUpdate (line 7) | void NotifyTopicUpdate(Topic topic, Forum forum, string topicLink);
method NotifyNewPost (line 8) | void NotifyNewPost(Topic topic, int postID);
method NotifyPMCount (line 9) | void NotifyPMCount(int userID, int pmCount);
method NotifyUser (line 10) | void NotifyUser(Notification notification);
method NotifyUser (line 11) | void NotifyUser(Notification notification, string tenantID);
method SendPMMessage (line 12) | void SendPMMessage(PrivateMessagePost post);
FILE: src/PopForums/Messaging/Models/AwardData.cs
class AwardData (line 3) | public class AwardData
FILE: src/PopForums/Messaging/Models/AwardPayload.cs
class AwardPayload (line 3) | public class AwardPayload
FILE: src/PopForums/Messaging/Models/QuestionData.cs
class QuestionData (line 3) | public class QuestionData
FILE: src/PopForums/Messaging/Models/ReplyData.cs
class ReplyData (line 3) | public class ReplyData
FILE: src/PopForums/Messaging/Models/ReplyPayload.cs
class ReplyPayload (line 3) | public class ReplyPayload
FILE: src/PopForums/Messaging/Models/VoteData.cs
class VoteData (line 3) | public class VoteData
FILE: src/PopForums/Messaging/Notification.cs
class Notification (line 3) | public class Notification
FILE: src/PopForums/Messaging/NotificationAdapter.cs
type INotificationAdapter (line 5) | public interface INotificationAdapter
method Reply (line 7) | Task Reply(string postName, string title, int topicID, int userID, str...
method Vote (line 8) | Task Vote(string voterName, string title, int postID, int userID);
method QuestionAnswer (line 9) | Task QuestionAnswer(string askerName, string title, int postID, int us...
method Award (line 10) | Task Award(string title, int userID);
method Award (line 11) | Task Award(string title, int userID, string tenantID);
class NotificationAdapter (line 14) | public class NotificationAdapter : INotificationAdapter
method NotificationAdapter (line 18) | public NotificationAdapter(INotificationManager notificationManager)
method Reply (line 23) | public async Task Reply(string postName, string title, int topicID, in...
method Vote (line 34) | public async Task Vote(string voterName, string title, int postID, int...
method QuestionAnswer (line 45) | public async Task QuestionAnswer(string askerName, string title, int p...
method Award (line 56) | public async Task Award(string title, int userID)
method Award (line 61) | public async Task Award(string title, int userID, string tenantID)
FILE: src/PopForums/Messaging/NotificationManager.cs
type INotificationManager (line 3) | public interface INotificationManager
method MarkNotificationRead (line 5) | Task MarkNotificationRead(int userID, NotificationType notificationTyp...
method ProcessNotification (line 6) | Task ProcessNotification(int userID, NotificationType notificationType...
method ProcessNotification (line 7) | Task ProcessNotification(int userID, NotificationType notificationType...
method GetUnreadNotificationCount (line 8) | Task<int> GetUnreadNotificationCount(int userID);
method MarkAllRead (line 9) | Task MarkAllRead(int userID);
method GetNotifications (line 10) | Task<List<Notification>> GetNotifications(int userID, DateTime afterDa...
class NotificationManager (line 13) | public class NotificationManager : INotificationManager
method NotificationManager (line 20) | public NotificationManager(INotificationRepository notificationReposit...
method ProcessNotification (line 26) | public async Task ProcessNotification(int userID, NotificationType not...
method ProcessNotification (line 31) | public async Task ProcessNotification(int userID, NotificationType not...
method MarkNotificationRead (line 55) | public async Task MarkNotificationRead(int userID, NotificationType no...
method GetNotifications (line 60) | public async Task<List<Notification>> GetNotifications(int userID, Dat...
method GetUnreadNotificationCount (line 65) | public async Task<int> GetUnreadNotificationCount(int userID)
method MarkAllRead (line 71) | public async Task MarkAllRead(int userID)
FILE: src/PopForums/Messaging/NotificationTunnel.cs
type INotificationTunnel (line 3) | public interface INotificationTunnel
method SendNotificationForUserAward (line 5) | void SendNotificationForUserAward(string title, int userID, string ten...
method SendNotificationForReply (line 6) | void SendNotificationForReply(string postName, string title, int topic...
class NotificationTunnel (line 9) | public class NotificationTunnel : INotificationTunnel
method NotificationTunnel (line 15) | public NotificationTunnel(INotificationAdapter notificationAdapter)
method SendNotificationForUserAward (line 20) | public async void SendNotificationForUserAward(string title, int userI...
method SendNotificationForReply (line 25) | public async void SendNotificationForReply(string postName, string tit...
FILE: src/PopForums/Messaging/NotificationType.cs
type NotificationType (line 3) | public enum NotificationType
FILE: src/PopForums/Models/AwardCalculationPayload.cs
class AwardCalculationPayload (line 3) | public class AwardCalculationPayload
FILE: src/PopForums/Models/BasicJsonMessage.cs
class BasicJsonMessage (line 3) | public class BasicJsonMessage
FILE: src/PopForums/Models/BasicServiceResponse.cs
class BasicServiceResponse (line 3) | public class BasicServiceResponse<T> where T : class
FILE: src/PopForums/Models/CategorizedForumContainer.cs
class CategorizedForumContainer (line 3) | public class CategorizedForumContainer
method CategorizedForumContainer (line 5) | public CategorizedForumContainer(IEnumerable<Category> categories, IEn...
FILE: src/PopForums/Models/Category.cs
class Category (line 3) | public class Category
FILE: src/PopForums/Models/CategoryContainerWithForums.cs
class CategoryContainerWithForums (line 3) | public class CategoryContainerWithForums
FILE: src/PopForums/Models/ClientPrivateMessagePost.cs
class ClientPrivateMessagePost (line 3) | public class ClientPrivateMessagePost
method MapForClient (line 11) | public static ClientPrivateMessagePost[] MapForClient(List<PrivateMess...
method MapForClient (line 17) | public static ClientPrivateMessagePost MapForClient(PrivateMessagePost...
FILE: src/PopForums/Models/DisplayProfile.cs
class DisplayProfile (line 3) | public class DisplayProfile
method DisplayProfile (line 5) | public DisplayProfile(User user, Profile profile, UserImage userImage)
FILE: src/PopForums/Models/EmailMessage.cs
class EmailMessage (line 3) | public class EmailMessage
FILE: src/PopForums/Models/ErrorLogEntry.cs
class ErrorLogEntry (line 3) | public class ErrorLogEntry
FILE: src/PopForums/Models/ExpiredUserSession.cs
class ExpiredUserSession (line 3) | public class ExpiredUserSession
FILE: src/PopForums/Models/FeedEvent.cs
class FeedEvent (line 3) | public class FeedEvent
FILE: src/PopForums/Models/Forum.cs
class Forum (line 3) | public class Forum
FILE: src/PopForums/Models/ForumPermissionContainer.cs
class ForumPermissionContainer (line 3) | public class ForumPermissionContainer
FILE: src/PopForums/Models/ForumPermissionContext.cs
class ForumPermissionContext (line 3) | public class ForumPermissionContext
FILE: src/PopForums/Models/ForumState.cs
class ForumState (line 3) | public class ForumState
FILE: src/PopForums/Models/ForumTopicContainer.cs
class ForumTopicContainer (line 3) | public class ForumTopicContainer : PagedTopicContainer
FILE: src/PopForums/Models/IPHistoryEvent.cs
class IPHistoryEvent (line 3) | public class IPHistoryEvent
FILE: src/PopForums/Models/IStreamResponse.cs
type IStreamResponse (line 10) | public interface IStreamResponse : IDisposable
FILE: src/PopForums/Models/Ignore.cs
class Ignore (line 3) | public class Ignore
class IgnoreWithName (line 9) | public class IgnoreWithName : Ignore
FILE: src/PopForums/Models/ModerationLogEntry.cs
class ModerationLogEntry (line 3) | public class ModerationLogEntry
FILE: src/PopForums/Models/ModerationType.cs
type ModerationType (line 3) | public enum ModerationType
FILE: src/PopForums/Models/ModifyForumRolesContainer.cs
class ModifyForumRolesContainer (line 3) | public class ModifyForumRolesContainer
FILE: src/PopForums/Models/ModifyForumRolesType.cs
type ModifyForumRolesType (line 3) | public enum ModifyForumRolesType
FILE: src/PopForums/Models/NewPost.cs
class NewPost (line 3) | public class NewPost
FILE: src/PopForums/Models/PagedListOfT.cs
class PagedList (line 3) | public class PagedList<T> : PagerContext where T : class
FILE: src/PopForums/Models/PagedTopicContainer.cs
class PagedTopicContainer (line 3) | public class Pag
Condensed preview — 575 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,204K chars).
[
{
"path": ".github/workflows/codeql.yml",
"chars": 4743,
"preview": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# Y"
},
{
"path": ".gitignore",
"chars": 542,
"preview": "packages\n/.vs/config\n/.vs\n/*.user\n*.user\n.idea\n.idea/.idea.PopForums/.idea\n.idea/.idea.PopForums/riderModule.iml\n.DS_Sto"
},
{
"path": "CLAUDE.md",
"chars": 5967,
"preview": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## "
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3210,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "LICENSE.txt",
"chars": 1664,
"preview": "POP Forums\r\nCopyright (c)1999-2023, POP World Media, LLC and Jeffrey M. Putz\r\nhttps://popw.com/\r\nhttps://jeffputz.com/\r\n"
},
{
"path": "NuGet.config",
"chars": 515,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n\t<activePackageSource>\n\t\t<add key=\"All\" value=\"(Aggregate source"
},
{
"path": "PopForums.sln",
"chars": 6278,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.2880"
},
{
"path": "PopForums.sln.DotSettings",
"chars": 947,
"preview": "<wpf:ResourceDictionary xml:space=\"preserve\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:s=\"clr-namesp"
},
{
"path": "README.md",
"chars": 1869,
"preview": "\n\nPOP Forums\n=========\n\nA forum and Q&A ap"
},
{
"path": "SECURITY.md",
"chars": 451,
"preview": "# Security Policy\n\n## Supported Versions\n\nUse this section to tell people about which versions of your project are\ncurre"
},
{
"path": "docs/_config.yml",
"chars": 209,
"preview": "remote_theme: just-the-docs/just-the-docs@v0.10.1\naux_links:\n \"POP Forums on GitHub\":\n - \"https://github.com/POPWorl"
},
{
"path": "docs/architecture.md",
"chars": 7453,
"preview": "---\nlayout: default\ntitle: Architecture\nnav_order: 2.5\n---\n# POP Forums Architecture\n\nForums are a text-driven medium in"
},
{
"path": "docs/azurekitlibrary.md",
"chars": 16054,
"preview": "---\nlayout: default\ntitle: Using Azure Kit Library\nnav_order: 6\n---\n# Using AzureKit Library\nThe `PopForums.AzureKit` li"
},
{
"path": "docs/customization.md",
"chars": 5723,
"preview": "---\nlayout: default\ntitle: Customization\nnav_order: 2.5\n---\n# Customization\n\nPOP Forums is fairly easy to customize to m"
},
{
"path": "docs/elastickitlibrary.md",
"chars": 3512,
"preview": "---\nlayout: default\ntitle: Using ElasticKit Library\nnav_order: 7\n---\n# Using ElasticKit Library\nThe `PopForums.ElasticKi"
},
{
"path": "docs/externalloginconfig.md",
"chars": 2830,
"preview": "---\nlayout: default\ntitle: External Login Configuration\nnav_order: 5\n---\n# External Login Configuration\n\n>Important: Ext"
},
{
"path": "docs/faq.md",
"chars": 5739,
"preview": "---\nlayout: default\ntitle: FAQ\nnav_order: 3\n---\n# Frequently Asked Questions\n\nThese are a few of the questions people as"
},
{
"path": "docs/features.md",
"chars": 2017,
"preview": "---\nlayout: default\ntitle: Features\nnav_order: 1.5\n---\n# Features\n\n## Classic forum functionality\n* Categories, forums, "
},
{
"path": "docs/index.md",
"chars": 2070,
"preview": "---\nlayout: default\ntitle: Home\nnav_order: 1\n---\n;\n}\n\npublic class Re"
},
{
"path": "src/PopForums/Composers/TopicStateComposer.cs",
"chars": 1517,
"preview": "namespace PopForums.Composers;\n\npublic interface ITopicStateComposer\n{\n\tTask<TopicState> GetState(Topic topic, int? pag"
},
{
"path": "src/PopForums/Configuration/Config.cs",
"chars": 3277,
"preview": "namespace PopForums.Configuration;\n\npublic interface IConfig\n{\n\tstring DatabaseConnectionString { get; }\n\tint CacheSeco"
},
{
"path": "src/PopForums/Configuration/ConfigContainer.cs",
"chars": 1366,
"preview": "namespace PopForums.Configuration;\n\npublic class ConfigContainer\n{\n\tpublic string DatabaseConnectionString { get; set; "
},
{
"path": "src/PopForums/Configuration/ConfigLoader.cs",
"chars": 3082,
"preview": "namespace PopForums.Configuration;\n\npublic class ConfigLoader\n{\n\tpublic ConfigContainer GetConfig(IConfiguration config"
},
{
"path": "src/PopForums/Configuration/ErrorLog.cs",
"chars": 2954,
"preview": "namespace PopForums.Configuration;\n\npublic interface IErrorLog\n{\n\tvoid Log(Exception exception, ErrorSeverity severity);"
},
{
"path": "src/PopForums/Configuration/ErrorLogException.cs",
"chars": 225,
"preview": "namespace PopForums.Configuration;\n\npublic class ErrorLogException : Exception\n{\n\tpublic ErrorLogException(string messag"
},
{
"path": "src/PopForums/Configuration/ErrorSeverity.cs",
"chars": 147,
"preview": "namespace PopForums.Configuration;\n\npublic enum ErrorSeverity\n{\n\tCritical = 1,\n\tWarning = 2,\n\tInformation = 3,\n\tDebug = "
},
{
"path": "src/PopForums/Configuration/ICacheHelper.cs",
"chars": 2269,
"preview": "namespace PopForums.Configuration;\n\npublic interface ICacheHelper\n{\n\t/// <summary>\n\t/// Saves an object to cache using h"
},
{
"path": "src/PopForums/Configuration/Settings.cs",
"chars": 4852,
"preview": "namespace PopForums.Configuration;\n\npublic class Settings\n{\n\tpublic Settings()\n\t{\n\t\tTermsOfService = string.Empty;\n\t\tIsN"
},
{
"path": "src/PopForums/Configuration/SettingsManager.cs",
"chars": 2283,
"preview": "namespace PopForums.Configuration;\n\npublic interface ISettingsManager\n{\n\tSettings Current { get; }\n\tvoid SaveCurrent();"
},
{
"path": "src/PopForums/Email/EmailQueuePayload.cs",
"chars": 276,
"preview": "namespace PopForums.Email;\n\npublic class EmailQueuePayload\n{\n\tpublic int MessageID { get; set; }\n\tpublic EmailQueuePayl"
},
{
"path": "src/PopForums/Email/EmailQueuePayloadType.cs",
"chars": 125,
"preview": "namespace PopForums.Email;\n\npublic enum EmailQueuePayloadType\n{\n\tFullMessage = 1,\n\tMassMessage = 2,\n\tDeleteMassMessage "
},
{
"path": "src/PopForums/Email/EmailWorker.cs",
"chars": 1713,
"preview": "namespace PopForums.Email;\n\npublic interface IEmailWorker\n{\n\tTask Execute();\n}\n\npublic class EmailWorker(ISettingsManage"
},
{
"path": "src/PopForums/Email/ForgotPasswordMailer.cs",
"chars": 1209,
"preview": "namespace PopForums.Email;\n\npublic interface IForgotPasswordMailer\n{\n\tTask ComposeAndQueue(User user, string resetLink);"
},
{
"path": "src/PopForums/Email/MailingListComposer.cs",
"chars": 1195,
"preview": "namespace PopForums.Email;\n\npublic interface IMailingListComposer\n{\n\tvoid ComposeAndQueue(User user, string subject, st"
},
{
"path": "src/PopForums/Email/NewAccountMailer.cs",
"chars": 2438,
"preview": "namespace PopForums.Email;\n\npublic interface INewAccountMailer\n{\n\tSmtpStatusCode? Send(User user, string verifyUrl);\n\n\t"
},
{
"path": "src/PopForums/Email/SmtpStatusCode.cs",
"chars": 1037,
"preview": "namespace PopForums.Email;\n\npublic enum SmtpStatusCode\n{\n\tSystemStatus = 211,\n\tHelpMessage = 214,\n\tServiceReady = 220,\n"
},
{
"path": "src/PopForums/Email/SmtpWrapper.cs",
"chars": 2559,
"preview": "using MailKit.Net.Smtp;\nusing MailKit.Security;\nusing MimeKit;\n\nnamespace PopForums.Email;\n\npublic interface ISmtpWrapp"
},
{
"path": "src/PopForums/Extensions/ServiceCollections.cs",
"chars": 4424,
"preview": "namespace PopForums.Extensions;\n\npublic static class ServiceCollections\n{\n\tpublic static void AddPopForumsBase(this ISe"
},
{
"path": "src/PopForums/Extensions/Streams.cs",
"chars": 244,
"preview": "namespace PopForums.Extensions;\n\npublic static class Streams\n{\n\tpublic static byte[] ToBytes(this Stream stream)\n\t{\n\t\tv"
},
{
"path": "src/PopForums/Extensions/Strings.cs",
"chars": 2423,
"preview": "namespace PopForums.Extensions;\n\npublic static class Strings\n{\n\tpublic static string GetSHA256Hash(this string text)\n\t{"
},
{
"path": "src/PopForums/Extensions/Users.cs",
"chars": 248,
"preview": "namespace PopForums.Extensions;\n\npublic static class Users\n{\n\tpublic static bool IsPostEditable(this User user, Post po"
},
{
"path": "src/PopForums/ExternalLogin/ExternalAuthenticationResult.cs",
"chars": 228,
"preview": "namespace PopForums.ExternalLogin;\n\npublic class ExternalAuthenticationResult\n{\n\tpublic string Issuer { get; set; }\n\tpu"
},
{
"path": "src/PopForums/ExternalLogin/ExternalLoginInfo.cs",
"chars": 400,
"preview": "namespace PopForums.ExternalLogin;\n\npublic class ExternalLoginInfo\n{\n\tpublic ExternalLoginInfo(string loginProvider, st"
},
{
"path": "src/PopForums/ExternalLogin/ExternalUserAssociation.cs",
"chars": 273,
"preview": "namespace PopForums.ExternalLogin;\n\npublic class ExternalUserAssociation\n{\n\tpublic int ExternalUserAssociationID { get;"
},
{
"path": "src/PopForums/ExternalLogin/ExternalUserAssociationManager.cs",
"chars": 4385,
"preview": "namespace PopForums.ExternalLogin;\n\npublic interface IExternalUserAssociationManager\n{\n\tTask<ExternalUserAssociationMat"
},
{
"path": "src/PopForums/ExternalLogin/ExternalUserAssociationMatchResult.cs",
"chars": 228,
"preview": "namespace PopForums.ExternalLogin;\n\npublic class ExternalUserAssociationMatchResult\n{\n\tpublic bool Successful { get; se"
},
{
"path": "src/PopForums/Feeds/FeedService.cs",
"chars": 966,
"preview": "namespace PopForums.Feeds;\n\npublic interface IFeedService\n{\n\tTask PublishToFeed(User user, string message, int points, D"
},
{
"path": "src/PopForums/Global.cs",
"chars": 985,
"preview": "global using System;\nglobal using System.Collections;\nglobal using System.Collections.Generic;\nglobal using System.IO;\n"
},
{
"path": "src/PopForums/Messaging/IBroker.cs",
"chars": 463,
"preview": "namespace PopForums.Messaging;\n\npublic interface IBroker\n{\n\tvoid NotifyNewPosts(Topic topic, int lasPostID);\n\tvoid Noti"
},
{
"path": "src/PopForums/Messaging/Models/AwardData.cs",
"chars": 101,
"preview": "namespace PopForums.Messaging.Models;\n\npublic class AwardData\n{\n\tpublic string Title { get; set; }\n}"
},
{
"path": "src/PopForums/Messaging/Models/AwardPayload.cs",
"chars": 175,
"preview": "namespace PopForums.Messaging.Models;\n\npublic class AwardPayload\n{\n\tpublic string Title { get; set; }\n\tpublic int UserI"
},
{
"path": "src/PopForums/Messaging/Models/QuestionData.cs",
"chars": 176,
"preview": "namespace PopForums.Messaging.Models;\n\npublic class QuestionData\n{\n\tpublic string AskerName { get; set; }\n\tpublic strin"
},
{
"path": "src/PopForums/Messaging/Models/ReplyData.cs",
"chars": 173,
"preview": "namespace PopForums.Messaging.Models;\n\npublic class ReplyData\n{\n\tpublic string PostName { get; set; }\n\tpublic int Topic"
},
{
"path": "src/PopForums/Messaging/Models/ReplyPayload.cs",
"chars": 247,
"preview": "namespace PopForums.Messaging.Models;\n\npublic class ReplyPayload\n{\n\tpublic string PostName { get; set; }\n\tpublic string"
},
{
"path": "src/PopForums/Messaging/Models/VoteData.cs",
"chars": 172,
"preview": "namespace PopForums.Messaging.Models;\n\npublic class VoteData\n{\n\tpublic string VoterName { get; set; }\n\tpublic string Ti"
},
{
"path": "src/PopForums/Messaging/Notification.cs",
"chars": 340,
"preview": "namespace PopForums.Messaging;\n\npublic class Notification\n{\n\tpublic int UserID { get; set; }\n\tpublic DateTime TimeStamp"
},
{
"path": "src/PopForums/Messaging/NotificationAdapter.cs",
"chars": 2025,
"preview": "using PopForums.Messaging.Models;\n\nnamespace PopForums.Messaging;\n\npublic interface INotificationAdapter\n{\n\tTask Reply("
},
{
"path": "src/PopForums/Messaging/NotificationManager.cs",
"chars": 2808,
"preview": "namespace PopForums.Messaging;\n\npublic interface INotificationManager\n{\n\tTask MarkNotificationRead(int userID, Notifica"
},
{
"path": "src/PopForums/Messaging/NotificationTunnel.cs",
"chars": 907,
"preview": "namespace PopForums.Messaging;\n\npublic interface INotificationTunnel\n{\n\tvoid SendNotificationForUserAward(string title,"
},
{
"path": "src/PopForums/Messaging/NotificationType.cs",
"chars": 127,
"preview": "namespace PopForums.Messaging;\n\npublic enum NotificationType\n{\n\tNewReply = 0,\n\tVoteUp = 1,\n\tQuestionAnswered = 2,\n\tAwar"
},
{
"path": "src/PopForums/Models/AwardCalculationPayload.cs",
"chars": 188,
"preview": "namespace PopForums.Models;\n\npublic class AwardCalculationPayload\n{\n\tpublic string EventDefinitionID { get; set; }\n\tpub"
},
{
"path": "src/PopForums/Models/BasicJsonMessage.cs",
"chars": 206,
"preview": "namespace PopForums.Models;\n\npublic class BasicJsonMessage\n{\n\tpublic bool Result { get; set; }\n\tpublic string Message {"
},
{
"path": "src/PopForums/Models/BasicServiceResponse.cs",
"chars": 230,
"preview": "namespace PopForums.Models;\n\npublic class BasicServiceResponse<T> where T : class\n{\n\tpublic bool IsSuccessful { get; se"
},
{
"path": "src/PopForums/Models/CategorizedForumContainer.cs",
"chars": 1116,
"preview": "namespace PopForums.Models;\n\npublic class CategorizedForumContainer\n{\n\tpublic CategorizedForumContainer(IEnumerable<Cate"
},
{
"path": "src/PopForums/Models/Category.cs",
"chars": 163,
"preview": "namespace PopForums.Models;\n\npublic class Category\n{\n\tpublic int CategoryID { get; set; }\n\tpublic string Title { get; s"
},
{
"path": "src/PopForums/Models/CategoryContainerWithForums.cs",
"chars": 162,
"preview": "namespace PopForums.Models;\n\npublic class CategoryContainerWithForums\n{\n\tpublic Category Category { get; set; }\n\tpublic"
},
{
"path": "src/PopForums/Models/ClientPrivateMessagePost.cs",
"chars": 842,
"preview": "namespace PopForums.Models;\n\npublic class ClientPrivateMessagePost\n{\n\tpublic int PMPostID { get; set; }\n\tpublic int Use"
},
{
"path": "src/PopForums/Models/DisplayProfile.cs",
"chars": 1223,
"preview": "namespace PopForums.Models;\n\npublic class DisplayProfile\n{\n\tpublic DisplayProfile(User user, Profile profile, UserImage "
},
{
"path": "src/PopForums/Models/EmailMessage.cs",
"chars": 316,
"preview": "namespace PopForums.Models;\n\npublic class EmailMessage\n{\n\tpublic string FromName { get; set; }\n\tpublic string ToEmail {"
},
{
"path": "src/PopForums/Models/ErrorLogEntry.cs",
"chars": 344,
"preview": "namespace PopForums.Models;\n\npublic class ErrorLogEntry\n{\n\tpublic int ErrorID { get; set; }\n\tpublic DateTime TimeStamp {"
},
{
"path": "src/PopForums/Models/ExpiredUserSession.cs",
"chars": 174,
"preview": "namespace PopForums.Models;\n\npublic class ExpiredUserSession\n{\n\tpublic int SessionID { get; set; }\n\tpublic int? UserID {"
},
{
"path": "src/PopForums/Models/FeedEvent.cs",
"chars": 199,
"preview": "namespace PopForums.Models;\n\npublic class FeedEvent\n{\n\tpublic int UserID { get; set; }\n\tpublic string Message { get; set"
},
{
"path": "src/PopForums/Models/Forum.cs",
"chars": 590,
"preview": "namespace PopForums.Models;\n\npublic class Forum\n{\n\tpublic int ForumID { get; set; }\n\tpublic int? CategoryID { get; set;"
},
{
"path": "src/PopForums/Models/ForumPermissionContainer.cs",
"chars": 238,
"preview": "namespace PopForums.Models;\n\npublic class ForumPermissionContainer\n{\n\tpublic int ForumID { get; set; }\n\tpublic List<stri"
},
{
"path": "src/PopForums/Models/ForumPermissionContext.cs",
"chars": 231,
"preview": "namespace PopForums.Models;\n\npublic class ForumPermissionContext\n{\n\tpublic bool UserCanView { get; set; }\n\tpublic bool U"
},
{
"path": "src/PopForums/Models/ForumState.cs",
"chars": 163,
"preview": "namespace PopForums.Models;\n\npublic class ForumState\n{\n\tpublic int? ForumID { get; set; }\n\tpublic int PageSize { get; s"
},
{
"path": "src/PopForums/Models/ForumTopicContainer.cs",
"chars": 229,
"preview": "namespace PopForums.Models;\n\npublic class ForumTopicContainer : PagedTopicContainer\n{\n\tpublic Forum Forum { get; set; }"
},
{
"path": "src/PopForums/Models/IPHistoryEvent.cs",
"chars": 277,
"preview": "namespace PopForums.Models;\n\npublic class IPHistoryEvent\n{\n\tpublic DateTime EventTime { get; set; }\n\tpublic string Type"
},
{
"path": "src/PopForums/Models/IStreamResponse.cs",
"chars": 653,
"preview": "namespace PopForums.Models;\n\n/// <summary>\n/// This interface is used to pass a Stream to send to the client. It impleme"
},
{
"path": "src/PopForums/Models/Ignore.cs",
"chars": 200,
"preview": "namespace PopForums.Models;\n\npublic class Ignore\n{\n\tpublic int UserID { get; set; }\n\tpublic int IgnoreUserID { get; set;"
},
{
"path": "src/PopForums/Models/ModerationLogEntry.cs",
"chars": 510,
"preview": "namespace PopForums.Models;\n\npublic class ModerationLogEntry\n{\n\tpublic int ModerationID { get; set; }\n\tpublic DateTime T"
},
{
"path": "src/PopForums/Models/ModerationType.cs",
"chars": 361,
"preview": "namespace PopForums.Models;\n\npublic enum ModerationType\n{\n\tNotSet = 0,\n\tPostEdit = 1,\n\tPostDelete = 2,\n\tPostDeletePerman"
},
{
"path": "src/PopForums/Models/ModifyForumRolesContainer.cs",
"chars": 194,
"preview": "namespace PopForums.Models;\n\npublic class ModifyForumRolesContainer\n{\n\tpublic int ForumID { get; set; }\n\tpublic ModifyF"
},
{
"path": "src/PopForums/Models/ModifyForumRolesType.cs",
"chars": 143,
"preview": "namespace PopForums.Models;\n\npublic enum ModifyForumRolesType\n{\n\tAddView,\n\tRemoveView,\n\tAddPost,\n\tRemovePost,\n\tRemoveAl"
},
{
"path": "src/PopForums/Models/NewPost.cs",
"chars": 501,
"preview": "namespace PopForums.Models;\n\npublic class NewPost\n{\n\tpublic string Title { get; set; }\n\tpublic string FullText { get; s"
},
{
"path": "src/PopForums/Models/PagedListOfT.cs",
"chars": 132,
"preview": "namespace PopForums.Models;\n\npublic class PagedList<T> : PagerContext where T : class\n{\n\tpublic IEnumerable<T> List { g"
},
{
"path": "src/PopForums/Models/PagedTopicContainer.cs",
"chars": 381,
"preview": "namespace PopForums.Models;\n\npublic class PagedTopicContainer\n{\n\tpublic PagedTopicContainer()\n\t{\n\t\tReadStatusLookup = n"
},
{
"path": "src/PopForums/Models/PagerContext.cs",
"chars": 166,
"preview": "namespace PopForums.Models;\n\npublic class PagerContext\n{\n\tpublic int PageCount { get; set; }\n\tpublic int PageIndex { ge"
},
{
"path": "src/PopForums/Models/PasswordResetContainer.cs",
"chars": 225,
"preview": "namespace PopForums.Models;\n\npublic class PasswordResetContainer\n{\n\tpublic bool IsValidUser { get; set; }\n\tpublic string"
},
{
"path": "src/PopForums/Models/PermanentRoles.cs",
"chars": 151,
"preview": "namespace PopForums.Models;\n\npublic static class PermanentRoles\n{\n\tpublic const string Admin = \"Admin\";\n\tpublic const st"
},
{
"path": "src/PopForums/Models/Post.cs",
"chars": 638,
"preview": "namespace PopForums.Models;\n\npublic class Post\n{\n\tpublic int PostID { get; set; }\n\tpublic int TopicID { get; set; }\n\tpu"
},
{
"path": "src/PopForums/Models/PostEdit.cs",
"chars": 459,
"preview": "namespace PopForums.Models;\n\npublic class PostEdit\n{\n\tpublic PostEdit() {}\n\n\tpublic PostEdit(Post post)\n\t{\n\t\tTitle = po"
},
{
"path": "src/PopForums/Models/PostImage.cs",
"chars": 253,
"preview": "namespace PopForums.Models;\n\npublic class PostImage\n{\n\tpublic string ID { get; init; }\n\tpublic DateTime TimeStamp { get"
},
{
"path": "src/PopForums/Models/PostImagePersistPayload.cs",
"chars": 135,
"preview": "namespace PopForums.Models;\n\npublic class PostImagePersistPayload\n{\n\tpublic string Url { get; set; }\n\tpublic string ID "
},
{
"path": "src/PopForums/Models/PostItemContainer.cs",
"chars": 400,
"preview": "namespace PopForums.Models;\n\npublic class PostItemContainer\n{\n\tpublic Post Post { get; set; }\n\tpublic List<int> VotedPo"
},
{
"path": "src/PopForums/Models/PostWithChildren.cs",
"chars": 183,
"preview": "namespace PopForums.Models;\n\npublic class PostWithChildren\n{\n\tpublic Post Post { get; set; }\n\tpublic List<Post> Childre"
},
{
"path": "src/PopForums/Models/PrivateMessage.cs",
"chars": 783,
"preview": "namespace PopForums.Models;\n\npublic class PrivateMessage\n{\n\tpublic int PMID { get; set; }\n\tpublic DateTime LastPostTime"
},
{
"path": "src/PopForums/Models/PrivateMessageBoxType.cs",
"chars": 92,
"preview": "namespace PopForums.Models;\n\npublic enum PrivateMessageBoxType\n{\n\tInbox = 1,\n\tArchive = 2\n}"
},
{
"path": "src/PopForums/Models/PrivateMessagePost.cs",
"chars": 276,
"preview": "namespace PopForums.Models;\n\npublic class PrivateMessagePost\n{\n\tpublic int PMPostID { get; set; }\n\tpublic int PMID { ge"
},
{
"path": "src/PopForums/Models/PrivateMessageState.cs",
"chars": 277,
"preview": "namespace PopForums.Models;\n\npublic class PrivateMessageState\n{\n\tpublic int PmID { get; set; }\n\tpublic JsonElement User"
},
{
"path": "src/PopForums/Models/PrivateMessageUser.cs",
"chars": 211,
"preview": "namespace PopForums.Models;\n\npublic class PrivateMessageUser\n{\n\tpublic int PMID { get; set; }\n\tpublic int UserID { get;"
},
{
"path": "src/PopForums/Models/PrivateMessageView.cs",
"chars": 165,
"preview": "namespace PopForums.Models;\n\npublic class PrivateMessageView\n{\n\tpublic PrivateMessage PrivateMessage { get; set; }\n\tpub"
},
{
"path": "src/PopForums/Models/Profile.cs",
"chars": 688,
"preview": "namespace PopForums.Models;\n\npublic class Profile\n{\n\tpublic int UserID { get; set; }\n\tpublic bool IsSubscribed { get; s"
},
{
"path": "src/PopForums/Models/QAPostItemContainer.cs",
"chars": 142,
"preview": "namespace PopForums.Models;\n\npublic class QAPostItemContainer : PostItemContainer\n{\n\tpublic PostWithChildren PostWithCh"
},
{
"path": "src/PopForums/Models/QueuedEmailMessage.cs",
"chars": 156,
"preview": "namespace PopForums.Models;\n\npublic class QueuedEmailMessage : EmailMessage\n{\n\tpublic int MessageID { get; set; }\n\tpubli"
},
{
"path": "src/PopForums/Models/ReadStatus.cs",
"chars": 149,
"preview": "namespace PopForums.Models;\n\n[Flags]\npublic enum ReadStatus\n{\n\tNoNewPosts = 1,\n\tNewPosts = 2,\n\tClosed = 4,\n\tOpen = 8,\n\tP"
},
{
"path": "src/PopForums/Models/ResponseOfT.cs",
"chars": 1123,
"preview": "namespace PopForums.Models;\n\n/// <summary>\n/// A generic container for wrapping the response of external calls for cons"
},
{
"path": "src/PopForums/Models/SearchIndexPayload.cs",
"chars": 177,
"preview": "namespace PopForums.Models;\n\npublic class SearchIndexPayload\n{\n\tpublic int TopicID { get; set; }\n\tpublic string TenantI"
},
{
"path": "src/PopForums/Models/SearchType.cs",
"chars": 94,
"preview": "namespace PopForums.Models;\n\npublic enum SearchType\n{\n\tRank,\n\tDate,\n\tTitle,\n\tName,\n\tReplies\n}"
},
{
"path": "src/PopForums/Models/SearchWord.cs",
"chars": 156,
"preview": "namespace PopForums.Models;\n\npublic class SearchWord\n{\n\tpublic string Word { get; set; }\n\tpublic int TopicID { get; set"
},
{
"path": "src/PopForums/Models/SecurityLogEntry.cs",
"chars": 411,
"preview": "namespace PopForums.Models;\n\npublic class SecurityLogEntry\n{\n\tpublic int SecurityLogID { get; set; }\n\tpublic SecurityLog"
},
{
"path": "src/PopForums/Models/SecurityLogType.cs",
"chars": 585,
"preview": "namespace PopForums.Models;\n\npublic enum SecurityLogType\n{\n\tUndefined = 0,\n\tLogin = 1,\n\tLogout = 2,\n\tPasswordChange = 3,"
},
{
"path": "src/PopForums/Models/ServiceHeartbeat.cs",
"chars": 184,
"preview": "namespace PopForums.Models;\n\npublic class ServiceHeartbeat\n{\n\tpublic string ServiceName { get; set; }\n\tpublic string Ma"
},
{
"path": "src/PopForums/Models/SetupVariables.cs",
"chars": 480,
"preview": "namespace PopForums.Models;\n\npublic class SetupVariables\n{\n\tpublic string Name { get; set; }\n\tpublic string Email { get"
},
{
"path": "src/PopForums/Models/SignupData.cs",
"chars": 493,
"preview": "namespace PopForums.Models;\n\npublic class SignupData\n{\n\tpublic string Name { get; set; }\n\tpublic string Email { get; se"
},
{
"path": "src/PopForums/Models/SingleString.cs",
"chars": 95,
"preview": "namespace PopForums.Models;\n\npublic class SingleString\n{\n\tpublic string String { get; set; }\n}"
},
{
"path": "src/PopForums/Models/SubscribeNotificationPayload.cs",
"chars": 272,
"preview": "namespace PopForums.Models;\n\npublic class SubscribeNotificationPayload\n{\n\tpublic int TopicID { get; set; }\n\tpublic stri"
},
{
"path": "src/PopForums/Models/TimeFormats.cs",
"chars": 266,
"preview": "namespace PopForums.Models;\n\npublic class TimeFormats\n{\n\tpublic string TodayTime { get; set; }\n\tpublic string Yesterday"
},
{
"path": "src/PopForums/Models/Topic.cs",
"chars": 626,
"preview": "namespace PopForums.Models;\n\npublic class Topic\n{\n\tpublic int TopicID { get; set; }\n\tpublic int ForumID { get; set; }\n\t"
},
{
"path": "src/PopForums/Models/TopicContainer.cs",
"chars": 567,
"preview": "namespace PopForums.Models;\n\npublic class TopicContainer\n{\n\tpublic Forum Forum { get; set; }\n\tpublic Topic Topic { get;"
},
{
"path": "src/PopForums/Models/TopicContainerForQA.cs",
"chars": 213,
"preview": "namespace PopForums.Models;\n\npublic class TopicContainerForQA : TopicContainer\n{\n\tpublic PostWithChildren QuestionPostW"
},
{
"path": "src/PopForums/Models/TopicState.cs",
"chars": 369,
"preview": "namespace PopForums.Models;\n\npublic class TopicState\n{\n\tpublic int TopicID { get; set; }\n\tpublic bool IsImageEnabled { "
},
{
"path": "src/PopForums/Models/TopicUnsubscribeContainer.cs",
"chars": 138,
"preview": "namespace PopForums.Models;\n\npublic class TopicUnsubscribeContainer\n{\n\tpublic User User { get; set; }\n\tpublic Topic Top"
},
{
"path": "src/PopForums/Models/User.cs",
"chars": 513,
"preview": "namespace PopForums.Models;\n\npublic class User\n{\n\tpublic int UserID { get; set; }\n\tpublic DateTime CreationDate { get; "
},
{
"path": "src/PopForums/Models/UserEdit.cs",
"chars": 1522,
"preview": "namespace PopForums.Models;\n\npublic class UserEdit\n{\n\tpublic UserEdit() {}\n\n\tpublic UserEdit(User user, Profile profile)"
},
{
"path": "src/PopForums/Models/UserEditProfile.cs",
"chars": 936,
"preview": "namespace PopForums.Models;\n\npublic class UserEditProfile\n{\n\tpublic UserEditProfile() {}\n\n\tpublic UserEditProfile(Profil"
},
{
"path": "src/PopForums/Models/UserEditSecurity.cs",
"chars": 901,
"preview": "namespace PopForums.Models;\n\npublic class UserEditSecurity\n{\n\tpublic UserEditSecurity() {}\n\n\tpublic UserEditSecurity(Use"
},
{
"path": "src/PopForums/Models/UserImage.cs",
"chars": 201,
"preview": "namespace PopForums.Models;\n\npublic class UserImage\n{\n\tpublic int UserImageID { get; set; }\n\tpublic int UserID { get; s"
},
{
"path": "src/PopForums/Models/UserImageApprovalContainer.cs",
"chars": 282,
"preview": "namespace PopForums.Models;\n\npublic class UserImageApprovalContainer\n{\n\tpublic bool IsNewUserImageApproved { get; set; "
},
{
"path": "src/PopForums/Models/UserResult.cs",
"chars": 235,
"preview": "namespace PopForums.Models;\n\npublic class UserResult\n{\n\tpublic int UserID { get; set; }\n\tpublic string Name { get; set;"
},
{
"path": "src/PopForums/Models/UserSearch.cs",
"chars": 199,
"preview": "namespace PopForums.Models;\n\npublic class UserSearch\n{\n\tpublic string SearchText { get; set; }\n\tpublic UserSearchType Se"
},
{
"path": "src/PopForums/Models/VotePostContainer.cs",
"chars": 181,
"preview": "namespace PopForums.Models;\n\npublic class VotePostContainer\n{\n\tpublic int PostID { get; set; }\n\tpublic int Votes { get; "
},
{
"path": "src/PopForums/PopForums.csproj",
"chars": 1967,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n\t<PropertyGroup>\n\t\t<Description>PopForums Class Library</Description>\n\t\t<VersionPrefi"
},
{
"path": "src/PopForums/Repositories/IAwardCalculationQueueRepository.cs",
"chars": 181,
"preview": "namespace PopForums.Repositories;\n\npublic interface IAwardCalculationQueueRepository\n{\n\tTask Enqueue(AwardCalculationPa"
},
{
"path": "src/PopForums/Repositories/IAwardConditionRepository.cs",
"chars": 400,
"preview": "namespace PopForums.Repositories;\n\npublic interface IAwardConditionRepository\n{\n\tTask<List<AwardCondition>> GetConditio"
},
{
"path": "src/PopForums/Repositories/IAwardDefinitionRepository.cs",
"chars": 393,
"preview": "namespace PopForums.Repositories;\n\npublic interface IAwardDefinitionRepository\n{\n\tTask<AwardDefinition> Get(string awar"
},
{
"path": "src/PopForums/Repositories/IBanRepository.cs",
"chars": 335,
"preview": "namespace PopForums.Repositories;\n\npublic interface IBanRepository\n{\n\tTask BanIP(string ip);\n\tTask RemoveIPBan(string ip"
},
{
"path": "src/PopForums/Repositories/ICategoryRepository.cs",
"chars": 263,
"preview": "namespace PopForums.Repositories;\n\npublic interface ICategoryRepository\n{\n\tTask<Category> Get(int categoryID);\n\tTask<Lis"
},
{
"path": "src/PopForums/Repositories/IEmailQueueRepository.cs",
"chars": 156,
"preview": "namespace PopForums.Repositories;\n\npublic interface IEmailQueueRepository\n{\n\tTask Enqueue(EmailQueuePayload payload);\n\t"
},
{
"path": "src/PopForums/Repositories/IErrorLogRepository.cs",
"chars": 347,
"preview": "namespace PopForums.Repositories;\n\npublic interface IErrorLogRepository\n{\n\tTask<ErrorLogEntry> Create(DateTime timeStamp"
},
{
"path": "src/PopForums/Repositories/IEventDefinitionRepository.cs",
"chars": 263,
"preview": "namespace PopForums.Repositories;\n\npublic interface IEventDefinitionRepository\n{\n\tTask<EventDefinition> Get(string even"
},
{
"path": "src/PopForums/Repositories/IExternalUserAssociationRepository.cs",
"chars": 406,
"preview": "namespace PopForums.Repositories;\n\npublic interface IExternalUserAssociationRepository\n{\n\tTask<ExternalUserAssociation>"
},
{
"path": "src/PopForums/Repositories/IFavoriteTopicsRepository.cs",
"chars": 361,
"preview": "namespace PopForums.Repositories;\n\npublic interface IFavoriteTopicsRepository\n{\n\tTask<List<Topic>> GetFavoriteTopics(in"
},
{
"path": "src/PopForums/Repositories/IFeedRepository.cs",
"chars": 371,
"preview": "namespace PopForums.Repositories;\n\npublic interface IFeedRepository\n{\n\tTask<List<FeedEvent>> GetFeed(int userID, int ite"
},
{
"path": "src/PopForums/Repositories/IForumRepository.cs",
"chars": 3363,
"preview": "namespace PopForums.Repositories;\n\npublic interface IForumRepository\n{\n\tTask<Forum> Get(int forumID);\n\tTask<Forum> Get("
},
{
"path": "src/PopForums/Repositories/IIgnoreRepository.cs",
"chars": 299,
"preview": "namespace PopForums.Repositories;\n\npublic interface IIgnoreRepository\n{\n\tTask AddIgnore(int userID, int ignoreUserID);\n\t"
},
{
"path": "src/PopForums/Repositories/ILastReadRepository.cs",
"chars": 659,
"preview": "namespace PopForums.Repositories;\n\npublic interface ILastReadRepository\n{\n\tTask SetForumRead(int userID, int forumID, Da"
},
{
"path": "src/PopForums/Repositories/IModerationLogRepository.cs",
"chars": 432,
"preview": "namespace PopForums.Repositories;\n\npublic interface IModerationLogRepository\n{\n\tTask Log(DateTime timeStamp, int userID,"
},
{
"path": "src/PopForums/Repositories/INotificationRepository.cs",
"chars": 565,
"preview": "namespace PopForums.Repositories;\n\npublic interface INotificationRepository\n{\n\tTask<int> UpdateNotification(Notificatio"
},
{
"path": "src/PopForums/Repositories/IPointLedgerRepository.cs",
"chars": 224,
"preview": "namespace PopForums.Repositories;\n\npublic interface IPointLedgerRepository\n{\n\tTask RecordEntry(PointLedgerEntry entry);"
},
{
"path": "src/PopForums/Repositories/IPostImageRepository.cs",
"chars": 424,
"preview": "namespace PopForums.Repositories;\n\npublic interface IPostImageRepository\n{\n\tTask<PostImagePersistPayload> Persist(byte["
},
{
"path": "src/PopForums/Repositories/IPostImageTempRepository.cs",
"chars": 221,
"preview": "namespace PopForums.Repositories;\n\npublic interface IPostImageTempRepository\n{\n\tTask Save(Guid postImageTempID, DateTim"
},
{
"path": "src/PopForums/Repositories/IPostRepository.cs",
"chars": 1203,
"preview": "namespace PopForums.Repositories;\n\npublic interface IPostRepository\n{\n\tTask<int> Create(int topicID, int parentPostID, "
},
{
"path": "src/PopForums/Repositories/IPrivateMessageRepository.cs",
"chars": 1046,
"preview": "namespace PopForums.Repositories;\n\npublic interface IPrivateMessageRepository\n{\n\tTask<PrivateMessage> Get(int pmID, int"
},
{
"path": "src/PopForums/Repositories/IProfileRepository.cs",
"chars": 483,
"preview": "namespace PopForums.Repositories;\n\npublic interface IProfileRepository\n{\n\tTask<Profile> GetProfile(int userID);\n\tTask C"
},
{
"path": "src/PopForums/Repositories/IQueuedEmailMessageRepository.cs",
"chars": 229,
"preview": "namespace PopForums.Repositories;\n\npublic interface IQueuedEmailMessageRepository\n{\n\tTask<int> CreateMessage(QueuedEmai"
},
{
"path": "src/PopForums/Repositories/IRoleRepository.cs",
"chars": 272,
"preview": "namespace PopForums.Repositories;\n\npublic interface IRoleRepository\n{\n\tTask CreateRole(string role);\n\tTask<bool> DeleteR"
},
{
"path": "src/PopForums/Repositories/ISearchIndexQueueRepository.cs",
"chars": 164,
"preview": "namespace PopForums.Repositories;\n\npublic interface ISearchIndexQueueRepository\n{\n\tTask Enqueue(SearchIndexPayload payl"
},
{
"path": "src/PopForums/Repositories/ISearchRepository.cs",
"chars": 436,
"preview": "namespace PopForums.Repositories;\n\npublic interface ISearchRepository\n{\n\tTask<List<string>> GetJunkWords();\n\tTask Create"
},
{
"path": "src/PopForums/Repositories/ISecurityLogRepository.cs",
"chars": 295,
"preview": "namespace PopForums.Repositories;\n\npublic interface ISecurityLogRepository\n{\n\tTask Create(SecurityLogEntry logEntry);\n\tT"
},
{
"path": "src/PopForums/Repositories/IServiceHeartbeatRepository.cs",
"chars": 223,
"preview": "namespace PopForums.Repositories;\n\npublic interface IServiceHeartbeatRepository\n{\n\tTask RecordHeartbeat(string serviceN"
},
{
"path": "src/PopForums/Repositories/ISettingsRepository.cs",
"chars": 199,
"preview": "namespace PopForums.Repositories;\n\npublic interface ISettingsRepository\n{\n\tDictionary<string, string> Get();\n\tvoid Save"
},
{
"path": "src/PopForums/Repositories/ISetupRepository.cs",
"chars": 151,
"preview": "namespace PopForums.Repositories;\n\npublic interface ISetupRepository\n{\n\tbool IsConnectionPossible();\n\tbool IsDatabaseSe"
},
{
"path": "src/PopForums/Repositories/ISubscribeNotificationRepository.cs",
"chars": 189,
"preview": "namespace PopForums.Repositories;\n\npublic interface ISubscribeNotificationRepository\n{\n\tTask Enqueue(SubscribeNotificat"
},
{
"path": "src/PopForums/Repositories/ISubscribedTopicsRepository.cs",
"chars": 425,
"preview": "namespace PopForums.Repositories;\n\npublic interface ISubscribedTopicsRepository\n{\n\tTask<List<Topic>> GetSubscribedTopic"
},
{
"path": "src/PopForums/Repositories/ITopicRepository.cs",
"chars": 2039,
"preview": "namespace PopForums.Repositories;\n\npublic interface ITopicRepository\n{\n\tTask<Topic> GetLastUpdatedTopic(int forumID);\n\t"
},
{
"path": "src/PopForums/Repositories/ITopicViewLogRepository.cs",
"chars": 137,
"preview": "namespace PopForums.Repositories;\n\npublic interface ITopicViewLogRepository\n{\n\tTask Log(int? userID, int topicID, DateT"
},
{
"path": "src/PopForums/Repositories/IUserAvatarRepository.cs",
"chars": 451,
"preview": "namespace PopForums.Repositories;\n\npublic interface IUserAvatarRepository\n{\n\t[Obsolete(\"Use GetImageData(int) instead.\""
},
{
"path": "src/PopForums/Repositories/IUserAwardRepository.cs",
"chars": 294,
"preview": "namespace PopForums.Repositories;\n\npublic interface IUserAwardRepository\n{\n\tTask IssueAward(int userID, string awardDef"
},
{
"path": "src/PopForums/Repositories/IUserImageRepository.cs",
"chars": 698,
"preview": "namespace PopForums.Repositories;\n\npublic interface IUserImageRepository\n{\n\t[Obsolete(\"Use GetImageStream instead.\")]\n\t"
},
{
"path": "src/PopForums/Repositories/IUserRepository.cs",
"chars": 4354,
"preview": "namespace PopForums.Repositories;\n\npublic interface IUserRepository\n{\n\t/// <summary>\n\t/// Stores the hashed password in"
},
{
"path": "src/PopForums/Repositories/IUserSessionRepository.cs",
"chars": 481,
"preview": "namespace PopForums.Repositories;\n\npublic interface IUserSessionRepository\n{\n\tTask CreateSession(int sessionID, int? use"
},
{
"path": "src/PopForums/Resources/Resources.Designer.cs",
"chars": 70252,
"preview": "//------------------------------------------------------------------------------\n// <auto-generated>\n// This code w"
},
{
"path": "src/PopForums/Resources/Resources.de.resx",
"chars": 47113,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <!-- \n Microsoft ResX Schema \n \n Version 2.0\n \n The prim"
},
{
"path": "src/PopForums/Resources/Resources.es.resx",
"chars": 47058,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <!-- \n Microsoft ResX Schema \n \n Version 2.0\n \n The prim"
},
{
"path": "src/PopForums/Resources/Resources.fr.resx",
"chars": 45761,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <xsd:schema id=\"root\" xmlns=\"\" xmlns:xsd=\"http://www.w3.org/2001/XMLSch"
},
{
"path": "src/PopForums/Resources/Resources.nl.resx",
"chars": 46798,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <!-- \n Microsoft ResX Schema \n \n Version 2.0\n \n The prim"
},
{
"path": "src/PopForums/Resources/Resources.resx",
"chars": 46064,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <!-- \n Microsoft ResX Schema \n \n Version 2.0\n \n The prim"
},
{
"path": "src/PopForums/Resources/Resources.uk.resx",
"chars": 47298,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <!-- \n Microsoft ResX Schema \n \n Version 2.0\n \n The prim"
},
{
"path": "src/PopForums/Resources/Resources.zh-TW.resx",
"chars": 39451,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root>\n <!-- \n Microsoft ResX Schema \n \n Version 2.0\n \n The prim"
},
{
"path": "src/PopForums/ScoringGame/AwardCalculator.cs",
"chars": 3055,
"preview": "namespace PopForums.ScoringGame;\n\npublic interface IAwardCalculator\n{\n\tTask QueueCalculation(User user, EventDefinition "
},
{
"path": "src/PopForums/ScoringGame/AwardCalculatorWorker.cs",
"chars": 591,
"preview": "namespace PopForums.ScoringGame;\n\npublic interface IAwardCalculatorWorker\n{\n\tvoid Execute();\n}\n\npublic class AwardCalcu"
},
{
"path": "src/PopForums/ScoringGame/AwardCondition.cs",
"chars": 197,
"preview": "namespace PopForums.ScoringGame;\n\npublic class AwardCondition\n{\n\tpublic string AwardDefinitionID { get; set; }\n\tpublic "
},
{
"path": "src/PopForums/ScoringGame/AwardDefinition.cs",
"chars": 235,
"preview": "namespace PopForums.ScoringGame;\n\npublic class AwardDefinition\n{\n\tpublic string AwardDefinitionID { get; set; }\n\tpublic"
},
{
"path": "src/PopForums/ScoringGame/AwardDefinitionService.cs",
"chars": 2745,
"preview": "namespace PopForums.ScoringGame;\n\npublic interface IAwardDefinitionService\n{\n\tTask<AwardDefinition> Get(string awardDef"
},
{
"path": "src/PopForums/ScoringGame/EventDefinition.cs",
"chars": 237,
"preview": "namespace PopForums.ScoringGame;\n\npublic class EventDefinition\n{\n\tpublic string EventDefinitionID { get; set; }\n\tpublic"
},
{
"path": "src/PopForums/ScoringGame/EventDefinitionService.cs",
"chars": 2830,
"preview": "namespace PopForums.ScoringGame;\n\npublic interface IEventDefinitionService\n{\n\tTask<EventDefinition> GetEventDefinition("
},
{
"path": "src/PopForums/ScoringGame/EventPublisher.cs",
"chars": 2397,
"preview": "namespace PopForums.ScoringGame;\n\npublic interface IEventPublisher\n{\n\tTask ProcessEvent(string feedMessage, User user, "
},
{
"path": "src/PopForums/ScoringGame/PointLedgerEntry.cs",
"chars": 222,
"preview": "namespace PopForums.ScoringGame;\n\npublic class PointLedgerEntry\n{\n\tpublic int UserID { get; set; }\n\tpublic string Event"
},
{
"path": "src/PopForums/ScoringGame/UserAward.cs",
"chars": 296,
"preview": "namespace PopForums.ScoringGame;\n\npublic class UserAward\n{\n\tpublic int UserAwardID { get; set; }\n\tpublic int UserID { g"
},
{
"path": "src/PopForums/ScoringGame/UserAwardService.cs",
"chars": 1426,
"preview": "namespace PopForums.ScoringGame;\n\npublic interface IUserAwardService\n{\n\tTask IssueAward(User user, AwardDefinition awar"
}
]
// ... and 375 more files (download for full content)
About this extraction
This page contains the full source code of the POPWorldMedia/POPForums GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 575 files (1.9 MB), approximately 534.6k tokens, and a symbol index with 3436 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.