/src/Web/Modules/Plato.Questions.StopForumSpam/Controllers/HomeController.cs

https://github.com/InstantASP/plato · C# · 357 lines · 250 code · 66 blank · 41 comment · 41 complexity · 3a32feb5b1946c63c793f5253e98f273 MD5 · raw file

  1. using System;
  2. using System.Threading.Tasks;
  3. using Microsoft.AspNetCore.Authorization;
  4. using Microsoft.AspNetCore.Mvc;
  5. using Microsoft.AspNetCore.Mvc.Localization;
  6. using Microsoft.AspNetCore.Routing;
  7. using Microsoft.Extensions.Localization;
  8. using Microsoft.Extensions.Options;
  9. using Plato.Questions.Models;
  10. using Plato.Questions.StopForumSpam.ViewModels;
  11. using Plato.Entities.Models;
  12. using Plato.Entities.Stores;
  13. using Plato.Entities.ViewModels;
  14. using PlatoCore.Abstractions.Settings;
  15. using PlatoCore.Layout.Alerts;
  16. using PlatoCore.Models.Users;
  17. using PlatoCore.Security.Abstractions;
  18. using PlatoCore.Stores.Abstractions.Users;
  19. using Plato.StopForumSpam.Client.Models;
  20. using Plato.StopForumSpam.Client.Services;
  21. using Plato.StopForumSpam.Models;
  22. using Plato.StopForumSpam.Services;
  23. using Plato.StopForumSpam.Stores;
  24. using PlatoCore.Hosting.Web.Abstractions;
  25. namespace Plato.Questions.StopForumSpam.Controllers
  26. {
  27. public class HomeController : Controller
  28. {
  29. private readonly ISpamSettingsStore<SpamSettings> _spamSettingsStore;
  30. private readonly IAuthorizationService _authorizationService;
  31. private readonly IEntityReplyStore<Answer> _entityReplyStore;
  32. private readonly IPlatoUserStore<User> _platoUserStore;
  33. private readonly IEntityStore<Question> _entityStore;
  34. private readonly IContextFacade _contextFacade;
  35. private readonly ISpamChecker _spamChecker;
  36. private readonly ISpamClient _spamClient;
  37. private readonly IAlerter _alerter;
  38. private readonly PlatoOptions _platoOpts;
  39. public IHtmlLocalizer T { get; }
  40. public IStringLocalizer S { get; }
  41. public HomeController(
  42. IHtmlLocalizer<HomeController> htmlLocalizer,
  43. IStringLocalizer<HomeController> stringLocalizer,
  44. ISpamSettingsStore<SpamSettings> spamSettingsStore,
  45. IAuthorizationService authorizationService,
  46. IEntityReplyStore<Answer> entityReplyStore,
  47. IPlatoUserStore<User> platoUserStore,
  48. IOptions<PlatoOptions> platoOpts,
  49. IEntityStore<Question> entityStore,
  50. IContextFacade contextFacade,
  51. ISpamChecker spamChecker,
  52. ISpamClient spamClient,
  53. IAlerter alerter)
  54. {
  55. _authorizationService = authorizationService;
  56. _spamSettingsStore = spamSettingsStore;
  57. _entityReplyStore = entityReplyStore;
  58. _platoUserStore = platoUserStore;
  59. _contextFacade = contextFacade;
  60. _platoOpts = platoOpts.Value;
  61. _spamChecker = spamChecker;
  62. _entityStore = entityStore;
  63. _spamClient = spamClient;
  64. _alerter = alerter;
  65. T = htmlLocalizer;
  66. S = stringLocalizer;
  67. }
  68. // -----------------
  69. // Index
  70. // Displays a summary from StopForumSpam.
  71. // -----------------
  72. public async Task<IActionResult> Index(EntityOptions opts)
  73. {
  74. if (opts == null)
  75. {
  76. opts = new EntityOptions();
  77. }
  78. // We always need an entity Id
  79. if (opts.Id <= 0)
  80. {
  81. throw new ArgumentOutOfRangeException(nameof(opts.Id));
  82. }
  83. // We always need an entity
  84. var entity = await _entityStore.GetByIdAsync(opts.Id);
  85. if (entity == null)
  86. {
  87. return NotFound();
  88. }
  89. // Ensure we have permission
  90. if (!await _authorizationService.AuthorizeAsync(User, entity.CategoryId, Permissions.ViewStopForumSpam))
  91. {
  92. return Unauthorized();
  93. }
  94. // Get reply
  95. IEntityReply reply = null;
  96. if (opts.ReplyId > 0)
  97. {
  98. reply = await _entityReplyStore.GetByIdAsync(opts.ReplyId);
  99. if (reply == null)
  100. {
  101. return NotFound();
  102. }
  103. }
  104. // Get user to validate
  105. var user = reply != null
  106. ? await GetUserToValidateAsync(reply)
  107. : await GetUserToValidateAsync(entity);
  108. // Ensure we found the user
  109. if (user == null)
  110. {
  111. return NotFound();
  112. }
  113. // Build view model
  114. var viewModel = new StopForumSpamViewModel()
  115. {
  116. Options = opts,
  117. Checker = await _spamChecker.CheckAsync(user)
  118. };
  119. // Return view
  120. return View(viewModel);
  121. }
  122. // -----------------
  123. // AddSpammer
  124. // -----------------
  125. public async Task<IActionResult> AddSpammer(EntityOptions opts)
  126. {
  127. // Disable functionality within demo mode
  128. if (_platoOpts.DemoMode)
  129. {
  130. return Unauthorized();
  131. }
  132. // Empty options
  133. if (opts == null)
  134. {
  135. opts = new EntityOptions();
  136. }
  137. // Validate
  138. if (opts.Id <= 0)
  139. {
  140. throw new ArgumentOutOfRangeException(nameof(opts.Id));
  141. }
  142. // Get entity
  143. var entity = await _entityStore.GetByIdAsync(opts.Id);
  144. // Ensure the topic exists
  145. if (entity == null)
  146. {
  147. return NotFound();
  148. }
  149. // Ensure we have permission
  150. if (!await _authorizationService.AuthorizeAsync(User,
  151. entity.CategoryId, Permissions.AddToStopForumSpam))
  152. {
  153. return Unauthorized();
  154. }
  155. // Get reply
  156. IEntityReply reply = null;
  157. if (opts.ReplyId > 0)
  158. {
  159. reply = await _entityReplyStore.GetByIdAsync(opts.ReplyId);
  160. }
  161. // Get user for reply or entity
  162. var user = reply != null
  163. ? await GetUserToValidateAsync(reply)
  164. : await GetUserToValidateAsync(entity);
  165. // Ensure we found the user
  166. if (user == null)
  167. {
  168. return NotFound();
  169. }
  170. // Add spammer for reply or entity
  171. var result = await AddSpammerAsync(user);
  172. // Confirmation
  173. if (result.Success)
  174. {
  175. _alerter.Success(T["Spammer Added Successfully"]);
  176. }
  177. else
  178. {
  179. _alerter.Danger(!string.IsNullOrEmpty(result.Error)
  180. ? T[result.Error]
  181. : T["An unknown error occurred adding the user to the StopForumSpam database."]);
  182. }
  183. // Redirect back to reply
  184. if (reply != null)
  185. {
  186. return Redirect(_contextFacade.GetRouteUrl(new RouteValueDictionary()
  187. {
  188. ["area"] = "Plato.Questions",
  189. ["controller"] = "Home",
  190. ["action"] = "Reply",
  191. ["opts.id"] = entity.Id,
  192. ["opts.alias"] = entity.Alias,
  193. ["opts.replyId"] = reply.Id
  194. }));
  195. }
  196. // Redirect back to entity
  197. return Redirect(_contextFacade.GetRouteUrl(new RouteValueDictionary()
  198. {
  199. ["area"] = "Plato.Questions",
  200. ["controller"] = "Home",
  201. ["action"] = "Display",
  202. ["opts.id"] = entity.Id,
  203. ["opts.alias"] = entity.Alias
  204. }));
  205. }
  206. // ----------------------
  207. async Task<Response> AddSpammerAsync(IUser user)
  208. {
  209. // Configure client
  210. ConfigureSpamClient();
  211. // Add the user & return the result
  212. return await _spamClient.AddSpammerAsync(
  213. user.UserName,
  214. user.Email,
  215. user.IpV4Address);
  216. }
  217. async Task<User> GetUserToValidateAsync(IEntity entity)
  218. {
  219. // Get author
  220. var user = await _platoUserStore.GetByIdAsync(entity.CreatedUserId);
  221. // Ensure we found the user
  222. if (user == null)
  223. {
  224. return null;
  225. }
  226. // Use IP information from entity
  227. if (!string.IsNullOrEmpty(entity.IpV4Address))
  228. {
  229. if (!entity.IpV4Address.Equals(user.IpV4Address, StringComparison.OrdinalIgnoreCase))
  230. {
  231. user.IpV4Address = entity.IpV4Address;
  232. }
  233. }
  234. if (!string.IsNullOrEmpty(entity.IpV6Address))
  235. {
  236. if (!entity.IpV6Address.Equals(user.IpV6Address, StringComparison.OrdinalIgnoreCase))
  237. {
  238. user.IpV6Address = entity.IpV6Address;
  239. }
  240. }
  241. return user;
  242. }
  243. async Task<User> GetUserToValidateAsync(IEntityReply reply)
  244. {
  245. // Get author
  246. var user = await _platoUserStore.GetByIdAsync(reply.CreatedUserId);
  247. // Ensure we found the user
  248. if (user == null)
  249. {
  250. return null;
  251. }
  252. // Use IP information from reply
  253. if (!string.IsNullOrEmpty(reply.IpV4Address))
  254. {
  255. if (!reply.IpV4Address.Equals(user.IpV4Address, StringComparison.OrdinalIgnoreCase))
  256. {
  257. user.IpV4Address = reply.IpV4Address;
  258. }
  259. }
  260. if (!string.IsNullOrEmpty(reply.IpV6Address))
  261. {
  262. if (!reply.IpV6Address.Equals(user.IpV6Address, StringComparison.OrdinalIgnoreCase))
  263. {
  264. user.IpV6Address = reply.IpV6Address;
  265. }
  266. }
  267. return user;
  268. }
  269. void ConfigureSpamClient()
  270. {
  271. // Configure spam client
  272. _spamClient.Configure(async o => { o.ApiKey = await GetStopForumSpamApiKeyAsync(); });
  273. }
  274. async Task<string> GetStopForumSpamApiKeyAsync()
  275. {
  276. // Get spam settings
  277. var settings = await _spamSettingsStore.GetAsync();
  278. // Ensure we have settings
  279. if (settings == null)
  280. {
  281. throw new Exception("No spam settings have been configured!");
  282. }
  283. // Ensure we have an api key
  284. if (String.IsNullOrEmpty(settings.ApiKey))
  285. {
  286. throw new Exception("A StopForumSpam API key is required!");
  287. }
  288. return settings.ApiKey;
  289. }
  290. }
  291. }