feat(backend): global notices
This commit is contained in:
		
							parent
							
								
									22be49976a
								
							
						
					
					
						commit
						b07f4b75c0
					
				
					 19 changed files with 1247 additions and 8 deletions
				
			
		|  | @ -13,20 +13,23 @@ | |||
| // You should have received a copy of the GNU Affero General Public License | ||||
| // along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
| using System.Text.RegularExpressions; | ||||
| using Foxnouns.Backend.Database.Models; | ||||
| using Foxnouns.Backend.Dto; | ||||
| using Foxnouns.Backend.Services.Caching; | ||||
| using Foxnouns.Backend.Utils; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| 
 | ||||
| namespace Foxnouns.Backend.Controllers; | ||||
| 
 | ||||
| [Route("/api/v2/meta")] | ||||
| public partial class MetaController(Config config) : ApiControllerBase | ||||
| public partial class MetaController(Config config, NoticeCacheService noticeCache) | ||||
|     : ApiControllerBase | ||||
| { | ||||
|     private const string Repository = "https://codeberg.org/pronounscc/pronouns.cc"; | ||||
| 
 | ||||
|     [HttpGet] | ||||
|     [ProducesResponseType<MetaResponse>(StatusCodes.Status200OK)] | ||||
|     public IActionResult GetMeta() => | ||||
|     public async Task<IActionResult> GetMeta(CancellationToken ct = default) => | ||||
|         Ok( | ||||
|             new MetaResponse( | ||||
|                 Repository, | ||||
|  | @ -45,10 +48,14 @@ public partial class MetaController(Config config) : ApiControllerBase | |||
|                     ValidationUtils.MaxCustomPreferences, | ||||
|                     AuthUtils.MaxAuthMethodsPerType, | ||||
|                     FlagsController.MaxFlagCount | ||||
|                 ) | ||||
|                 ), | ||||
|                 Notice: NoticeResponse(await noticeCache.GetAsync(ct)) | ||||
|             ) | ||||
|         ); | ||||
| 
 | ||||
|     private static MetaNoticeResponse? NoticeResponse(Notice? notice) => | ||||
|         notice == null ? null : new MetaNoticeResponse(notice.Id, notice.Message); | ||||
| 
 | ||||
|     [HttpGet("page/{page}")] | ||||
|     public async Task<IActionResult> GetStaticPageAsync(string page, CancellationToken ct = default) | ||||
|     { | ||||
|  | @ -71,7 +78,7 @@ public partial class MetaController(Config config) : ApiControllerBase | |||
| 
 | ||||
|     [HttpGet("/api/v2/coffee")] | ||||
|     public IActionResult BrewCoffee() => | ||||
|         Problem("Sorry, I'm a teapot!", statusCode: StatusCodes.Status418ImATeapot); | ||||
|         StatusCode(StatusCodes.Status418ImATeapot, "Sorry, I'm a teapot!"); | ||||
| 
 | ||||
|     [GeneratedRegex(@"^[a-z\-_]+$")]
 | ||||
|     private static partial Regex PageRegex(); | ||||
|  |  | |||
							
								
								
									
										77
									
								
								Foxnouns.Backend/Controllers/Moderation/NoticesController.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								Foxnouns.Backend/Controllers/Moderation/NoticesController.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| using Foxnouns.Backend.Database; | ||||
| using Foxnouns.Backend.Database.Models; | ||||
| using Foxnouns.Backend.Dto; | ||||
| using Foxnouns.Backend.Middleware; | ||||
| using Foxnouns.Backend.Services; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using NodaTime; | ||||
| 
 | ||||
| namespace Foxnouns.Backend.Controllers.Moderation; | ||||
| 
 | ||||
| [Route("/api/v2/notices")] | ||||
| [Authorize("user.moderation")] | ||||
| [Limit(RequireModerator = true)] | ||||
| public class NoticesController( | ||||
|     DatabaseContext db, | ||||
|     UserRendererService userRenderer, | ||||
|     ISnowflakeGenerator snowflakeGenerator, | ||||
|     IClock clock | ||||
| ) : ApiControllerBase | ||||
| { | ||||
|     [HttpGet] | ||||
|     public async Task<IActionResult> GetNoticesAsync(CancellationToken ct = default) | ||||
|     { | ||||
|         List<Notice> notices = await db | ||||
|             .Notices.Include(n => n.Author) | ||||
|             .OrderByDescending(n => n.Id) | ||||
|             .ToListAsync(ct); | ||||
|         return Ok(notices.Select(RenderNotice)); | ||||
|     } | ||||
| 
 | ||||
|     [HttpPost] | ||||
|     public async Task<IActionResult> CreateNoticeAsync(CreateNoticeRequest req) | ||||
|     { | ||||
|         Instant now = clock.GetCurrentInstant(); | ||||
|         if (req.StartTime < now) | ||||
|         { | ||||
|             throw new ApiError.BadRequest( | ||||
|                 "Start time cannot be in the past", | ||||
|                 "start_time", | ||||
|                 req.StartTime | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         if (req.EndTime < now) | ||||
|         { | ||||
|             throw new ApiError.BadRequest( | ||||
|                 "End time cannot be in the past", | ||||
|                 "end_time", | ||||
|                 req.EndTime | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         var notice = new Notice | ||||
|         { | ||||
|             Id = snowflakeGenerator.GenerateSnowflake(), | ||||
|             Message = req.Message, | ||||
|             StartTime = req.StartTime ?? clock.GetCurrentInstant(), | ||||
|             EndTime = req.EndTime, | ||||
|             Author = CurrentUser!, | ||||
|         }; | ||||
| 
 | ||||
|         db.Add(notice); | ||||
|         await db.SaveChangesAsync(); | ||||
| 
 | ||||
|         return Ok(RenderNotice(notice)); | ||||
|     } | ||||
| 
 | ||||
|     private NoticeResponse RenderNotice(Notice notice) => | ||||
|         new( | ||||
|             notice.Id, | ||||
|             notice.Message, | ||||
|             notice.StartTime, | ||||
|             notice.EndTime, | ||||
|             userRenderer.RenderPartialUser(notice.Author) | ||||
|         ); | ||||
| } | ||||
|  | @ -281,6 +281,8 @@ public class UsersController( | |||
| 
 | ||||
|         if (req.HasProperty(nameof(req.DarkMode))) | ||||
|             user.Settings.DarkMode = req.DarkMode; | ||||
|         if (req.HasProperty(nameof(req.LastReadNotice))) | ||||
|             user.Settings.LastReadNotice = req.LastReadNotice; | ||||
| 
 | ||||
|         user.LastActive = clock.GetCurrentInstant(); | ||||
|         db.Update(user); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue