InvokeAsync()
13 | {
14 | var container = await _userStateComposer.GetState();
15 | return View(container);
16 | }
17 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Account/AccountCreated.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = PopForums.Resources.AccountCreated;
3 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
4 | }
5 |
6 | @PopForums.Resources.AccountCreated
7 |
10 |
11 | @if (ViewData["EmailProblem"] == null)
12 | {
13 | @ViewData["Result"]
14 | }
15 | else
16 | {
17 | @ViewData["EmailProblem"] @ViewData["Result"]
18 | }
19 |
20 | @PopForums.Resources.EditYourProfile
21 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Account/EditAccountNoUser.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = PopForums.Resources.EditAccount;
3 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
4 | }
5 |
6 | @PopForums.Resources.EditAccount
7 |
10 |
11 | @PopForums.Resources.MustBeRegisteredToEditAccount
12 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Account/Forgot.cshtml:
--------------------------------------------------------------------------------
1 | @using PopForums.Configuration
2 | @inject ISettingsManager SettingsManager
3 | @{
4 | ViewBag.Title = PopForums.Resources.ForgotPassword;
5 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
6 | }
7 |
8 | @PopForums.Resources.ForgotPassword
9 | @if (!SettingsManager.Current.IsPrivateForumInstance)
10 | {
11 |
14 | }
15 |
16 | @PopForums.Resources.ForgotInstructions
17 |
18 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Account/MiniUserNotFound.cshtml:
--------------------------------------------------------------------------------
1 | @PopForums.Resources.UserNotFound
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Account/OAuthLogin.cshtml:
--------------------------------------------------------------------------------
1 | @using PopForums
2 | @model string
3 | @inject ISettingsManager SettingsManager
4 |
5 | @{
6 | Layout = null;
7 | }
8 |
9 |
10 |
11 |
12 |
13 | @Resources.Login
14 |
15 |
16 |
17 |
18 |
@SettingsManager.Current.ForumTitle
19 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Account/ResetPasswordSuccess.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = PopForums.Resources.PasswordResetSuccess;
3 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
4 | }
5 |
6 | @PopForums.Resources.PasswordResetSuccess
7 |
10 |
11 | @PopForums.Resources.PasswordResetNote
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Account/Unsubscribe.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = PopForums.Resources.Unsubscribe;
3 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
4 | }
5 |
6 | @PopForums.Resources.Unsubscribe
7 |
10 |
11 | @PopForums.Resources.UnsubscribeNote
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Account/UnsubscribeFailure.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = PopForums.Resources.UnsubscribeFail;
3 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
4 | }
5 |
6 | @PopForums.Resources.UnsubscribeFail
7 |
10 |
11 | @PopForums.Resources.UnsubscribeLinkBad
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Account/VerifyFail.cshtml:
--------------------------------------------------------------------------------
1 | @using PopForums.Configuration
2 | @inject ISettingsManager SettingsManager
3 | @{
4 | ViewBag.Title = PopForums.Resources.VerificationFailure;
5 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
6 | }
7 |
8 | @PopForums.Resources.VerificationFailure
9 | @if (!SettingsManager.Current.IsPrivateForumInstance)
10 | {
11 |
14 | }
15 |
16 | @PopForums.Resources.VerificationLinkBad @PopForums.Resources.NeedToVerifyExistingAccount
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Forum/NewComment.cshtml:
--------------------------------------------------------------------------------
1 | @model NewPost
2 |
3 |
4 |
5 | @PopForums.Resources.CreateNewReply
6 |
7 |
8 |
9 | @Html.HiddenFor(p => p.Title)
10 | @Html.HiddenFor(p => p.IncludeSignature)
11 | @Html.HiddenFor(p => p.ItemID)
12 | @Html.HiddenFor(p => p.IsPlainText)
13 | @Html.HiddenFor(p => p.IsImageEnabled)
14 | @Html.HiddenFor(p => p.ParentPostID)
15 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Forum/NewTopic.cshtml:
--------------------------------------------------------------------------------
1 | @model NewPost
2 |
3 |
4 |
5 | @PopForums.Resources.CreateNewTopic
6 |
7 |
8 | @Html.TextBoxFor(p => p.Title, new {@class = "form-control", placeholder = PopForums.Resources.Title})
9 |
10 |
11 |
12 |
16 |
17 | @Html.HiddenFor(p => p.ItemID)
18 | @Html.HiddenFor(p => p.IsPlainText)
19 | @Html.HiddenFor(p => p.IsImageEnabled)
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Forum/TopicPage.cshtml:
--------------------------------------------------------------------------------
1 | @model TopicContainer
2 | @inject IUserRetrievalShim UserRetrievalShim
3 | @{
4 | var user = UserRetrievalShim.GetUser();
5 | var profile = UserRetrievalShim.GetProfile();
6 | var routeParameters = new Dictionary {{"id", Model.Topic.UrlName}};
7 | }
8 |
9 | @foreach (var post in Model.Posts)
10 | {
11 | @await Html.PartialAsync("~/Areas/Forums/Views/Forum/PostItem.cshtml", new PostItemContainer { Post = post, VotedPostIDs = Model.VotedPostIDs, Signatures = Model.Signatures, Avatars = Model.Avatars, User = user, Profile = profile, Topic = Model.Topic });
12 | }
13 |
14 | @Html.Hidden("LastPostID", Model.Posts.Last().PostID, new { @class = "lastPostID" })
15 | @Html.Hidden("PageCount", Model.PagerContext.PageCount, new { @class = "pageCount" })
16 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Forum/Voters.cshtml:
--------------------------------------------------------------------------------
1 | @model VotePostContainer
2 |
3 | @foreach (var user in Model.Voters)
4 | {
5 | - @Html.ActionLink(user.Value, "ViewProfile", "Account", new { id = user.Key }, new { target = "_blank" })
6 | }
7 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Identity/ExternalError.cshtml:
--------------------------------------------------------------------------------
1 | @model string
2 | @{
3 | ViewBag.Title = PopForums.Resources.Login + " - " + PopForums.Resources.Error;
4 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
5 | }
6 |
7 |
8 |
@PopForums.Resources.Login - @PopForums.Resources.Error
9 |
12 |
13 |
14 |
21 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Moderator/PostModerationLog.cshtml:
--------------------------------------------------------------------------------
1 | @model List
2 |
3 |
4 |
5 | @foreach (var entry in Model)
6 | {
7 |
8 | |
9 | @entry.UserName |
10 | @entry.ModerationType |
11 |
12 |
13 |
14 | @PopForums.Resources.Comment: @entry.Comment
15 | @Html.Raw(entry.OldText)
16 | |
17 |
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Moderator/TopicModerationLog.cshtml:
--------------------------------------------------------------------------------
1 | @model List
2 |
3 |
4 |
@PopForums.Resources.ModerationLog
5 |
6 | @if (Model.Count == 0)
7 | {
8 |
@PopForums.Resources.None
9 | }
10 |
11 | @foreach (var entry in Model)
12 | {
13 |
14 | |
15 | @if (entry.UserID == 0)
16 | {
17 | @entry.UserName |
18 | }
19 | else
20 | {
21 | @entry.UserName |
22 | }
23 | @entry.ModerationType |
24 |
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Setup/Exception.cshtml:
--------------------------------------------------------------------------------
1 | @model System.Exception
2 |
3 |
4 |
5 |
6 | @PopForums.Resources.PopForumsSetup - @PopForums.Resources.Error
7 |
8 |
9 |
10 |
11 |
@PopForums.Resources.ErrorSettingUpDb:
12 |
13 |
@Model.Message
14 |
15 |
@Html.Raw(Model.StackTrace.Replace(Environment.NewLine, "
"))
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Setup/NoConnection.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | @PopForums.Resources.PopForumsSetup - @PopForums.Resources.NoDataConnection
6 |
7 |
8 |
9 |
10 |
@PopForums.Resources.PopForumsSetup
11 |
12 |
@PopForums.Resources.SetupCantConnect
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Setup/Success.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | @PopForums.Resources.PopForumsSetup - @PopForums.Resources.Success
6 |
7 |
8 |
9 |
10 |
@PopForums.Resources.PopForumsSetup - @PopForums.Resources.Success
11 |
Congratulations!
12 |
@PopForums.Resources.ForumReady
13 |
@PopForums.Resources.AppRestartRequired
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Shared/Components/UserState/Default.cshtml:
--------------------------------------------------------------------------------
1 | @model UserState
2 | @inject IUserRetrievalShim UserRetrievalShim
3 | @inject ITimeFormatStringService TimeFormatStringService
4 | @{
5 | var serialized = JsonSerializer.Serialize(Model, new JsonSerializerOptions{ PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
6 | var user = UserRetrievalShim.GetUser();
7 | }
8 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Shared/Forbidden.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = PopForums.Resources.Forbidden;
3 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
4 | }
5 |
6 |
7 |
@PopForums.Resources.Forbidden
8 |
9 | - @Html.ActionLink(PopForums.Resources.Forums, "Index", HomeController.Name, null, null)
10 |
11 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/Shared/NotFound.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = PopForums.Resources.PageNotFound;
3 | Layout = "~/Areas/Forums/Views/Shared/PopForumsMaster.cshtml";
4 | }
5 |
6 |
7 |
@PopForums.Resources.PageNotFound
8 |
9 | - @Html.ActionLink(PopForums.Resources.Forums, "Index", HomeController.Name, null, null)
10 |
11 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Areas/Forums/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using PopForums.Extensions
2 | @using PopForums.Models
3 | @using PopForums.Services
4 | @using PopForums.Mvc.Areas.Forums.Controllers
5 | @using PopForums.Mvc.Areas.Forums.Models
6 | @using PopForums.Mvc.Areas.Forums.Services
7 | @using System.Threading.Tasks
8 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
9 | @addTagHelper *, PopForums.Mvc
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/Components/NotificationList.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | export class NotificationList extends ElementBase {
4 | constructor() {
5 | super();
6 | }
7 |
8 | connectedCallback() {
9 | super.connectedCallback();
10 | }
11 |
12 | getDependentReference(): [UserState, string] {
13 | return [PopForums.userState, "notifications"];
14 | }
15 |
16 | updateUI(data: Array): void {
17 | if (!data || data.length === 0) {
18 | this.replaceChildren();
19 | return;
20 | }
21 | data.forEach(item => {
22 | let n = new NotificationItem(item);
23 | this.append(n);
24 | });
25 | }
26 | }
27 |
28 | customElements.define('pf-notificationlist', NotificationList);
29 |
30 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/Components/NotificationMarkAllButton.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | export class NotificationMarkAllButton extends HTMLElement {
4 | constructor() {
5 | super();
6 | }
7 |
8 | get buttonclass(): string {
9 | return this.getAttribute("buttonclass");
10 | }
11 | get buttontext(): string {
12 | return this.getAttribute("buttontext");
13 | }
14 |
15 | connectedCallback() {
16 | this.innerHTML = ``;
17 | this.querySelector("input").addEventListener("click", () => {
18 | PopForums.userState.MarkAllRead();
19 | });
20 | }
21 | }
22 |
23 | customElements.define('pf-notificationmarkallbutton', NotificationMarkAllButton);
24 |
25 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/Components/PMCount.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | export class PMCount extends ElementBase {
4 | constructor() {
5 | super();
6 | this.isInit = false;
7 | }
8 |
9 | private isInit: boolean;
10 |
11 | getDependentReference(): [UserState, string] {
12 | return [PopForums.userState, "newPmCount"];
13 | }
14 |
15 | updateUI(data: number): void {
16 | if (data === 0)
17 | this.innerHTML = "";
18 | else {
19 | this.innerHTML = `${data}`;
20 | if (this.isInit)
21 | this.innerHTML = `${data}`;
22 | }
23 | this.isInit = true;
24 | }
25 | }
26 |
27 | customElements.define('pf-pmcount', PMCount);
28 |
29 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/ElementBase.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | export abstract class ElementBase extends HTMLElement {
4 |
5 | connectedCallback() {
6 | if (this.state && this.propertyToWatch)
7 | return;
8 | let stateAndWatchProperty = this.getDependentReference();
9 | this.state = stateAndWatchProperty[0];
10 | this.propertyToWatch = stateAndWatchProperty[1];
11 | const delegate = this.update.bind(this);
12 | this.state.subscribe(this.propertyToWatch, delegate);
13 | }
14 |
15 | private state: B;
16 | private propertyToWatch: string;
17 |
18 | update() {
19 | const externalValue = this.state[this.propertyToWatch as keyof B];
20 | this.updateUI(externalValue);
21 | }
22 |
23 | // Implementation should return the StateBase and property (as a string) to monitor
24 | abstract getDependentReference(): [B, string];
25 |
26 | // Use in the implementation to manipulate the shadow or light DOM or straight markup as needed in response to the new data.
27 | abstract updateUI(data: any): void;
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/Models/Notification.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | export class Notification {
4 | userID: number;
5 | timeStamp: Date;
6 | isRead: boolean;
7 | notificationType: number;
8 | contextID: number;
9 | data: any;
10 | unreadCount: number;
11 | }
12 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/Models/PrivateMessage.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | export class PrivateMessage {
4 | pmPostID: number;
5 | userID: number;
6 | name: string;
7 | postTime: Date;
8 | fullText: string;
9 | }
10 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/Models/PrivateMessageUser.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 | export class PrivateMessageUser {
3 | userID: number;
4 | name: string;
5 | }
6 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/Services/LocalizationService.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | export class LocalizationService {
4 | static init(): void {
5 | const path = PopForums.AreaPath + "/Resources";
6 | fetch(path)
7 | .then(response => {
8 | return response.json();
9 | })
10 | .then(json => {
11 | PopForums.localizations = Object.assign(new Localizations(), json);
12 | return this.signal();
13 | });
14 | }
15 |
16 | private static signal() {
17 | PopForums.Ready(() => {
18 | if (this.readies) {
19 | for (let i of this.readies) {
20 | i();
21 | }
22 | }
23 | this.isSignaled = true;
24 | });
25 | }
26 |
27 | static readies: Array;
28 | private static isSignaled: boolean = false;
29 |
30 | static subscribe(ready: Function): boolean {
31 | if (!this.readies)
32 | this.readies = new Array();
33 | this.readies.push(ready);
34 | return this.isSignaled;
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/Services/MessagingService.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | export class MessagingService {
4 | private static service: MessagingService;
5 | private static promise: Promise;
6 |
7 | static async GetService(): Promise {
8 | if (!this.promise) {
9 | const service = new MessagingService();
10 | this.promise = service.start();
11 | this.service = service;
12 | }
13 | await Promise.all([this.promise]);
14 | return this.service;
15 | }
16 |
17 | connection: any;
18 |
19 | private async start() {
20 | this.connection = new signalR.HubConnectionBuilder().withUrl("/PopForumsHub").withAutomaticReconnect().build();
21 | await this.connection.start();
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/State/Localizations.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 | export class Localizations {
3 | todayTime: string;
4 | yesterdayTime: string;
5 | minutesAgo: string;
6 | oneMinuteAgo: string;
7 | lessThanMinute: string;
8 |
9 | notifications: string;
10 | newReplyNotification: string;
11 | award: string;
12 | voteUpNotification: string;
13 | questionAnsweredNotification: string;
14 | send: string;
15 |
16 | uploadImage: string;
17 | }
18 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/StateBase.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | // Properties to watch require the @WatchProperty attribute.
4 | export class StateBase {
5 | constructor() {
6 | this._subs = new Map>();
7 | }
8 |
9 | private _subs: Map>;
10 |
11 | subscribe(propertyName: string, eventHandler: Function) {
12 | if (!this._subs.has(propertyName))
13 | this._subs.set(propertyName, new Array());
14 | const callbacks = this._subs.get(propertyName);
15 | callbacks.push(eventHandler);
16 | eventHandler();
17 | }
18 |
19 | notify(propertyName: string) {
20 | const callbacks = this._subs.get(propertyName);
21 | if (callbacks)
22 | for (let i of callbacks) {
23 | i();
24 | }
25 | }
26 | }
27 |
28 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/WatchPropertyAttribute.ts:
--------------------------------------------------------------------------------
1 | namespace PopForums {
2 |
3 | export const WatchProperty = (target: any, memberName: string) => {
4 | let currentValue: any = target[memberName];
5 | Object.defineProperty(target, memberName, {
6 | set(this: any, newValue: any) {
7 | currentValue = newValue;
8 | this.notify(memberName);
9 | },
10 | get() {return currentValue;}
11 | });
12 | };
13 |
14 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/Client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": true,
3 | "compilerOptions": {
4 | "target": "es2018",
5 | "inlineSources": true,
6 | "inlineSourceMap": true,
7 | "outFile": "../wwwroot/PopForums.js",
8 | "experimentalDecorators": true,
9 | "noImplicitAny": true,
10 | "moduleResolution": "Node"
11 | }
12 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {},
3 | "dependencies": {
4 | "@microsoft/signalr": "8.0.7",
5 | "axios": "1.8.2",
6 | "bootstrap": "5.3.3",
7 | "tinymce": "7.5.1",
8 | "vue": "3.5.13",
9 | "vue-router": "4.4.5"
10 | },
11 | "devDependencies": {
12 | "typescript": "5.2.2",
13 | "gulp-typescript": "5.0.1",
14 | "@babel/core": "7.23.3",
15 | "@babel/preset-env": "7.23.3",
16 | "gulp": "4.0.2",
17 | "gulp-babel": "8.0.0",
18 | "gulp-clean-css": "4.3.0",
19 | "gulp-rename": "2.0.0",
20 | "gulp-sourcemaps": "3.0.0",
21 | "gulp-uglify": "3.0.2",
22 | "merge-stream": "2.0.0"
23 | },
24 | "babel": {
25 | "presets": [
26 | "@babel/preset-env"
27 | ]
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/PopForums.Mvc/wwwroot/Editor.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 10px;
3 | }
4 | blockquote {
5 | font-size: 100%;
6 | border-left: 5px solid #aaaaaa;
7 | padding: 0 1em;
8 | }
9 |
10 | img {
11 | max-width: 100%;
12 | }
--------------------------------------------------------------------------------
/src/PopForums.Mvc/wwwroot/Fonts/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/POPWorldMedia/POPForums/2a6d6e5cb34b37b5ae26b5006eabf24efbcda319/src/PopForums.Mvc/wwwroot/Fonts/icomoon.ttf
--------------------------------------------------------------------------------
/src/PopForums.Mvc/wwwroot/Fonts/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/POPWorldMedia/POPForums/2a6d6e5cb34b37b5ae26b5006eabf24efbcda319/src/PopForums.Mvc/wwwroot/Fonts/icomoon.woff
--------------------------------------------------------------------------------
/src/PopForums.Sql/Global.cs:
--------------------------------------------------------------------------------
1 | global using System;
2 | global using System.Collections.Generic;
3 | global using System.Data;
4 | global using System.Data.Common;
5 | global using System.IO;
6 | global using System.Linq;
7 | global using System.Reflection;
8 | global using System.Text;
9 | global using System.Text.RegularExpressions;
10 | global using System.Text.Json;
11 | global using System.Threading.Tasks;
12 |
13 | global using Microsoft.Data.SqlClient;
14 | global using Microsoft.Extensions.Caching.Memory;
15 | global using Microsoft.Extensions.DependencyInjection;
16 |
17 | global using Dapper;
18 |
19 | global using PopForums.Configuration;
20 | global using PopForums.Email;
21 | global using PopForums.ExternalLogin;
22 | global using PopForums.Models;
23 | global using PopForums.Repositories;
24 | global using PopForums.ScoringGame;
25 | global using PopForums.Services;
26 |
27 | global using PopForums.Sql.Repositories;
--------------------------------------------------------------------------------
/src/PopForums.Sql/ISqlObjectFactory.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Sql;
2 |
3 | public interface ISqlObjectFactory
4 | {
5 | DbConnection GetConnection();
6 | DbCommand GetCommand();
7 | DbCommand GetCommand(string sql);
8 | DbCommand GetCommand(string sql, DbConnection connection);
9 | DbParameter GetParameter(string parameterName, object value);
10 | }
--------------------------------------------------------------------------------
/src/PopForums.Sql/JsonElementTypeHandler.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Sql;
2 |
3 | public class JsonElementTypeHandler : SqlMapper.TypeHandler
4 | {
5 | public override void SetValue(IDbDataParameter parameter, JsonElement value)
6 | {
7 | parameter.DbType = DbType.String;
8 | parameter.Size = int.MaxValue;
9 | parameter.Value = value.ToString();
10 | }
11 |
12 | public override JsonElement Parse(object value)
13 | {
14 | var o = JsonSerializer.Deserialize((string)value);
15 | var element = JsonSerializer.SerializeToElement(o, new JsonSerializerOptions {PropertyNamingPolicy = JsonNamingPolicy.CamelCase});
16 | return element;
17 | }
18 | }
--------------------------------------------------------------------------------
/src/PopForums.Sql/PopForums13to14.sql:
--------------------------------------------------------------------------------
1 | IF OBJECT_ID('pf_EmailQueue', 'U') IS NULL
2 | BEGIN
3 | CREATE TABLE [dbo].[pf_EmailQueue](
4 | [Id] [int] IDENTITY(1,1) NOT NULL,
5 | [Payload] [nvarchar](256) NOT NULL
6 | ) ON [PRIMARY]
7 |
8 | CREATE CLUSTERED INDEX IX_pf_EmailQueue_Id ON pf_EmailQueue (Id)
9 | END
10 |
11 |
12 |
13 | IF OBJECT_ID('pf_SearchQueue', 'U') IS NULL
14 | BEGIN
15 | CREATE TABLE [dbo].[pf_SearchQueue](
16 | [ID] [int] IDENTITY(1,1) NOT NULL,
17 | [TopicID] [int] NOT NULL
18 | )
19 |
20 | CREATE CLUSTERED INDEX IX_pf_SearchQueue_ID ON pf_SearchQueue (ID)
21 | END
22 |
23 |
24 |
25 | IF OBJECT_ID('pf_ServiceHeartbeat', 'U') IS NULL
26 | BEGIN
27 | CREATE TABLE [dbo].[pf_ServiceHeartbeat](
28 | [ServiceName] [nvarchar](256) NOT NULL,
29 | [MachineName] [nvarchar](256) NOT NULL,
30 | [LastRun] [datetime] NOT NULL,
31 | CONSTRAINT [PK_pf_ServiceHeartbeat] PRIMARY KEY CLUSTERED
32 | (
33 | [ServiceName] ASC,
34 | [MachineName] ASC
35 | )
36 | )
37 | END
38 |
39 | IF EXISTS( SELECT TOP 1 1 FROM sys.objects o INNER JOIN sys.columns c ON o.object_id = c.object_id WHERE o.name = 'pf_Profile' AND c.name = 'AIM')
40 | ALTER TABLE dbo.pf_Profile DROP COLUMN [AIM]
41 | GO
42 |
--------------------------------------------------------------------------------
/src/PopForums.Sql/PopForums19to20.sql:
--------------------------------------------------------------------------------
1 | IF COL_LENGTH('dbo.pf_PopForumsUser', 'TokenExpiration') IS NULL
2 | BEGIN
3 | ALTER TABLE pf_PopForumsUser ADD [TokenExpiration] [datetime] NULL;
4 | END
5 |
6 | IF COL_LENGTH('dbo.pf_UserActivity', 'RefreshToken') IS NULL
7 | BEGIN
8 | ALTER TABLE pf_UserActivity ADD [RefreshToken] [nvarchar](MAX) NULL;
9 | END
--------------------------------------------------------------------------------
/src/PopForums.Sql/PopForums20to21.sql:
--------------------------------------------------------------------------------
1 | IF COL_LENGTH('dbo.pf_Profile', 'Twitter') IS NOT NULL
2 | BEGIN
3 | ALTER TABLE pf_Profile DROP COLUMN [Twitter];
4 | END
5 |
--------------------------------------------------------------------------------
/src/PopForums.Sql/Repositories/TopicViewLogRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Sql.Repositories;
2 |
3 | public class TopicViewLogRepository : ITopicViewLogRepository
4 | {
5 | private readonly ISqlObjectFactory _sqlObjectFactory;
6 |
7 | public TopicViewLogRepository(ISqlObjectFactory sqlObjectFactory)
8 | {
9 | _sqlObjectFactory = sqlObjectFactory;
10 | }
11 |
12 | public async Task Log(int? userID, int topicID, DateTime timeStamp)
13 | {
14 | await _sqlObjectFactory.GetConnection().UsingAsync(connection =>
15 | connection.ExecuteAsync("INSERT INTO pf_TopicViewLog (UserID, TopicID, [TimeStamp]) VALUES (@UserID, @TopicID, @TimeStamp)", new {UserID = userID, TopicID = topicID, TimeStamp = timeStamp}));
16 | }
17 | }
--------------------------------------------------------------------------------
/src/PopForums.Sql/SqlObjectFactory.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Sql;
2 |
3 | public class SqlObjectFactory : ISqlObjectFactory
4 | {
5 | private readonly IConfig _config;
6 |
7 | public SqlObjectFactory(IConfig config)
8 | {
9 | _config = config;
10 | }
11 |
12 | public DbConnection GetConnection()
13 | {
14 | if (string.IsNullOrWhiteSpace(_config.DatabaseConnectionString))
15 | throw new Exception("No database connection string found for POP Forums.");
16 | var connectionString = _config.DatabaseConnectionString;
17 | return new SqlConnection(connectionString);
18 | }
19 |
20 | public DbCommand GetCommand()
21 | {
22 | return new SqlCommand();
23 | }
24 |
25 | public DbCommand GetCommand(string sql)
26 | {
27 | return new SqlCommand(sql);
28 | }
29 |
30 | public DbCommand GetCommand(string sql, DbConnection connection)
31 | {
32 | return new SqlCommand(sql, (SqlConnection)connection);
33 | }
34 |
35 | public DbParameter GetParameter(string parameterName, object value)
36 | {
37 | return new SqlParameter(parameterName, value);
38 | }
39 | }
--------------------------------------------------------------------------------
/src/PopForums.Sql/StreamResponse.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Sql;
2 |
3 | public class StreamResponse(Stream stream, SqlConnection connection, SqlDataReader reader) : IStreamResponse
4 | {
5 | public Stream Stream => stream;
6 |
7 | public void Dispose()
8 | {
9 | reader.Close();
10 | connection.Close();
11 | stream.Close();
12 |
13 | reader.Dispose();
14 | connection.Dispose();
15 | stream.Dispose();
16 | }
17 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Composers/ForumStateComposerTests.cs:
--------------------------------------------------------------------------------
1 | using PopForums.Composers;
2 |
3 | namespace PopForums.Test.Composers;
4 |
5 | public class ForumStateComposerTests
6 | {
7 | protected ForumStateComposer GetComposer()
8 | {
9 | return new ForumStateComposer();
10 | }
11 |
12 | public class GetState : ForumStateComposerTests
13 | {
14 | [Fact]
15 | public void MapsCorrectly()
16 | {
17 | var composer = GetComposer();
18 | var pagerContext = new PagerContext {PageCount = 1, PageIndex = 2, PageSize = 3};
19 | var forum = new Forum {ForumID = 4};
20 |
21 | var result = composer.GetState(forum, pagerContext);
22 |
23 | Assert.Equal(forum.ForumID, result.ForumID);
24 | Assert.Equal(pagerContext.PageIndex, result.PageIndex);
25 | Assert.Equal(pagerContext.PageSize, result.PageSize);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Email/NewAccountMailerTests.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Test.Email;
2 |
3 | public class NewAccountMailerTests
4 | {
5 | [Fact]
6 | public void SendCallsSmtpWrapper()
7 | {
8 | var wrapper = Substitute.For();
9 | var resultMessage = new EmailMessage();
10 | wrapper.Send(Arg.Do(msg => resultMessage = msg)).Returns(SmtpStatusCode.Ok);
11 | const string mailerAddress = "a@b.com";
12 | const string forumTitle = "superawesome";
13 | var user = UserTest.GetTestUser();
14 | var settings = new Settings { MailerAddress = mailerAddress, ForumTitle = forumTitle};
15 | var settingsManager = Substitute.For();
16 | settingsManager.Current.Returns(settings);
17 | var mailer = new NewAccountMailer(settingsManager, wrapper);
18 |
19 | var result = mailer.Send(user, "http://blah/");
20 |
21 | Assert.Equal(SmtpStatusCode.Ok, result);
22 | Assert.Equal(resultMessage.ToName, user.Name);
23 | Assert.Equal(resultMessage.ToEmail, user.Email);
24 | Assert.Equal(forumTitle, resultMessage.FromName);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Global.cs:
--------------------------------------------------------------------------------
1 | global using System;
2 | global using System.Collections.Generic;
3 | global using System.Linq;
4 | global using System.Reflection;
5 | global using System.Security;
6 | global using System.Text.RegularExpressions;
7 | global using System.Threading.Tasks;
8 |
9 | global using Microsoft.AspNetCore.Mvc;
10 |
11 | global using PopForums.Configuration;
12 | global using PopForums.Email;
13 | global using PopForums.Extensions;
14 | global using PopForums.ExternalLogin;
15 | global using PopForums.Feeds;
16 | global using PopForums.Messaging;
17 | global using PopForums.Models;
18 | global using PopForums.Repositories;
19 | global using PopForums.ScoringGame;
20 | global using PopForums.Services;
21 |
22 | global using PopForums.Mvc.Areas.Forums.Controllers;
23 | global using PopForums.Mvc.Areas.Forums.Services;
24 |
25 | global using PopForums.Test.Models;
26 |
27 | global using NSubstitute;
28 | global using Xunit;
--------------------------------------------------------------------------------
/src/PopForums.Test/Models/UserEditSecurityTests.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Test.Models;
2 |
3 | public class UserEditSecurityTests
4 | {
5 | [Fact]
6 | public void PasswordsMatch()
7 | {
8 | var edit = new UserEditSecurity();
9 | edit.NewPassword = "blah";
10 | edit.NewPasswordRetype = "blah";
11 | Assert.True(edit.NewPasswordsMatch());
12 | }
13 |
14 | [Fact]
15 | public void PasswordsNoMatch()
16 | {
17 | var edit = new UserEditSecurity();
18 | edit.NewPassword = "blasjspvjsh";
19 | edit.NewPasswordRetype = "blah";
20 | Assert.False(edit.NewPasswordsMatch());
21 | }
22 |
23 | [Fact]
24 | public void EmailMatch()
25 | {
26 | var edit = new UserEditSecurity();
27 | edit.NewEmail = "blah";
28 | edit.NewEmailRetype = "blah";
29 | Assert.True(edit.NewEmailsMatch());
30 | }
31 |
32 | [Fact]
33 | public void EmailNoMatch()
34 | {
35 | var edit = new UserEditSecurity();
36 | edit.NewEmail = "blah";
37 | edit.NewEmailRetype = "bloidsvosah";
38 | Assert.False(edit.NewEmailsMatch());
39 | }
40 |
41 | [Fact]
42 | public void IsNewUserApprovedMapped()
43 | {
44 | var edit = new UserEditSecurity(new User { UserID = 1 }, true);
45 | Assert.True(edit.IsNewUserApproved);
46 | }
47 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Models/UserTest.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Test.Models;
2 |
3 | public class UserTest
4 | {
5 | [Fact]
6 | public void IsRoleWiredToRoles()
7 | {
8 | var user = GetTestUser();
9 | user.Roles = new List {"blah", "three", PermanentRoles.Admin};
10 | Assert.True(user.IsInRole(PermanentRoles.Admin));
11 | }
12 |
13 | public static User GetTestUser()
14 | {
15 | const int userID = 123;
16 | const string name = "Jeff";
17 | const string email = "a@b.com";
18 | var createDate = DateTime.UtcNow;
19 | const bool approved = true;
20 | var authKey = Guid.NewGuid();
21 | return new User { UserID = userID, Name = name, Email = email, CreationDate = createDate, IsApproved = approved, AuthorizationKey = authKey, Roles = new List() };
22 | }
23 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Services/BanServiceTests.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Test.Services;
2 |
3 | public class BanServiceTests
4 | {
5 | private IBanRepository _banRepo;
6 |
7 | private IBanService GetService()
8 | {
9 | _banRepo = Substitute.For();
10 | return new BanService(_banRepo);
11 | }
12 |
13 | [Fact]
14 | public async Task IPTrimmedOnSave()
15 | {
16 | var service = GetService();
17 | await service.BanIP(" 1.1.1.1 ");
18 | await _banRepo.Received().BanIP("1.1.1.1");
19 | }
20 |
21 | [Fact]
22 | public async Task EmailTrimmedOnSave()
23 | {
24 | var service = GetService();
25 | await service.BanEmail(" a@b.com ");
26 | await _banRepo.Received().BanEmail("a@b.com");
27 | }
28 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Services/CloseAgedTopicsWorkerTests.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.ExceptionExtensions;
2 |
3 | namespace PopForums.Test.Services;
4 |
5 | public class CloseAgedTopicsWorkerTests
6 | {
7 | private ITopicService _topicService;
8 | private IErrorLog _errorLog;
9 |
10 | private CloseAgedTopicsWorker GetWorker()
11 | {
12 | _topicService = Substitute.For();
13 | _errorLog = Substitute.For();
14 | return new CloseAgedTopicsWorker(_topicService, _errorLog);
15 | }
16 |
17 | [Fact]
18 | public void NoErrorNoLog()
19 | {
20 | var worker = GetWorker();
21 | _topicService.CloseAgedTopics().Returns(Task.CompletedTask);
22 |
23 | worker.Execute();
24 |
25 | _errorLog.DidNotReceive().Log(Arg.Any(), Arg.Any());
26 | }
27 |
28 | [Fact]
29 | public void LogWhenThrows()
30 | {
31 | var worker = GetWorker();
32 | _topicService.CloseAgedTopics().ThrowsAsync();
33 |
34 | worker.Execute();
35 |
36 | _errorLog.Received().Log(Arg.Any(), Arg.Any());
37 | }
38 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Services/PostImageCleanupWorkerTests.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.ExceptionExtensions;
2 |
3 | namespace PopForums.Test.Services;
4 |
5 | public class PostImageCleanupWorkerTests
6 | {
7 | private IPostImageService _postImageService;
8 | private IErrorLog _errorLog;
9 |
10 | private PostImageCleanupWorker GetWorker()
11 | {
12 | _postImageService = Substitute.For();
13 | _errorLog = Substitute.For();
14 | return new PostImageCleanupWorker(_postImageService, _errorLog);
15 | }
16 |
17 | [Fact]
18 | public void NoErrorNoLog()
19 | {
20 | var worker = GetWorker();
21 | _postImageService.DeleteOldPostImages().Returns(Task.CompletedTask);
22 |
23 | worker.Execute();
24 |
25 | _errorLog.DidNotReceive().Log(Arg.Any(), Arg.Any());
26 | }
27 |
28 | [Fact]
29 | public void LogWhenThrows()
30 | {
31 | var worker = GetWorker();
32 | _postImageService.DeleteOldPostImages().ThrowsAsync();
33 |
34 | worker.Execute();
35 |
36 | _errorLog.Received().Log(Arg.Any(),ErrorSeverity.Error);
37 | }
38 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Services/TopicViewLogServiceTests.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Test.Services;
2 |
3 | public class TopicViewLogServiceTests
4 | {
5 | private TopicViewLogService GetService()
6 | {
7 | _config = Substitute.For();
8 | _topicViewLogRepo = Substitute.For();
9 | return new TopicViewLogService(_config, _topicViewLogRepo);
10 | }
11 |
12 | private IConfig _config;
13 | private ITopicViewLogRepository _topicViewLogRepo;
14 |
15 | [Fact]
16 | public async Task LogViewDoesNotCallRepoWhenConfigIsFalse()
17 | {
18 | var service = GetService();
19 | _config.LogTopicViews.Returns(false);
20 |
21 | await service.LogView(123, 456);
22 |
23 | await _topicViewLogRepo.DidNotReceive().Log(Arg.Any(), Arg.Any(), Arg.Any());
24 | }
25 |
26 | [Fact]
27 | public async Task LogViewDoesCallsRepoWhenConfigIsTrue()
28 | {
29 | var service = GetService();
30 | _config.LogTopicViews.Returns(true);
31 |
32 | await service.LogView(123, 456);
33 |
34 | await _topicViewLogRepo.Received().Log(123, 456, Arg.Any());
35 | }
36 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Services/UserEmailReconcilerTests.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Test.Services;
2 |
3 | public class UserEmailReconcilerTests
4 | {
5 | private IUserRepository _userRepo;
6 |
7 | private UserEmailReconciler GetService()
8 | {
9 | _userRepo = Substitute.For();
10 | return new UserEmailReconciler(_userRepo);
11 | }
12 |
13 | public class GetUniqueEmail : UserEmailReconcilerTests
14 | {
15 | [Fact]
16 | public async Task UnmatchedReturnsSameEmail()
17 | {
18 | var service = GetService();
19 | var email = "a@b.com";
20 | _userRepo.GetUserByEmail(email).Returns((User)null);
21 |
22 | var result = await service.GetUniqueEmail(email, "12345");
23 |
24 | Assert.Equal(email, result);
25 | }
26 |
27 | [Fact]
28 | public async Task MatchedReturnsUniqueEmail()
29 | {
30 | var service = GetService();
31 | var email = "a@b.com";
32 | var user = new User { Email = email };
33 | _userRepo.GetUserByEmail(email).Returns(Task.FromResult(user));
34 |
35 | var result = await service.GetUniqueEmail(email, "12345");
36 |
37 | Assert.Equal("a-at-b.com@12345.example.com", result);
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/src/PopForums.Test/Services/UserSessionWorkerTests.cs:
--------------------------------------------------------------------------------
1 | using NSubstitute.ExceptionExtensions;
2 |
3 | namespace PopForums.Test.Services;
4 |
5 | public class UserSessionWorkerTests
6 | {
7 | private IUserSessionService _userSessionService;
8 | private IErrorLog _errorLog;
9 |
10 | private UserSessionWorker GetWorker()
11 | {
12 | _userSessionService = Substitute.For();
13 | _errorLog = Substitute.For();
14 | return new UserSessionWorker(_userSessionService, _errorLog);
15 | }
16 |
17 | [Fact]
18 | public void NoErrorNoLog()
19 | {
20 | var worker = GetWorker();
21 | _userSessionService.CleanUpExpiredSessions().Returns(Task.CompletedTask);
22 |
23 | worker.Execute();
24 |
25 | _errorLog.DidNotReceive().Log(Arg.Any(), Arg.Any());
26 | }
27 |
28 | [Fact]
29 | public void LogWhenThrows()
30 | {
31 | var worker = GetWorker();
32 | _userSessionService.CleanUpExpiredSessions().ThrowsAsync();
33 |
34 | worker.Execute();
35 |
36 | _errorLog.Received().Log(Arg.Any(), ErrorSeverity.Error);
37 | }
38 | }
--------------------------------------------------------------------------------
/src/PopForums.Web/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 |
3 | namespace PopForums.Mvc.Controllers
4 | {
5 | public class HomeController : Controller
6 | {
7 | public IActionResult Index()
8 | {
9 | return View();
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/PopForums.Web/PopForums.Web.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | 21.0.0
6 | PopForums.Web
7 | PopForums.Web
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/PopForums.Web/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "PopForumsKestrel": {
4 | "commandName": "Project",
5 | "launchBrowser": true,
6 | "environmentVariables": {
7 | "ASPNETCORE_ENVIRONMENT": "Development"
8 | },
9 | "applicationUrl": "https://localhost:5091;http://localhost:5090",
10 | "dotnetRunMessages": true
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/PopForums.Web/Views/Home/Index.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewData["Title"] = "Home Page";
3 | }
4 |
5 | forums
6 |
7 |
8 | PopForums - v@(System.Reflection.Assembly.Load("PopForums").GetName().Version)
9 | PopForums.Sql - v@(System.Reflection.Assembly.Load("PopForums.Sql").GetName().Version)
10 | PopForums.Mvc - v@(System.Reflection.Assembly.Load("PopForums.Mvc").GetName().Version)
11 | PopForums.Web - v@(System.Reflection.Assembly.Load("PopForums.Web").GetName().Version)
12 |
--------------------------------------------------------------------------------
/src/PopForums.Web/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewBag.Title
7 |
8 | @await RenderSectionAsync("HeaderContent", false)
9 |
10 |
11 |
12 | @RenderBody()
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/PopForums.Web/Views/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using PopForums.Mvc
2 | @addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
3 |
--------------------------------------------------------------------------------
/src/PopForums.Web/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/src/PopForums.Web/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/POPWorldMedia/POPForums/2a6d6e5cb34b37b5ae26b5006eabf24efbcda319/src/PopForums.Web/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/src/PopForums/Composers/ForumStateComposer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Composers;
2 |
3 | public interface IForumStateComposer
4 | {
5 | ForumState GetState(Forum forum, PagerContext pagerContext);
6 | }
7 |
8 | public class ForumStateComposer : IForumStateComposer
9 | {
10 | public ForumState GetState(Forum forum, PagerContext pagerContext)
11 | {
12 | var forumState = new ForumState {ForumID = forum?.ForumID, PageSize = pagerContext.PageSize, PageIndex = pagerContext.PageIndex};
13 | return forumState;
14 | }
15 | }
--------------------------------------------------------------------------------
/src/PopForums/Composers/ResourceComposer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Composers;
2 |
3 | public interface IResourceComposer
4 | {
5 | dynamic GetForCurrentThread();
6 | }
7 |
8 | public class ResourceComposer : IResourceComposer
9 | {
10 | public dynamic GetForCurrentThread()
11 | {
12 | var resources = new
13 | {
14 | LessThanMinute = Resources.LessThanMinute,
15 | OneMinuteAgo = Resources.OneMinuteAgo,
16 | MinutesAgo = Resources.MinutesAgo,
17 | TodayTime = Resources.TodayTime,
18 | YesterdayTime = Resources.YesterdayTime,
19 |
20 | Notifications = Resources.Notifications,
21 | NewReplyNotification = Resources.NewReplyNotification,
22 | Award = Resources.Award,
23 | VoteUpNotification = Resources.VoteUpNotification,
24 | QuestionAnsweredNotification = Resources.QuestionAnsweredNotification,
25 | Send = Resources.Send,
26 |
27 | UploadImage = Resources.UploadImage
28 | };
29 | return resources;
30 | }
31 | }
--------------------------------------------------------------------------------
/src/PopForums/Configuration/ErrorLogException.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Configuration;
2 |
3 | public class ErrorLogException : Exception
4 | {
5 | public ErrorLogException(string message) : base(message)
6 | {
7 |
8 | }
9 |
10 | public override string Message => "Can't log exception: " + base.Message;
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Configuration/ErrorSeverity.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Configuration;
2 |
3 | public enum ErrorSeverity
4 | {
5 | Critical = 1,
6 | Warning = 2,
7 | Information = 3,
8 | Debug = 4,
9 | Error = 5,
10 | Email = 6
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Email/EmailQueuePayload.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Email;
2 |
3 | public class EmailQueuePayload
4 | {
5 | public int MessageID { get; set; }
6 | public EmailQueuePayloadType EmailQueuePayloadType { get; set; }
7 | public string ToEmail { get; set; }
8 | public string ToName { get; set; }
9 | public string TenantID { get; set; }
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Email/EmailQueuePayloadType.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Email;
2 |
3 | public enum EmailQueuePayloadType
4 | {
5 | FullMessage = 1,
6 | MassMessage = 2,
7 | DeleteMassMessage = 3
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Email/SmtpStatusCode.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Email;
2 |
3 | public enum SmtpStatusCode
4 | {
5 | SystemStatus = 211,
6 | HelpMessage = 214,
7 | ServiceReady = 220,
8 | ServiceClosingTransmissionChannel = 221,
9 | AuthenticationSuccessful = 235,
10 | Ok = 250,
11 | UserNotLocalWillForward = 251,
12 | CannotVerifyUserWillAttemptDelivery = 252,
13 | AuthenticationChallenge = 334,
14 | StartMailInput = 354,
15 | ServiceNotAvailable = 421,
16 | PasswordTransitionNeeded = 432,
17 | MailboxBusy = 450,
18 | ErrorInProcessing = 451,
19 | InsufficientStorage = 452,
20 | TemporaryAuthenticationFailure = 454,
21 | CommandUnrecognized = 500,
22 | SyntaxError = 501,
23 | CommandNotImplemented = 502,
24 | BadCommandSequence = 503,
25 | CommandParameterNotImplemented = 504,
26 | AuthenticationRequired = 530,
27 | AuthenticationMechanismTooWeak = 534,
28 | AuthenticationInvalidCredentials = 535,
29 | EncryptionRequiredForAuthenticationMechanism = 538,
30 | MailboxUnavailable = 550,
31 | UserNotLocalTryAlternatePath = 551,
32 | ExceededStorageAllocation = 552,
33 | MailboxNameNotAllowed = 553,
34 | TransactionFailed = 554,
35 | MailFromOrRcptToParametersNotRecognizedOrNotImplemented = 555
36 | }
--------------------------------------------------------------------------------
/src/PopForums/Extensions/Streams.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Extensions;
2 |
3 | public static class Streams
4 | {
5 | public static byte[] ToBytes(this Stream stream)
6 | {
7 | var length = (int)stream.Length;
8 | var bytes = new byte[length];
9 | stream.Read(bytes, 0, length);
10 | return bytes;
11 | }
12 | }
--------------------------------------------------------------------------------
/src/PopForums/Extensions/Users.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Extensions;
2 |
3 | public static class Users
4 | {
5 | public static bool IsPostEditable(this User user, Post post)
6 | {
7 | if (user == null)
8 | return false;
9 | return user.IsInRole(PermanentRoles.Moderator) || user.UserID == post.UserID;
10 | }
11 | }
--------------------------------------------------------------------------------
/src/PopForums/ExternalLogin/ExternalAuthenticationResult.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ExternalLogin;
2 |
3 | public class ExternalAuthenticationResult
4 | {
5 | public string Issuer { get; set; }
6 | public string ProviderKey { get; set; }
7 | public string Name { get; set; }
8 | public string Email { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/ExternalLogin/ExternalLoginInfo.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ExternalLogin;
2 |
3 | public class ExternalLoginInfo
4 | {
5 | public ExternalLoginInfo(string loginProvider, string providerKey,
6 | string displayName)
7 | {
8 | LoginProvider = loginProvider;
9 | ProviderKey = providerKey;
10 | ProviderDisplayName = displayName;
11 | }
12 |
13 | public string LoginProvider { get; set; }
14 | public string ProviderKey { get; set; }
15 | public string ProviderDisplayName { get; set; }
16 | }
--------------------------------------------------------------------------------
/src/PopForums/ExternalLogin/ExternalUserAssociation.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ExternalLogin;
2 |
3 | public class ExternalUserAssociation
4 | {
5 | public int ExternalUserAssociationID { get; set; }
6 | public int UserID { get; set; }
7 | public string Issuer { get; set; }
8 | public string ProviderKey { get; set; }
9 | public string Name { get; set; }
10 | }
--------------------------------------------------------------------------------
/src/PopForums/ExternalLogin/ExternalUserAssociationMatchResult.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ExternalLogin;
2 |
3 | public class ExternalUserAssociationMatchResult
4 | {
5 | public bool Successful { get; set; }
6 | public ExternalUserAssociation ExternalUserAssociation { get; set; }
7 | public User User { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Feeds/FeedService.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Feeds;
2 |
3 | public interface IFeedService
4 | {
5 | Task PublishToFeed(User user, string message, int points, DateTime timeStamp);
6 | Task> GetFeed(User user);
7 | }
8 |
9 | public class FeedService : IFeedService
10 | {
11 |
12 | public FeedService(IFeedRepository feedRepository, IBroker broker)
13 | {
14 | _feedRepository = feedRepository;
15 | _broker = broker;
16 | }
17 |
18 | private readonly IFeedRepository _feedRepository;
19 | private readonly IBroker _broker;
20 |
21 | public const int MaxFeedCount = 50;
22 |
23 | public async Task PublishToFeed(User user, string message, int points, DateTime timeStamp)
24 | {
25 | if (user == null)
26 | return;
27 | await _feedRepository.PublishEvent(user.UserID, message, points, timeStamp);
28 | var cutOff = await _feedRepository.GetOldestTime(user.UserID, MaxFeedCount);
29 | await _feedRepository.DeleteOlderThan(user.UserID, cutOff);
30 | }
31 |
32 | public async Task> GetFeed(User user)
33 | {
34 | return await _feedRepository.GetFeed(user.UserID, MaxFeedCount);
35 | }
36 | }
--------------------------------------------------------------------------------
/src/PopForums/Global.cs:
--------------------------------------------------------------------------------
1 | global using System;
2 | global using System.Collections;
3 | global using System.Collections.Generic;
4 | global using System.IO;
5 | global using System.Linq;
6 | global using System.Net.Http;
7 | global using System.Security;
8 | global using System.Security.Cryptography;
9 | global using System.Text;
10 | global using System.Text.Json;
11 | global using System.Text.Json.Serialization;
12 | global using System.Text.RegularExpressions;
13 | global using System.Threading;
14 | global using System.Threading.Tasks;
15 |
16 | global using Microsoft.Extensions.Configuration;
17 | global using Microsoft.Extensions.DependencyInjection;
18 |
19 | global using PopForums.Composers;
20 | global using PopForums.Configuration;
21 | global using PopForums.Email;
22 | global using PopForums.Extensions;
23 | global using PopForums.ExternalLogin;
24 | global using PopForums.Feeds;
25 | global using PopForums.Messaging;
26 | global using PopForums.Models;
27 | global using PopForums.Repositories;
28 | global using PopForums.ScoringGame;
29 | global using PopForums.Services;
--------------------------------------------------------------------------------
/src/PopForums/Messaging/IBroker.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging;
2 |
3 | public interface IBroker
4 | {
5 | void NotifyNewPosts(Topic topic, int lasPostID);
6 | void NotifyForumUpdate(Forum forum);
7 | void NotifyTopicUpdate(Topic topic, Forum forum, string topicLink);
8 | void NotifyNewPost(Topic topic, int postID);
9 | void NotifyPMCount(int userID, int pmCount);
10 | void NotifyUser(Notification notification);
11 | void NotifyUser(Notification notification, string tenantID);
12 | void SendPMMessage(PrivateMessagePost post);
13 | }
--------------------------------------------------------------------------------
/src/PopForums/Messaging/Models/AwardData.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging.Models;
2 |
3 | public class AwardData
4 | {
5 | public string Title { get; set; }
6 | }
--------------------------------------------------------------------------------
/src/PopForums/Messaging/Models/AwardPayload.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging.Models;
2 |
3 | public class AwardPayload
4 | {
5 | public string Title { get; set; }
6 | public int UserID { get; set; }
7 | public string TenantID { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Messaging/Models/QuestionData.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging.Models;
2 |
3 | public class QuestionData
4 | {
5 | public string AskerName { get; set; }
6 | public string Title { get; set; }
7 | public int PostID { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Messaging/Models/ReplyData.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging.Models;
2 |
3 | public class ReplyData
4 | {
5 | public string PostName { get; set; }
6 | public int TopicID { get; set; }
7 | public string Title { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Messaging/Models/ReplyPayload.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging.Models;
2 |
3 | public class ReplyPayload
4 | {
5 | public string PostName { get; set; }
6 | public string Title { get; set; }
7 | public int TopicID { get; set; }
8 | public int UserID { get; set; }
9 | public string TenantID { get; set; }
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Messaging/Models/VoteData.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging.Models;
2 |
3 | public class VoteData
4 | {
5 | public string VoterName { get; set; }
6 | public string Title { get; set; }
7 | public int PostID { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Messaging/Notification.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging;
2 |
3 | public class Notification
4 | {
5 | public int UserID { get; set; }
6 | public DateTime TimeStamp { get; set; }
7 | public bool IsRead { get; set; }
8 | public NotificationType NotificationType { get; set; }
9 | public long ContextID { get; set; }
10 | public JsonElement Data { get; set; }
11 | public int UnreadCount { get; set; }
12 | }
--------------------------------------------------------------------------------
/src/PopForums/Messaging/NotificationTunnel.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging;
2 |
3 | public interface INotificationTunnel
4 | {
5 | void SendNotificationForUserAward(string title, int userID, string tenantID);
6 | void SendNotificationForReply(string postName, string title, int topicID, int userID, string tenantID);
7 | }
8 |
9 | public class NotificationTunnel : INotificationTunnel
10 | {
11 | public static string HeaderName = "PfApi";
12 |
13 | private readonly INotificationAdapter _notificationAdapter;
14 |
15 | public NotificationTunnel(INotificationAdapter notificationAdapter)
16 | {
17 | _notificationAdapter = notificationAdapter;
18 | }
19 |
20 | public async void SendNotificationForUserAward(string title, int userID, string tenantID)
21 | {
22 | await _notificationAdapter.Award(title, userID, tenantID);
23 | }
24 |
25 | public async void SendNotificationForReply(string postName, string title, int topicID, int userID, string tenantID)
26 | {
27 | await _notificationAdapter.Reply(postName, title, topicID, userID, tenantID);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/PopForums/Messaging/NotificationType.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Messaging;
2 |
3 | public enum NotificationType
4 | {
5 | NewReply = 0,
6 | VoteUp = 1,
7 | QuestionAnswered = 2,
8 | Award = 3
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/AwardCalculationPayload.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class AwardCalculationPayload
4 | {
5 | public string EventDefinitionID { get; set; }
6 | public int UserID { get; set; }
7 | public string TenantID { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/BasicJsonMessage.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class BasicJsonMessage
4 | {
5 | public bool Result { get; set; }
6 | public string Message { get; set; }
7 | public object Data { get; set; }
8 | public string Redirect { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/BasicServiceResponse.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class BasicServiceResponse where T : class
4 | {
5 | public bool IsSuccessful { get; set; }
6 | public string Message { get; set; }
7 | public T Data { get; set; }
8 | public string Redirect { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/CategorizedForumContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class CategorizedForumContainer
4 | {
5 | public CategorizedForumContainer(IEnumerable categories, IEnumerable forums)
6 | {
7 | ReadStatusLookup = new Dictionary();
8 | AllCategories = categories;
9 | AllForums = forums;
10 | UncategorizedForums = forums.Where(f => !f.CategoryID.HasValue || f.CategoryID == 0).OrderBy(f => f.SortOrder).ToList();
11 | CategoryDictionary = new Dictionary>();
12 | foreach (var category in AllCategories.OrderBy(c => c.SortOrder))
13 | {
14 | var forumSet = AllForums.Where(f => f.CategoryID == category.CategoryID).OrderBy(f => f.SortOrder).ToList();
15 | if (forumSet.Count > 0)
16 | CategoryDictionary.Add(category, forumSet);
17 | }
18 | }
19 |
20 | public IEnumerable AllCategories { get; private set; }
21 | public IEnumerable AllForums { get; private set; }
22 | public List UncategorizedForums { get; private set; }
23 | public Dictionary> CategoryDictionary { get; private set; }
24 | public string ForumTitle { get; set; }
25 | public Dictionary ReadStatusLookup { get; private set; }
26 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/Category.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class Category
4 | {
5 | public int CategoryID { get; set; }
6 | public string Title { get; set; }
7 | public int SortOrder { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/CategoryContainerWithForums.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class CategoryContainerWithForums
4 | {
5 | public Category Category { get; set; }
6 | public IEnumerable Forums { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ClientPrivateMessagePost.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ClientPrivateMessagePost
4 | {
5 | public int PMPostID { get; set; }
6 | public int UserID { get; set; }
7 | public string Name { get; set; }
8 | public string PostTime { get; set; }
9 | public string FullText { get; set; }
10 |
11 | public static ClientPrivateMessagePost[] MapForClient(List posts)
12 | {
13 | 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();
14 | return messages;
15 | }
16 |
17 | public static ClientPrivateMessagePost MapForClient(PrivateMessagePost post)
18 | {
19 | var message = new ClientPrivateMessagePost { PMPostID = post.PMPostID, UserID = post.UserID, Name = post.Name, PostTime = post.PostTime.ToString("o"), FullText = post.FullText };
20 | return message;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/EmailMessage.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class EmailMessage
4 | {
5 | public string FromName { get; set; }
6 | public string ToEmail { get; set; }
7 | public string ToName { get; set; }
8 | public string Subject { get; set; }
9 | public string Body { get; set; }
10 | public string HtmlBody { get; set; }
11 | public string ReplyTo { get; set; }
12 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ErrorLogEntry.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ErrorLogEntry
4 | {
5 | public int ErrorID { get; set; }
6 | public DateTime TimeStamp { get; set; }
7 | public string Message { get; set; }
8 | public string StackTrace { get; set; }
9 | public string Data { get; set; }
10 | public ErrorSeverity Severity { get; set; }
11 | public string SeverityString => Severity.ToString();
12 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ExpiredUserSession.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ExpiredUserSession
4 | {
5 | public int SessionID { get; set; }
6 | public int? UserID { get; set; }
7 | public DateTime LastTime { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/FeedEvent.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class FeedEvent
4 | {
5 | public int UserID { get; set; }
6 | public string Message { get; set; }
7 | public int Points { get; set; }
8 | public DateTime TimeStamp { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/Forum.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class Forum
4 | {
5 | public int ForumID { get; set; }
6 | public int? CategoryID { get; set; }
7 | public string Title { get; set; }
8 | public string Description { get; set; }
9 | public bool IsVisible { get; set; }
10 | public bool IsArchived { get; set; }
11 | public int SortOrder { get; set; }
12 | public int TopicCount { get; set; }
13 | public int PostCount { get; set; }
14 | public DateTime LastPostTime { get; set; }
15 | public string LastPostName { get; set; }
16 | public string UrlName { get; set; }
17 | public string ForumAdapterName { get; set; }
18 | public bool IsQAForum { get; set; }
19 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ForumPermissionContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ForumPermissionContainer
4 | {
5 | public int ForumID { get; set; }
6 | public List AllRoles { get; set; }
7 | public List PostRoles { get; set; }
8 | public List ViewRoles { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ForumPermissionContext.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ForumPermissionContext
4 | {
5 | public bool UserCanView { get; set; }
6 | public bool UserCanPost { get; set; }
7 | public bool UserCanModerate { get; set; }
8 | public string DenialReason { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ForumState.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ForumState
4 | {
5 | public int? ForumID { get; set; }
6 | public int PageSize { get; set; }
7 | public int PageIndex { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ForumTopicContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ForumTopicContainer : PagedTopicContainer
4 | {
5 | public Forum Forum { get; set; }
6 | public ForumPermissionContext PermissionContext { get; set; }
7 | public ForumState ForumState { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/IPHistoryEvent.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class IPHistoryEvent
4 | {
5 | public DateTime EventTime { get; set; }
6 | public string Type { get; set; }
7 | public string Description { get; set; }
8 | public int? UserID { get; set; }
9 | public string Name { get; set; }
10 | public object ID { get; set; }
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/IStreamResponse.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | ///
4 | /// This interface is used to pass a Stream to send to the client. It implements IDisposable to allow for cleanup
5 | /// of the Stream and any other unmanaged resources (like the database connections, for example). Because using
6 | /// statements would fall out of scope when a controller action returns, the Stream would be disposed before it
7 | /// could be used. This interface allows for the Stream to be used and then disposed of when the client is done by
8 | /// registering it with the HttpResponse RegisterForDispose method.
9 | ///
10 | public interface IStreamResponse : IDisposable
11 | {
12 | Stream Stream { get; }
13 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ModerationLogEntry.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ModerationLogEntry
4 | {
5 | public int ModerationID { get; set; }
6 | public DateTime TimeStamp { get; set; }
7 | public int UserID { get; set; }
8 | public string UserName { get; set; }
9 | public ModerationType ModerationType { get; set; }
10 | public string ModerationTypeString => ModerationType.ToString();
11 | public int? ForumID { get; set; }
12 | public int TopicID { get; set; }
13 | public int? PostID { get; set; }
14 | public string Comment { get; set; }
15 | public string OldText { get; set; }
16 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ModerationType.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public enum ModerationType
4 | {
5 | NotSet = 0,
6 | PostEdit = 1,
7 | PostDelete = 2,
8 | PostDeletePermanently = 3,
9 | TopicEdit = 4,
10 | TopicDelete = 5,
11 | TopicDeletePermanently = 6,
12 | TopicClose = 7,
13 | TopicOpen = 8,
14 | TopicPin = 9,
15 | TopicUnpin = 10,
16 | TopicMoved = 11,
17 | TopicUndelete = 12,
18 | PostUndelete = 13,
19 | TopicRenamed = 14,
20 | TopicCloseAuto = 15
21 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ModifyForumRolesContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ModifyForumRolesContainer
4 | {
5 | public int ForumID { get; set; }
6 | public ModifyForumRolesType ModifyType { get; set; }
7 | public string Role { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ModifyForumRolesType.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public enum ModifyForumRolesType
4 | {
5 | AddView,
6 | RemoveView,
7 | AddPost,
8 | RemovePost,
9 | RemoveAllView,
10 | RemoveAllPost
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/NewPost.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class NewPost
4 | {
5 | public string Title { get; set; }
6 | public string FullText { get; set; }
7 | public bool IncludeSignature { get; set; }
8 | ///
9 | /// The ForumID or TopicID the post will be associated with.
10 | ///
11 | public int ItemID { get; set; }
12 | public bool CloseOnReply { get; set; }
13 | public bool IsPlainText { get; set; }
14 | public bool IsImageEnabled { get; set; }
15 | public int ParentPostID { get; set; }
16 | public string[] PostImageIDs { get; set; }
17 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PagedListOfT.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PagedList : PagerContext where T : class
4 | {
5 | public IEnumerable List { get; set; }
6 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PagedTopicContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PagedTopicContainer
4 | {
5 | public PagedTopicContainer()
6 | {
7 | ReadStatusLookup = new Dictionary();
8 | }
9 |
10 | public List Topics { get; set; }
11 | public PagerContext PagerContext { get; set; }
12 | public Dictionary ReadStatusLookup { get; private set; }
13 | public Dictionary ForumTitles { get; set; }
14 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PagerContext.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PagerContext
4 | {
5 | public int PageCount { get; set; }
6 | public int PageIndex { get; set; }
7 | public int PageSize { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PasswordResetContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PasswordResetContainer
4 | {
5 | public bool IsValidUser { get; set; }
6 | public string Password { get; set; }
7 | public string PasswordRetype { get; set; }
8 | public string Result { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PermanentRoles.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public static class PermanentRoles
4 | {
5 | public const string Admin = "Admin";
6 | public const string Moderator = "Moderator";
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/Post.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class Post
4 | {
5 | public int PostID { get; set; }
6 | public int TopicID { get; set; }
7 | public int ParentPostID { get; set; }
8 | public string IP { get; set; }
9 | public bool IsFirstInTopic { get; set; }
10 | public bool ShowSig { get; set; }
11 | public int UserID { get; set; }
12 | public string Name { get; set; }
13 | public string Title { get; set; }
14 | public string FullText { get; set; }
15 | public DateTime PostTime { get; set; }
16 | public bool IsEdited { get; set; }
17 | public string LastEditName { get; set; }
18 | public DateTime? LastEditTime { get; set; }
19 | public bool IsDeleted { get; set; }
20 | public int Votes { get; set; }
21 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PostEdit.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PostEdit
4 | {
5 | public PostEdit() {}
6 |
7 | public PostEdit(Post post)
8 | {
9 | Title = post.Title;
10 | FullText = post.FullText;
11 | ShowSig = post.ShowSig;
12 | }
13 |
14 | public string Title { get; set; }
15 | public string FullText { get; set; }
16 | public bool ShowSig { get; set; }
17 | public string Comment { get; set; }
18 | public bool IsPlainText { get; set; }
19 | public bool IsFirstInTopic { get; set; }
20 | public string[] PostImageIDs { get; set; }
21 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PostImage.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PostImage
4 | {
5 | public string ID { get; init; }
6 | public DateTime TimeStamp { get; init; }
7 | public string TenantID { get; init; }
8 | public string ContentType { get; init; }
9 | public byte[] ImageData { get; init; }
10 |
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PostImagePersistPayload.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PostImagePersistPayload
4 | {
5 | public string Url { get; set; }
6 | public string ID { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PostItemContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PostItemContainer
4 | {
5 | public Post Post { get; set; }
6 | public List VotedPostIDs { get; set; }
7 | public Dictionary Signatures { get; set; }
8 | public Dictionary Avatars { get; set; }
9 | public User User { get; set; }
10 | public Profile Profile { get; set; }
11 | public Topic Topic { get; set; }
12 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PostWithChildren.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PostWithChildren
4 | {
5 | public Post Post { get; set; }
6 | public List Children { get; set; }
7 | public DateTime? LastReadTime { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PrivateMessage.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PrivateMessage
4 | {
5 | public int PMID { get; set; }
6 | public DateTime LastPostTime { get; set; }
7 | public JsonElement Users { get; set; }
8 | public DateTime LastViewDate { get; set; }
9 |
10 | public static string GetUserNames(PrivateMessage pm, int excludeUserID)
11 | {
12 | var users = pm.Users.Deserialize(new JsonSerializerOptions{PropertyNamingPolicy = JsonNamingPolicy.CamelCase});
13 | if (users == null)
14 | return string.Empty;
15 | var names = new List();
16 | foreach (var item in users)
17 | {
18 | if (item.UserID != excludeUserID)
19 | names.Add(item.Name as string);
20 | }
21 | var result = string.Join(", ", names);
22 | return result;
23 | }
24 |
25 | private class UserNamePair
26 | {
27 | public int UserID { get; set; }
28 | public string Name { get; set; }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PrivateMessageBoxType.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public enum PrivateMessageBoxType
4 | {
5 | Inbox = 1,
6 | Archive = 2
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PrivateMessagePost.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PrivateMessagePost
4 | {
5 | public int PMPostID { get; set; }
6 | public int PMID { get; set; }
7 | public int UserID { get; set; }
8 | public string Name { get; set; }
9 | public DateTime PostTime { get; set; }
10 | public string FullText { get; set; }
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PrivateMessageState.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PrivateMessageState
4 | {
5 | public int PmID { get; set; }
6 | public JsonElement Users { get; set; }
7 | public ClientPrivateMessagePost[] Messages { get; set; }
8 | public int? NewestPostID { get; set; }
9 | public bool IsUserNotFound { get; set; }
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PrivateMessageUser.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PrivateMessageUser
4 | {
5 | public int PMID { get; set; }
6 | public int UserID { get; set; }
7 | public DateTime LastViewDate { get; set; }
8 | public bool IsArchived { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/PrivateMessageView.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class PrivateMessageView
4 | {
5 | public PrivateMessage PrivateMessage { get; set; }
6 | public PrivateMessageState State { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/Profile.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class Profile
4 | {
5 | public int UserID { get; set; }
6 | public bool IsSubscribed { get; set; }
7 | public string Signature { get; set; }
8 | public bool ShowDetails { get; set; }
9 | public string Location { get; set; }
10 | public bool IsPlainText { get; set; }
11 | public DateTime? Dob { get; set; }
12 | public string Web { get; set; }
13 | public string Facebook { get; set; }
14 | public string Instagram { get; set; }
15 | public bool IsTos { get; set; }
16 | public int? AvatarID { get; set; }
17 | public int? ImageID { get; set; }
18 | public bool HideVanity { get; set; }
19 | public int? LastPostID { get; set; }
20 | public int Points { get; set; }
21 | public bool IsAutoFollowOnReply { get; set; }
22 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/QAPostItemContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class QAPostItemContainer : PostItemContainer
4 | {
5 | public PostWithChildren PostWithChildren { get; set; }
6 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/QueuedEmailMessage.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class QueuedEmailMessage : EmailMessage
4 | {
5 | public int MessageID { get; set; }
6 | public DateTime QueueTime { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ReadStatus.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | [Flags]
4 | public enum ReadStatus
5 | {
6 | NoNewPosts = 1,
7 | NewPosts = 2,
8 | Closed = 4,
9 | Open = 8,
10 | Pinned = 16,
11 | NotPinned = 32
12 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ResponseOfT.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | ///
4 | /// A generic container for wrapping the response of external calls for consumption by internal service.
5 | ///
6 | ///
7 | public class Response where T : class
8 | {
9 | ///
10 | /// Creates a generic Response with IsValid set to true and no debug information or exception.
11 | ///
12 | /// The strongly typed result to be consumed by the caller.
13 | public Response(T data)
14 | {
15 | Data = data;
16 | IsValid = true;
17 | }
18 |
19 | ///
20 | /// Creates a generic response with all fields set.
21 | ///
22 | ///
23 | /// Default is false.
24 | /// Default is null.
25 | /// Default is null.
26 | public Response(T data, bool isValid = false, Exception exception = null, string debugInfo = null)
27 | {
28 | Data = data;
29 | IsValid = isValid;
30 | Exception = exception;
31 | DebugInfo = debugInfo;
32 | }
33 |
34 | public T Data { get; }
35 | public bool IsValid { get; }
36 | public Exception Exception { get; }
37 | public string DebugInfo { get; }
38 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/SearchIndexPayload.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class SearchIndexPayload
4 | {
5 | public int TopicID { get; set; }
6 | public string TenantID { get; set; }
7 | public bool IsForRemoval { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/SearchType.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public enum SearchType
4 | {
5 | Rank,
6 | Date,
7 | Title,
8 | Name,
9 | Replies
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/SearchWord.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class SearchWord
4 | {
5 | public string Word { get; set; }
6 | public int TopicID { get; set; }
7 | public int Rank { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/SecurityLogEntry.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class SecurityLogEntry
4 | {
5 | public int SecurityLogID { get; set; }
6 | public SecurityLogType SecurityLogType { get; set; }
7 | public string SecurityLogTypeString => SecurityLogType.ToString();
8 | public int? UserID { get; set; }
9 | public int? TargetUserID { get; set; }
10 | public string IP { get; set; }
11 | public string Message { get; set; }
12 | public DateTime ActivityDate { get; set; }
13 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/SecurityLogType.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public enum SecurityLogType
4 | {
5 | Undefined = 0,
6 | Login = 1,
7 | Logout = 2,
8 | PasswordChange = 3,
9 | EmailChange = 4,
10 | FailedLogin = 5,
11 | UserCreated = 6,
12 | UserDeleted = 7,
13 | RoleCreated = 8,
14 | RoleDeleted = 9,
15 | UserAddedToRole = 10,
16 | UserRemovedFromRole = 11,
17 | UserSessionStart = 12,
18 | UserSessionEnd = 13,
19 | NameChange = 14,
20 | IsApproved = 15,
21 | IsNotApproved = 16,
22 | ExternalAssociationSet = 17,
23 | ExternalAssociationRemoved = 18,
24 | ExternalAssociationCheckSuccessful = 19,
25 | ExternalAssociationCheckFailed = 20,
26 | ReCaptchaFailed = 21,
27 | ExternalLoginChallengeFailed = 22
28 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/ServiceHeartbeat.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class ServiceHeartbeat
4 | {
5 | public string ServiceName { get; set; }
6 | public string MachineName { get; set; }
7 | public DateTime LastRun { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/SetupVariables.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class SetupVariables
4 | {
5 | public string Name { get; set; }
6 | public string Email { get; set; }
7 | public string Password { get; set; }
8 | public string ForumTitle { get; set; }
9 | public string SmtpServer { get; set; }
10 | public int SmtpPort { get; set; }
11 | public string MailerAddress { get; set; }
12 | public bool UseEsmtp { get; set; }
13 | public string SmtpUser { get; set; }
14 | public string SmtpPassword { get; set; }
15 | public bool UseSslSmtp { get; set; }
16 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/SignupData.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class SignupData
4 | {
5 | public string Name { get; set; }
6 | public string Email { get; set; }
7 | public string Password { get; set; }
8 | public string PasswordRetype { get; set; }
9 | public bool IsSubscribed { get; set; }
10 | public bool IsCoppa { get; set; }
11 | public bool IsTos { get; set; }
12 | public string Token { get; set; }
13 | public bool IsAutoFollowOnReply { get; set; }
14 |
15 | public static string GetCoppaDate()
16 | {
17 | return DateTime.Now.AddYears(-13).ToString("D");
18 | }
19 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/SingleString.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class SingleString
4 | {
5 | public string String { get; set; }
6 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/SubscribeNotificationPayload.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class SubscribeNotificationPayload
4 | {
5 | public int TopicID { get; set; }
6 | public string TopicTitle { get; set; }
7 | public int PostingUserID { get; set; }
8 | public string PostingUserName { get; set; }
9 | public string TenantID { get; set; }
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/TimeFormats.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class TimeFormats
4 | {
5 | public string TodayTime { get; set; }
6 | public string YesterdayTime { get; set; }
7 | public string MinutesAgo { get; set; }
8 | public string OneMinuteAgo { get; set; }
9 | public string LessThanMinute { get; set; }
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/Topic.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class Topic
4 | {
5 | public int TopicID { get; set; }
6 | public int ForumID { get; set; }
7 | public string Title { get; set; }
8 | public int ReplyCount { get; set; }
9 | public int ViewCount { get; set; }
10 | public int StartedByUserID { get; set; }
11 | public string StartedByName { get; set; }
12 | public int LastPostUserID { get; set; }
13 | public string LastPostName { get; set; }
14 | public DateTime LastPostTime { get; set; }
15 | public bool IsClosed { get; set; }
16 | public bool IsPinned { get; set; }
17 | public bool IsDeleted { get; set; }
18 | public string UrlName { get; set; }
19 | public int? AnswerPostID { get; set; }
20 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/TopicContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class TopicContainer
4 | {
5 | public Forum Forum { get; set; }
6 | public Topic Topic { get; set; }
7 | public List Posts { get; set; }
8 | public PagerContext PagerContext { get; set; }
9 | public ForumPermissionContext PermissionContext { get; set; }
10 | public Dictionary Signatures { get; set; }
11 | public Dictionary Avatars { get; set; }
12 | public List VotedPostIDs { get; set; }
13 | public DateTime? LastReadTime { get; set; }
14 | public TopicState TopicState { get; set; }
15 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/TopicContainerForQA.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class TopicContainerForQA : TopicContainer
4 | {
5 | public PostWithChildren QuestionPostWithComments { get; set; }
6 | public List AnswersWithComments { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/TopicState.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class TopicState
4 | {
5 | public int TopicID { get; set; }
6 | public bool IsImageEnabled { get; set; }
7 | public bool IsSubscribed { get; set; }
8 | public bool IsFavorite { get; set; }
9 | public int? PageIndex { get; set; }
10 | public int? PageCount { get; set; }
11 | public int LastVisiblePostID { get; set; }
12 | public int? AnswerPostID { get; set; }
13 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/TopicUnsubscribeContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class TopicUnsubscribeContainer
4 | {
5 | public User User { get; set; }
6 | public Topic Topic { get; set; }
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/User.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class User
4 | {
5 | public int UserID { get; set; }
6 | public DateTime CreationDate { get; set; }
7 | public string Name { get; set; }
8 | public string Email { get; set; }
9 | public Guid AuthorizationKey { get; set; }
10 | public bool IsApproved { get; set; }
11 | public DateTime? TokenExpiration { get; set; }
12 | public List Roles { get; set; }
13 |
14 | public bool IsInRole(string role)
15 | {
16 | if (Roles == null)
17 | throw new Exception("Roles not set for user.");
18 | return Roles.Contains(role);
19 | }
20 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/UserEditProfile.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class UserEditProfile
4 | {
5 | public UserEditProfile() {}
6 |
7 | public UserEditProfile(Profile profile)
8 | {
9 | IsSubscribed = profile.IsSubscribed;
10 | Signature = profile.Signature;
11 | ShowDetails = profile.ShowDetails;
12 | Location = profile.Location;
13 | IsPlainText = profile.IsPlainText;
14 | Dob = profile.Dob;
15 | Web = profile.Web;
16 | Instagram = profile.Instagram;
17 | Facebook = profile.Facebook;
18 | HideVanity = profile.HideVanity;
19 | IsAutoFollowOnReply = profile.IsAutoFollowOnReply;
20 | }
21 |
22 | public bool IsSubscribed { get; set; }
23 | public string Signature { get; set; }
24 | public bool ShowDetails { get; set; }
25 | public string Location { get; set; }
26 | public bool IsPlainText { get; set; }
27 | public DateTime? Dob { get; set; }
28 | public string Web { get; set; }
29 | public string Instagram { get; set; }
30 | public string Facebook { get; set; }
31 | public bool HideVanity { get; set; }
32 | public bool IsAutoFollowOnReply { get; set; }
33 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/UserEditSecurity.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class UserEditSecurity
4 | {
5 | public UserEditSecurity() {}
6 |
7 | public UserEditSecurity(User user, bool isNewUserApproved)
8 | {
9 | OldEmail = user.Email;
10 | IsNewUserApproved = isNewUserApproved;
11 | }
12 |
13 | public string OldPassword { get; set; }
14 | public string NewPassword { get; set; }
15 | public string NewPasswordRetype { get; set; }
16 | public string OldEmail { get; private set; }
17 | public string NewEmail { get; set; }
18 | public string NewEmailRetype { get; set; }
19 | public bool IsNewUserApproved { get; set; }
20 |
21 | public bool NewPasswordsMatch()
22 | {
23 | if (String.IsNullOrWhiteSpace(NewPassword) || String.IsNullOrWhiteSpace(NewPasswordRetype))
24 | return false;
25 | return NewPassword == NewPasswordRetype;
26 | }
27 |
28 | public bool NewEmailsMatch()
29 | {
30 | if (String.IsNullOrWhiteSpace(NewEmail) || String.IsNullOrWhiteSpace(NewEmailRetype))
31 | return false;
32 | return NewEmail == NewEmailRetype;
33 | }
34 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/UserImage.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class UserImage
4 | {
5 | public int UserImageID { get; set; }
6 | public int UserID { get; set; }
7 | public int SortOrder { get; set; }
8 | public bool IsApproved { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/UserImageApprovalContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class UserImageApprovalContainer
4 | {
5 | public bool IsNewUserImageApproved { get; set; }
6 | public List Unapproved { get; set; }
7 | }
8 |
9 | public class UserImagePair
10 | {
11 | public User User { get; set; }
12 | public UserImage UserImage { get; set; }
13 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/UserResult.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class UserResult
4 | {
5 | public int UserID { get; set; }
6 | public string Name { get; set; }
7 | public string Email { get; set; }
8 | public DateTime CreationDate { get; set; }
9 | public string IP { get; set; }
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/UserSearch.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class UserSearch
4 | {
5 | public string SearchText { get; set; }
6 | public UserSearchType SearchType { get; set; }
7 |
8 | public enum UserSearchType
9 | {
10 | Name, Email, Role
11 | }
12 | }
--------------------------------------------------------------------------------
/src/PopForums/Models/VotePostContainer.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Models;
2 |
3 | public class VotePostContainer
4 | {
5 | public int PostID { get; set; }
6 | public int Votes { get; set; }
7 | public Dictionary Voters { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IAwardCalculationQueueRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IAwardCalculationQueueRepository
4 | {
5 | Task Enqueue(AwardCalculationPayload payload);
6 | Task> Dequeue();
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IAwardConditionRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IAwardConditionRepository
4 | {
5 | Task> GetConditions(string awardDefinitionID);
6 | Task DeleteConditions(string awardDefinitionID);
7 | Task SaveConditions(List conditions);
8 | Task DeleteConditionsByEventDefinitionID(string eventDefinitionID);
9 | Task DeleteCondition(string awardDefinitionID, string eventDefinitionID);
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IAwardDefinitionRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IAwardDefinitionRepository
4 | {
5 | Task Get(string awardDefinitionID);
6 | Task> GetAll();
7 | Task> GetByEventDefinitionID(string eventDefinitionID);
8 | Task Create(string awardDefinitionID, string title, string description, bool isSingleTimeAward);
9 | Task Delete(string awardDefinitionID);
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IBanRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IBanRepository
4 | {
5 | Task BanIP(string ip);
6 | Task RemoveIPBan(string ip);
7 | Task> GetIPBans();
8 | Task IPIsBanned(string ip);
9 | Task BanEmail(string email);
10 | Task RemoveEmailBan(string email);
11 | Task> GetEmailBans();
12 | Task EmailIsBanned(string email);
13 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ICategoryRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ICategoryRepository
4 | {
5 | Task Get(int categoryID);
6 | Task> GetAll();
7 | Task Create(string newTitle, int sortOrder);
8 | Task Delete(int categoryID);
9 | Task Update(Category category);
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IEmailQueueRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IEmailQueueRepository
4 | {
5 | Task Enqueue(EmailQueuePayload payload);
6 | Task Dequeue();
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IErrorLogRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IErrorLogRepository
4 | {
5 | Task Create(DateTime timeStamp, string message, string stackTrace, string data, ErrorSeverity severity);
6 | Task GetErrorCount();
7 | Task> GetErrors(int startRow, int pageSize);
8 | Task DeleteError(int errorID);
9 | Task DeleteAllErrors();
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IEventDefinitionRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IEventDefinitionRepository
4 | {
5 | Task Get(string eventDefinitionID);
6 | Task> GetAll();
7 | Task Create(EventDefinition eventDefinition);
8 | void Delete(string eventDefinitionID);
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IExternalUserAssociationRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IExternalUserAssociationRepository
4 | {
5 | Task Get(string issuer, string providerKey);
6 | Task Get(int externalUserAssociationID);
7 | Task> GetByUser(int userID);
8 | Task Save(int userID, string issuer, string providerKey, string name);
9 | Task Delete(int externalUserAssociationID);
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IFavoriteTopicsRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IFavoriteTopicsRepository
4 | {
5 | Task> GetFavoriteTopics(int userID, int startRow, int pageSize);
6 | Task GetFavoriteTopicCount(int userID);
7 | Task IsTopicFavorite(int userID, int topicID);
8 | Task AddFavoriteTopic(int userID, int topicID);
9 | Task RemoveFavoriteTopic(int userID, int topicID);
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IFeedRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IFeedRepository
4 | {
5 | Task> GetFeed(int userID, int itemCount);
6 | Task PublishEvent(int userID, string message, int points, DateTime timeStamp);
7 | Task GetOldestTime(int userID, int takeCount);
8 | Task DeleteOlderThan(int userID, DateTime timeCutOff);
9 | Task> GetFeed(int itemCount);
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ILastReadRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ILastReadRepository
4 | {
5 | Task SetForumRead(int userID, int forumID, DateTime readTime);
6 | Task DeleteTopicReadsInForum(int userID, int forumID);
7 | Task SetAllForumsRead(int userID, DateTime readTime);
8 | Task DeleteAllTopicReads(int userID);
9 | Task SetTopicRead(int userID, int topicID, DateTime readTime);
10 | Task> GetLastReadTimesForForums(int userID);
11 | Task GetLastReadTimesForForum(int userID, int forumID);
12 | Task> GetLastReadTimesForTopics(int userID, IEnumerable topicIDs);
13 | Task GetLastReadTimeForTopic(int userID, int topicID);
14 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IModerationLogRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IModerationLogRepository
4 | {
5 | Task Log(DateTime timeStamp, int userID, string userName, int moderationType, int? forumID, int topicID, int? postID, string comment, string oldText);
6 | Task> GetLog(DateTime start, DateTime end);
7 | Task> GetLog(int topicID, bool excludePostEntries);
8 | Task> GetLog(int postID);
9 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/INotificationRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface INotificationRepository
4 | {
5 | Task UpdateNotification(Notification notification);
6 | Task CreateNotification(Notification notification);
7 | Task MarkNotificationRead(int userID, NotificationType notificationType, long contextID);
8 | Task> GetNotifications(int userID, DateTime afterDateTime, int pageSize);
9 | Task GetPageCount(int userID, int pageSize);
10 | Task GetUnreadNotificationCount(int userID);
11 | Task MarkAllRead(int userID);
12 | Task DeleteOlderThan(int userID, DateTime timeCutOff);
13 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IPointLedgerRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IPointLedgerRepository
4 | {
5 | Task RecordEntry(PointLedgerEntry entry);
6 | Task GetPointTotal(int userID);
7 | Task GetEntryCount(int userID, string eventDefinitionID);
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IPostImageRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IPostImageRepository
4 | {
5 | Task Persist(byte[] bytes, string contentType);
6 | Task GetWithoutData(string id);
7 | [Obsolete("Use the combination of GetWithoutData(int) and GetImageStream(int) instead.")]
8 | Task Get(string id);
9 | Task DeletePostImageData(string id, string tenantID);
10 | Task GetImageStream(string id);
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IPostImageTempRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IPostImageTempRepository
4 | {
5 | Task Save(Guid postImageTempID, DateTime timeStamp, string tenantID);
6 | Task Delete(Guid id);
7 | Task> GetOld(DateTime olderThan);
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IPrivateMessageRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IPrivateMessageRepository
4 | {
5 | Task Get(int pmID, int userID);
6 | Task> GetPosts(int pmID, DateTime afterDateTime);
7 | Task> GetPosts(int pmID, DateTime beforeDateTime, int pageSize);
8 | Task CreatePrivateMessage(PrivateMessage pm);
9 | Task AddUsers(int pmID, List userIDs, DateTime viewDate, bool isArchived);
10 | Task AddPost(PrivateMessagePost post);
11 | Task> GetUsers(int pmID);
12 | Task SetLastViewTime(int pmID, int userID, DateTime viewDate);
13 | Task SetArchive(int pmID, int userID, bool isArchived);
14 | Task> GetPrivateMessages(int userID, PrivateMessageBoxType boxType, int startRow, int pageSize);
15 | Task GetUnreadCount(int userID);
16 | Task GetBoxCount(int userID, PrivateMessageBoxType boxType);
17 | Task UpdateLastPostTime(int pmID, DateTime lastPostTime);
18 | Task GetExistingFromIDs(List ids);
19 | Task GetFirstUnreadPostID(int pmID, DateTime lastReadTime);
20 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IProfileRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IProfileRepository
4 | {
5 | Task GetProfile(int userID);
6 | Task Create(Profile profile);
7 | Task Update(Profile profile);
8 | Task GetLastPostID(int userID);
9 | Task SetLastPostID(int userID, int postID);
10 | Task> GetSignatures(List userIDs);
11 | Task> GetAvatars(List userIDs);
12 | Task SetCurrentImageIDToNull(int userID);
13 | Task UpdatePoints(int userID, int points);
14 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IQueuedEmailMessageRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IQueuedEmailMessageRepository
4 | {
5 | Task CreateMessage(QueuedEmailMessage message);
6 | Task DeleteMessage(int messageID);
7 | Task GetMessage(int messageID);
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IRoleRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IRoleRepository
4 | {
5 | Task CreateRole(string role);
6 | Task DeleteRole(string role);
7 | Task> GetAllRoles();
8 | Task> GetUserRoles(int userID);
9 | Task ReplaceUserRoles(int userID, string[] roles);
10 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ISearchIndexQueueRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ISearchIndexQueueRepository
4 | {
5 | Task Enqueue(SearchIndexPayload payload);
6 | Task Dequeue();
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ISearchRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ISearchRepository
4 | {
5 | Task> GetJunkWords();
6 | Task CreateJunkWord(string word);
7 | Task DeleteJunkWord(string word);
8 | Task DeleteAllIndexedWordsForTopic(int topicID);
9 | Task SaveSearchWord(int topicID, string word, int rank);
10 | Task>, int>> SearchTopics(string searchTerm, List hiddenForums, SearchType searchType, int startRow, int pageSize);
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ISecurityLogRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ISecurityLogRepository
4 | {
5 | Task Create(SecurityLogEntry logEntry);
6 | Task> GetByUserID(int userID, DateTime startDate, DateTime endDate);
7 | Task> GetIPHistory(string ip, DateTime start, DateTime end);
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IServiceHeartbeatRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IServiceHeartbeatRepository
4 | {
5 | Task RecordHeartbeat(string serviceName, string machineName, DateTime lastRun);
6 | Task> GetAll();
7 | Task ClearAll();
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ISettingsRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ISettingsRepository
4 | {
5 | Dictionary Get();
6 | void Save(Dictionary dictionary);
7 | event Action OnSettingsInvalidated;
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ISetupRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ISetupRepository
4 | {
5 | bool IsConnectionPossible();
6 | bool IsDatabaseSetup();
7 | void SetupDatabase();
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ISubscribeNotificationRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ISubscribeNotificationRepository
4 | {
5 | Task Enqueue(SubscribeNotificationPayload payload);
6 | Task Dequeue();
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ISubscribedTopicsRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ISubscribedTopicsRepository
4 | {
5 | Task> GetSubscribedTopics(int userID, int startRow, int pageSize);
6 | Task GetSubscribedTopicCount(int userID);
7 | Task IsTopicSubscribed(int userID, int topicID);
8 | Task AddSubscribedTopic(int userID, int topicID);
9 | Task RemoveSubscribedTopic(int userID, int topicID);
10 | Task> GetSubscribedUserIDs(int topicID);
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/ITopicViewLogRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface ITopicViewLogRepository
4 | {
5 | Task Log(int? userID, int topicID, DateTime timeStamp);
6 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IUserAvatarRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IUserAvatarRepository
4 | {
5 | [Obsolete("Use GetImageData(int) instead.")]
6 | Task GetImageData(int userAvatarID);
7 | Task GetImageStream(int userAvatarID);
8 | Task> GetUserAvatarIDs(int userID);
9 | Task SaveNewAvatar(int userID, byte[] imageData, DateTime timeStamp);
10 | Task DeleteAvatarsByUserID(int userID);
11 | Task GetLastModificationDate(int userAvatarID);
12 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IUserAwardRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IUserAwardRepository
4 | {
5 | Task IssueAward(int userID, string awardDefinitionID, string title, string description, DateTime timeStamp);
6 | Task IsAwarded(int userID, string awardDefinitionID);
7 | Task> GetAwards(int userID);
8 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IUserImageRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IUserImageRepository
4 | {
5 | [Obsolete("Use GetImageStream instead.")]
6 | Task GetImageData(int userImageID);
7 | Task GetImageStream(int userImageID);
8 | Task> GetUserImages(int userID);
9 | Task SaveNewImage(int userID, int sortOrder, bool isApproved, byte[] imageData, DateTime timeStamp);
10 | Task DeleteImagesByUserID(int userID);
11 | Task GetLastModificationDate(int userImageID);
12 | Task> GetUnapprovedUserImages();
13 | Task IsUserImageApproved(int userImageID);
14 | Task ApproveUserImage(int userImageID);
15 | Task DeleteUserImage(int userImageID);
16 | Task Get(int userImageID);
17 | }
--------------------------------------------------------------------------------
/src/PopForums/Repositories/IUserSessionRepository.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Repositories;
2 |
3 | public interface IUserSessionRepository
4 | {
5 | Task CreateSession(int sessionID, int? userID, DateTime lastTime);
6 | Task UpdateSession(int sessionID, DateTime lastTime);
7 | Task IsSessionAnonymous(int sessionID);
8 | Task> GetAndDeleteExpiredSessions(DateTime cutOffDate);
9 | Task GetSessionIDByUserID(int userID);
10 | Task DeleteSessions(int? userID, int sessionID);
11 | Task GetTotalSessionCount();
12 | }
--------------------------------------------------------------------------------
/src/PopForums/ScoringGame/AwardCalculatorWorker.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ScoringGame;
2 |
3 | public interface IAwardCalculatorWorker
4 | {
5 | void Execute();
6 | }
7 |
8 | public class AwardCalculatorWorker(IAwardCalculator calculator, IAwardCalculationQueueRepository awardCalculationQueueRepository, IErrorLog errorLog) : IAwardCalculatorWorker
9 | {
10 | public async void Execute()
11 | {
12 | try
13 | {
14 | var nextItem = await awardCalculationQueueRepository.Dequeue();
15 | if (string.IsNullOrEmpty(nextItem.Key))
16 | return;
17 | await calculator.ProcessCalculation(nextItem.Key, nextItem.Value);
18 | }
19 | catch (Exception exc)
20 | {
21 | errorLog.Log(exc, ErrorSeverity.Error);
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/PopForums/ScoringGame/AwardCondition.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ScoringGame;
2 |
3 | public class AwardCondition
4 | {
5 | public string AwardDefinitionID { get; set; }
6 | public string EventDefinitionID { get; set; }
7 | public int EventCount { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/PopForums/ScoringGame/AwardDefinition.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ScoringGame;
2 |
3 | public class AwardDefinition
4 | {
5 | public string AwardDefinitionID { get; set; }
6 | public string Title { get; set; }
7 | public string Description { get; set; }
8 | public bool IsSingleTimeAward { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/ScoringGame/EventDefinition.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ScoringGame;
2 |
3 | public class EventDefinition
4 | {
5 | public string EventDefinitionID { get; set; }
6 | public string Description { get; set; }
7 | public int PointValue { get; set; }
8 | public bool IsPublishedToFeed { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/ScoringGame/PointLedgerEntry.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ScoringGame;
2 |
3 | public class PointLedgerEntry
4 | {
5 | public int UserID { get; set; }
6 | public string EventDefinitionID { get; set; }
7 | public int Points { get; set; }
8 | public DateTime TimeStamp { get; set; }
9 | }
--------------------------------------------------------------------------------
/src/PopForums/ScoringGame/UserAward.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.ScoringGame;
2 |
3 | public class UserAward
4 | {
5 | public int UserAwardID { get; set; }
6 | public int UserID { get; set; }
7 | public string AwardDefinitionID { get; set; }
8 | public string Title { get; set; }
9 | public string Description { get; set; }
10 | public DateTime TimeStamp { get; set; }
11 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/BanService.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface IBanService
4 | {
5 | Task BanIP(string ip);
6 | Task RemoveIPBan(string ip);
7 | Task> GetIPBans();
8 | Task BanEmail(string email);
9 | Task RemoveEmailBan(string email);
10 | Task> GetEmailBans();
11 | }
12 |
13 | public class BanService : IBanService
14 | {
15 | public BanService(IBanRepository banRepsoitory)
16 | {
17 | _banRepository = banRepsoitory;
18 | }
19 |
20 | private readonly IBanRepository _banRepository;
21 |
22 | public async Task BanIP(string ip)
23 | {
24 | await _banRepository.BanIP(ip.Trim());
25 | }
26 |
27 | public async Task RemoveIPBan(string ip)
28 | {
29 | await _banRepository.RemoveIPBan(ip);
30 | }
31 |
32 | public async Task> GetIPBans()
33 | {
34 | return await _banRepository.GetIPBans();
35 | }
36 |
37 | public async Task BanEmail(string email)
38 | {
39 | await _banRepository.BanEmail(email.Trim());
40 | }
41 |
42 | public async Task RemoveEmailBan(string email)
43 | {
44 | await _banRepository.RemoveEmailBan(email);
45 | }
46 |
47 | public async Task> GetEmailBans()
48 | {
49 | return await _banRepository.GetEmailBans();
50 | }
51 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/CloseAgedTopicsWorker.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface ICloseAgedTopicsWorker
4 | {
5 | void Execute();
6 | }
7 |
8 | public class CloseAgedTopicsWorker(ITopicService topicService, IErrorLog errorLog) : ICloseAgedTopicsWorker
9 | {
10 | public async void Execute()
11 | {
12 | try
13 | {
14 | await topicService.CloseAgedTopics();
15 | }
16 | catch (Exception exc)
17 | {
18 | errorLog.Log(exc, ErrorSeverity.Error);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/IPHistoryService.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface IIPHistoryService
4 | {
5 | Task> GetHistory(string ip, DateTime start, DateTime end);
6 | }
7 |
8 | public class IPHistoryService : IIPHistoryService
9 | {
10 | public IPHistoryService(IPostService postService, ISecurityLogService securityLogService)
11 | {
12 | _postService = postService;
13 | _securityLogService = securityLogService;
14 | }
15 |
16 | private readonly IPostService _postService;
17 | private readonly ISecurityLogService _securityLogService;
18 |
19 | public async Task> GetHistory(string ip, DateTime start, DateTime end)
20 | {
21 | var list = new List();
22 | list.AddRange(await _postService.GetIPHistory(ip, start, end));
23 | list.AddRange(await _securityLogService.GetIPHistory(ip, start, end));
24 | return list.OrderBy(i => i.EventTime).ToList();
25 | }
26 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/ITopicViewCountService.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface ITopicViewCountService
4 | {
5 | Task ProcessView(Topic topic);
6 | void SetViewedTopic(Topic topic);
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/IUserRetrievalShim.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface IUserRetrievalShim
4 | {
5 | User GetUser();
6 | Profile GetProfile();
7 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/PostImageCleanupWorker.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface IPostImageCleanupWorker
4 | {
5 | void Execute();
6 | }
7 |
8 | public class PostImageCleanupWorker(IPostImageService postImageService, IErrorLog errorLog) : IPostImageCleanupWorker
9 | {
10 | public async void Execute()
11 | {
12 | try
13 | {
14 | await postImageService.DeleteOldPostImages();
15 | }
16 | catch (Exception exc)
17 | {
18 | errorLog.Log(exc, ErrorSeverity.Error);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/QueuedEmailService.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface IQueuedEmailService
4 | {
5 | Task CreateAndQueueEmail(QueuedEmailMessage queuedEmailMessage);
6 | }
7 |
8 | public class QueuedEmailService : IQueuedEmailService
9 | {
10 | private readonly IQueuedEmailMessageRepository _queuedEmailMessageRepository;
11 | private readonly IEmailQueueRepository _emailQueueRepository;
12 | private readonly ITenantService _tenantService;
13 |
14 | public QueuedEmailService(IQueuedEmailMessageRepository queuedEmailMessageRepository, IEmailQueueRepository emailQueueRepository, ITenantService tenantService)
15 | {
16 | _queuedEmailMessageRepository = queuedEmailMessageRepository;
17 | _emailQueueRepository = emailQueueRepository;
18 | _tenantService = tenantService;
19 | }
20 |
21 | public async Task CreateAndQueueEmail(QueuedEmailMessage queuedEmailMessage)
22 | {
23 | var id = await _queuedEmailMessageRepository.CreateMessage(queuedEmailMessage);
24 | var tenantID = _tenantService.GetTenant();
25 | var payload = new EmailQueuePayload { MessageID = id, EmailQueuePayloadType = EmailQueuePayloadType.FullMessage, TenantID = tenantID };
26 | await _emailQueueRepository.Enqueue(payload);
27 | }
28 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/SearchIndexWorker.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface ISearchIndexWorker
4 | {
5 | void Execute();
6 | }
7 |
8 | public class SearchIndexWorker(IErrorLog errorLog, ISearchIndexSubsystem searchIndexSubsystem, ISearchService searchService) : ISearchIndexWorker
9 | {
10 | public async void Execute()
11 | {
12 | try
13 | {
14 | var payload = await searchService.GetNextTopicForIndexing();
15 | if (payload == null)
16 | return;
17 | searchIndexSubsystem.DoIndex(payload.TopicID, payload.TenantID, payload.IsForRemoval);
18 | }
19 | catch (Exception exc)
20 | {
21 | errorLog.Log(exc, ErrorSeverity.Error);
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/ServiceHeartbeatService.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface IServiceHeartbeatService
4 | {
5 | Task RecordHeartbeat(string serviceName, string machineName);
6 | Task> GetAll();
7 | Task ClearAll();
8 | }
9 |
10 | public class ServiceHeartbeatService : IServiceHeartbeatService
11 | {
12 | private readonly IServiceHeartbeatRepository _serviceHeartbeatRepository;
13 |
14 | public ServiceHeartbeatService(IServiceHeartbeatRepository serviceHeartbeatRepository)
15 | {
16 | _serviceHeartbeatRepository = serviceHeartbeatRepository;
17 | }
18 |
19 | public async Task RecordHeartbeat(string serviceName, string machineName)
20 | {
21 | await _serviceHeartbeatRepository.RecordHeartbeat(serviceName, machineName, DateTime.UtcNow);
22 | }
23 |
24 | public async Task> GetAll()
25 | {
26 | return await _serviceHeartbeatRepository.GetAll();
27 | }
28 |
29 | public async Task ClearAll()
30 | {
31 | await _serviceHeartbeatRepository.ClearAll();
32 | }
33 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/SubscribeNotificationWorker.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface ISubscribeNotificationWorker
4 | {
5 | void Execute();
6 | }
7 |
8 | public class SubscribeNotificationWorker(ISubscribeNotificationRepository subscribeNotificationRepository, ISubscribedTopicsService subscribedTopicsService, INotificationAdapter notificationAdapter, IErrorLog errorLog) : ISubscribeNotificationWorker
9 | {
10 | public async void Execute()
11 | {
12 | try
13 | {
14 | var payload = await subscribeNotificationRepository.Dequeue();
15 | if (payload == null)
16 | return;
17 | var userIDs = await subscribedTopicsService.GetSubscribedUserIDs(payload.TopicID);
18 | var filteredUserIDs = userIDs.Where(x => x != payload.PostingUserID);
19 | foreach (var userID in filteredUserIDs)
20 | await notificationAdapter.Reply(payload.PostingUserName, payload.TopicTitle, payload.TopicID, userID, payload.TenantID);
21 | }
22 | catch (Exception exc)
23 | {
24 | errorLog.Log(exc, ErrorSeverity.Error);
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/TenantService.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface ITenantService
4 | {
5 | void SetTenant(string tenantID);
6 | string GetTenant();
7 | }
8 |
9 | public class TenantService : ITenantService
10 | {
11 | public void SetTenant(string tenantID)
12 | {
13 | throw new NotImplementedException();
14 | }
15 |
16 | public string GetTenant()
17 | {
18 | return string.Empty;
19 | }
20 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/TimeFormatStringService.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface ITimeFormatStringService
4 | {
5 | TimeFormats GeTimeFormats();
6 | string GetTimeFormatsAsJson();
7 | }
8 |
9 | public class TimeFormatStringService : ITimeFormatStringService
10 | {
11 | public TimeFormats GeTimeFormats()
12 | {
13 | var formats = new TimeFormats
14 | {
15 | TodayTime = Resources.TodayTime,
16 | YesterdayTime = Resources.YesterdayTime,
17 | MinutesAgo = Resources.MinutesAgo,
18 | OneMinuteAgo = Resources.OneMinuteAgo,
19 | LessThanMinute = Resources.LessThanMinute
20 | };
21 | return formats;
22 | }
23 |
24 | public string GetTimeFormatsAsJson()
25 | {
26 | var formats = GeTimeFormats();
27 | var serialized = JsonSerializer.Serialize(formats, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
28 | return serialized;
29 | }
30 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/TopicViewLogService.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface ITopicViewLogService
4 | {
5 | Task LogView(int? userID, int topicID);
6 | }
7 |
8 | public class TopicViewLogService : ITopicViewLogService
9 | {
10 | private readonly IConfig _config;
11 | private readonly ITopicViewLogRepository _topicViewLogRepository;
12 |
13 | public TopicViewLogService(IConfig config, ITopicViewLogRepository topicViewLogRepository)
14 | {
15 | _config = config;
16 | _topicViewLogRepository = topicViewLogRepository;
17 | }
18 |
19 | public async Task LogView(int? userID, int topicID)
20 | {
21 | if (!_config.LogTopicViews)
22 | return;
23 | var timeStamp = DateTime.UtcNow;
24 | await _topicViewLogRepository.Log(userID, topicID, timeStamp);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/UserEmailReconciler.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface IUserEmailReconciler
4 | {
5 | Task GetUniqueEmail(string email, string externalID);
6 | }
7 |
8 | ///
9 | /// Checks for existing email addresses from an external identity provider. If a match is found, it mangles the address
10 | /// to use an "example.com" address, which is not real per IETF RFC 2606.
11 | ///
12 | public class UserEmailReconciler : IUserEmailReconciler
13 | {
14 | private readonly IUserRepository _userRepository;
15 |
16 | public UserEmailReconciler(IUserRepository userRepository)
17 | {
18 | _userRepository = userRepository;
19 | }
20 |
21 | public async Task GetUniqueEmail(string email, string externalID)
22 | {
23 | var match = await _userRepository.GetUserByEmail(email);
24 | if (match is null)
25 | return email;
26 |
27 | var uniqueEmail = $"{email.Replace("@","-at-")}@{externalID}.example.com";
28 | return uniqueEmail;
29 | }
30 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/UserNameReconciler.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface IUserNameReconciler
4 | {
5 | Task GetUniqueNameForUser(string name);
6 | }
7 |
8 | ///
9 | /// Used to make sure that incoming names from an external identity provider are unique. In other words, if there's
10 | /// a "John Smith," the next one becomes "John Smith-2."
11 | ///
12 | public class UserNameReconciler : IUserNameReconciler
13 | {
14 | private readonly IUserRepository _userRepository;
15 |
16 | public UserNameReconciler(IUserRepository userRepository)
17 | {
18 | _userRepository = userRepository;
19 | }
20 |
21 | public async Task GetUniqueNameForUser(string name)
22 | {
23 | var existingMatches = await _userRepository.GetUserNamesThatStartWith(name);
24 | var uniqueName = name.ToUniqueName(existingMatches.ToList());
25 | return uniqueName;
26 | }
27 | }
--------------------------------------------------------------------------------
/src/PopForums/Services/UserSessionWorker.cs:
--------------------------------------------------------------------------------
1 | namespace PopForums.Services;
2 |
3 | public interface IUserSessionWorker
4 | {
5 | void Execute();
6 | }
7 |
8 | public class UserSessionWorker(IUserSessionService sessionService, IErrorLog errorLog) : IUserSessionWorker
9 | {
10 | public async void Execute()
11 | {
12 | try
13 | {
14 | await sessionService.CleanUpExpiredSessions();
15 | }
16 | catch (Exception exc)
17 | {
18 | errorLog.Log(exc, ErrorSeverity.Error);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------