From 9ed428ef4743941f17912e81a7048769a84cc14b Mon Sep 17 00:00:00 2001 From: theolli999 Date: Thu, 2 May 2024 22:10:13 +0200 Subject: [PATCH 1/3] =?UTF-8?q?Initiala=20=C3=A4ndringar=20f=C3=B6r=20?= =?UTF-8?q?=C3=B6verg=C3=A5ngen=20fr=C3=A5n=20Firebase=20till=20Expo.=20Ha?= =?UTF-8?q?nteringen=20av=20topics=20sker=20nu=20i=20backend=20ist=C3=A4ll?= =?UTF-8?q?et?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Nexpo/Controllers/NotificationsController.cs | 2 +- Nexpo/Models/ApplicationDbContext.cs | 2 + Nexpo/Models/NotificationTopics.cs | 36 +++++++++ .../NotificationTopicRepository.cs | 75 +++++++++++++++++++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 Nexpo/Models/NotificationTopics.cs create mode 100644 Nexpo/Repositories/NotificationTopicRepository.cs diff --git a/Nexpo/Controllers/NotificationsController.cs b/Nexpo/Controllers/NotificationsController.cs index c2a3d00..c5708bc 100644 --- a/Nexpo/Controllers/NotificationsController.cs +++ b/Nexpo/Controllers/NotificationsController.cs @@ -1,4 +1,4 @@ -using FirebaseAdmin.Messaging; +//using FirebaseAdmin.Messaging; using Google.Apis.Auth.OAuth2; using FirebaseAdmin; using Microsoft.AspNetCore.Mvc; diff --git a/Nexpo/Models/ApplicationDbContext.cs b/Nexpo/Models/ApplicationDbContext.cs index 26f18fe..8a17c26 100644 --- a/Nexpo/Models/ApplicationDbContext.cs +++ b/Nexpo/Models/ApplicationDbContext.cs @@ -19,6 +19,8 @@ public class ApplicationDbContext : DbContext public DbSet Contacts { get; set; } public DbSet FrequentAskedQuestion { get; set; } + public DbSet NotificationTopic { get; set; } + #pragma warning restore format private readonly PasswordService _passwordService; diff --git a/Nexpo/Models/NotificationTopics.cs b/Nexpo/Models/NotificationTopics.cs new file mode 100644 index 0000000..e7d81b6 --- /dev/null +++ b/Nexpo/Models/NotificationTopics.cs @@ -0,0 +1,36 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; + +namespace Nexpo.Models +{ + /// + /// Represents a notification topic + /// + public class NotificationTopic + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int? Id { get; set; } + + [Required] + public TopicType Topic { get; set; } + + [Required] + [JsonIgnore] + public User User { get; set; } + + + + public enum TopicType + { + All, + Administratior, + CompanyRepresentative, + Student, + + Volunteer, + } + + } +} + diff --git a/Nexpo/Repositories/NotificationTopicRepository.cs b/Nexpo/Repositories/NotificationTopicRepository.cs new file mode 100644 index 0000000..2e83979 --- /dev/null +++ b/Nexpo/Repositories/NotificationTopicRepository.cs @@ -0,0 +1,75 @@ +using Nexpo.Models; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using static Nexpo.Models.NotificationTopic; //Denna borde ha importerats från Nexpo.Models? + +namespace Nexpo.Repositories +{ + public interface INotificationTopicRepository + { + //public Task> GetAll(); + public Task> GetUserTopics(User _user); + public Task> GetTopicSubscribers(NotificationTopic _topic); + public Task Add(TopicType _topic, User user); + public Task Delete(NotificationTopic _notificationTopic); + } + + public class NotificationTopicRepository : INotificationTopicRepository + { + private readonly ApplicationDbContext _context; + + public NotificationTopicRepository(ApplicationDbContext context) + { + _context = context; + } + /* + public async Task> GetAll() + { + return await _context.Events.OrderBy(_event => _event.Date) + .ThenBy(_event => _event.Start) + .Select(_event => new Event + { + Id = _event.Id, + Name = _event.Name, + Description = _event.Description, + Date = _event.Date, + Type = _event.Type, + Start = _event.Start, + End = _event.End, + Location = _event.Location, + Host = _event.Host, + Language = _event.Language, + Capacity = _event.Capacity, + TicketCount = _event.Tickets.Count() + }) + .ToListAsync(); + } +*/ + + + public async Task> GetUserTopics(User user) + { + return await _context.NotificationTopic.Where(_topic => _topic.User == user).ToListAsync(); + } + public async Task> GetTopicSubscribers(NotificationTopic topic) + { + return await _context.NotificationTopic.Where(_topic => _topic.Topic == topic.Topic).Select(_topic => _topic.User).ToListAsync(); + } + + + public async Task Add(TopicType topic, User user) + { + _context.NotificationTopic.Add(new NotificationTopic { Topic = topic, User = user }); + await _context.SaveChangesAsync(); + } + + + public async Task Delete(NotificationTopic NotificationTopic) + { + _context.NotificationTopic.Remove(NotificationTopic); + await _context.SaveChangesAsync(); + } + } +} From 1a71d74c9f16fa03b792930907c0d087d6496098 Mon Sep 17 00:00:00 2001 From: theolli999 Date: Tue, 14 May 2024 20:35:36 +0200 Subject: [PATCH 2/3] =?UTF-8?q?Tagit=20bort=20Topics=20och=20ersatt=20det?= =?UTF-8?q?=20med=20modellen=20som=20Leo=20f=C3=B6reslog=20med=20en=20join?= =?UTF-8?q?tabell.=20Ocks=C3=A5=20=C3=A4ndrat=20s=C3=A5=20att=20token=20la?= =?UTF-8?q?gras=20i=20databasen=20med=20anv=C3=A4ndaren.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pizzaburgare --- Nexpo/Controllers/NotificationsController.cs | 22 ++++-- Nexpo/DTO/Notifications/RegisterUserDTO.cs | 2 +- Nexpo/Models/ApplicationDbContext.cs | 4 +- Nexpo/Models/Notification.cs | 37 +++++++++ Nexpo/Models/User.cs | 2 + ...ificationTopics.cs => UserNotification.cs} | 25 ++----- Nexpo/Repositories/NotificationRepository.cs | 64 ++++++++++++++++ .../NotificationTopicRepository.cs | 75 ------------------- .../UserNotificationRepository.cs | 52 +++++++++++++ Nexpo/Repositories/UserRepository.cs | 7 ++ 10 files changed, 188 insertions(+), 102 deletions(-) create mode 100644 Nexpo/Models/Notification.cs rename Nexpo/Models/{NotificationTopics.cs => UserNotification.cs} (58%) create mode 100644 Nexpo/Repositories/NotificationRepository.cs delete mode 100644 Nexpo/Repositories/NotificationTopicRepository.cs create mode 100644 Nexpo/Repositories/UserNotificationRepository.cs diff --git a/Nexpo/Controllers/NotificationsController.cs b/Nexpo/Controllers/NotificationsController.cs index c5708bc..8e110e2 100644 --- a/Nexpo/Controllers/NotificationsController.cs +++ b/Nexpo/Controllers/NotificationsController.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Http; using Nexpo.DTO; using Nexpo.Models; +using Nexpo.Repositories; namespace Nexpo.Controllers { @@ -16,7 +17,18 @@ namespace Nexpo.Controllers [ApiController] public class NotificationController : ControllerBase { + private readonly INotificationRepository _notificationRepo; + private readonly IUserRepository _userRepo; + public NotificationController( + INotificationRepository iNotificationRepo, + IUserRepository iUserRepo + ) + { + _notificationRepo = iNotificationRepo; + _userRepo = iUserRepo; + } + private static Queue history; static NotificationController() @@ -42,13 +54,11 @@ public async Task RegisterUser(RegisterUserDTO dto) try { - var messaging = FirebaseMessaging.DefaultInstance; - - var registrationTokens = new List { dto.Token }; - - TopicManagementResponse response = await messaging.SubscribeToTopicAsync(registrationTokens, dto.Topic); - + + await _userRepo.AddToken(dto.Token, await _userRepo.Get(dto.UserId)); + return Ok(new { success = true, detail = "Successfully registered for topic" }); + } catch (Exception) { diff --git a/Nexpo/DTO/Notifications/RegisterUserDTO.cs b/Nexpo/DTO/Notifications/RegisterUserDTO.cs index 953da1d..59d2ed4 100644 --- a/Nexpo/DTO/Notifications/RegisterUserDTO.cs +++ b/Nexpo/DTO/Notifications/RegisterUserDTO.cs @@ -7,5 +7,5 @@ public class RegisterUserDTO public string Token { get; set; } [Required] - public string Topic { get; set; } + public int UserId { get; set; } } diff --git a/Nexpo/Models/ApplicationDbContext.cs b/Nexpo/Models/ApplicationDbContext.cs index 8a17c26..5d39149 100644 --- a/Nexpo/Models/ApplicationDbContext.cs +++ b/Nexpo/Models/ApplicationDbContext.cs @@ -19,8 +19,8 @@ public class ApplicationDbContext : DbContext public DbSet Contacts { get; set; } public DbSet FrequentAskedQuestion { get; set; } - public DbSet NotificationTopic { get; set; } - + public DbSet Notification { get; set; } + public DbSet UserNotification { get; set; } #pragma warning restore format private readonly PasswordService _passwordService; diff --git a/Nexpo/Models/Notification.cs b/Nexpo/Models/Notification.cs new file mode 100644 index 0000000..2130d3f --- /dev/null +++ b/Nexpo/Models/Notification.cs @@ -0,0 +1,37 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; + +namespace Nexpo.Models +{ + /// + /// Represents a notification topic + /// + public class Notification + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int? Id { get; set; } + + [Required] + public string Message { get; set; } + [Required] + public DateTime ScheduledTime { get; set; } + [Required] + public NotificationType Type { get; set; } + [Required] + public int? EventId { get; set; } + + + + + public enum NotificationType + { + General, + EventReminder, + InternalMessage, + } + + } +} + diff --git a/Nexpo/Models/User.cs b/Nexpo/Models/User.cs index e140f2d..0cffa78 100644 --- a/Nexpo/Models/User.cs +++ b/Nexpo/Models/User.cs @@ -35,6 +35,8 @@ public class User public bool hasCv { get; set; } public string profilePictureUrl { get; set; } + + public string notificationToken { get; set; } } public enum Role diff --git a/Nexpo/Models/NotificationTopics.cs b/Nexpo/Models/UserNotification.cs similarity index 58% rename from Nexpo/Models/NotificationTopics.cs rename to Nexpo/Models/UserNotification.cs index e7d81b6..0fd18b9 100644 --- a/Nexpo/Models/NotificationTopics.cs +++ b/Nexpo/Models/UserNotification.cs @@ -7,29 +7,18 @@ namespace Nexpo.Models /// /// Represents a notification topic /// - public class NotificationTopic + public class UserNotification { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int? Id { get; set; } - - [Required] - public TopicType Topic { get; set; } - + public int UserId { get; set; } [Required] [JsonIgnore] public User User { get; set; } - - - - public enum TopicType - { - All, - Administratior, - CompanyRepresentative, - Student, - - Volunteer, - } + [Required] + public int NotificationId { get; set; } + [Required] + [JsonIgnore] + public Notification Notification { get; set; } } } diff --git a/Nexpo/Repositories/NotificationRepository.cs b/Nexpo/Repositories/NotificationRepository.cs new file mode 100644 index 0000000..554f45f --- /dev/null +++ b/Nexpo/Repositories/NotificationRepository.cs @@ -0,0 +1,64 @@ +using Nexpo.Models; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System; + +namespace Nexpo.Repositories +{ + public interface INotificationRepository + { + public Task Get(int id); + public Task Add(Notification _notification); + public Task Update(Notification _notification); + public Task Remove(Notification _notification); + public Task> GetAllNotExpired(DateTime date, Notification.NotificationType type); + } + + public class NotificationRepository : INotificationRepository + { + private readonly ApplicationDbContext _context; + + public NotificationRepository(ApplicationDbContext context) + { + _context = context; + } + + public Task Get(int id) + { + return _context.Notification.FirstOrDefaultAsync(_notification => _notification.Id == id); + } + public async Task Add(Notification _notification) + { + _context.Notification.Add(_notification); + await _context.SaveChangesAsync(); + } + public async Task Remove(Notification _notification) + { + _context.Notification.Remove(_notification); + await _context.SaveChangesAsync(); + } + public Task Update(Notification _notification){ + _context.Entry(_notification).State = EntityState.Modified; + return _context.SaveChangesAsync(); + + } + public async Task> GetAllNotExpired(DateTime date, Notification.NotificationType type) + { + return await _context.Notification.Where(_notification => _notification.ScheduledTime > date && _notification.Type == type).ToListAsync(); + } + + + + + + + + + + + + + } +} diff --git a/Nexpo/Repositories/NotificationTopicRepository.cs b/Nexpo/Repositories/NotificationTopicRepository.cs deleted file mode 100644 index 2e83979..0000000 --- a/Nexpo/Repositories/NotificationTopicRepository.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Nexpo.Models; -using Microsoft.EntityFrameworkCore; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using static Nexpo.Models.NotificationTopic; //Denna borde ha importerats från Nexpo.Models? - -namespace Nexpo.Repositories -{ - public interface INotificationTopicRepository - { - //public Task> GetAll(); - public Task> GetUserTopics(User _user); - public Task> GetTopicSubscribers(NotificationTopic _topic); - public Task Add(TopicType _topic, User user); - public Task Delete(NotificationTopic _notificationTopic); - } - - public class NotificationTopicRepository : INotificationTopicRepository - { - private readonly ApplicationDbContext _context; - - public NotificationTopicRepository(ApplicationDbContext context) - { - _context = context; - } - /* - public async Task> GetAll() - { - return await _context.Events.OrderBy(_event => _event.Date) - .ThenBy(_event => _event.Start) - .Select(_event => new Event - { - Id = _event.Id, - Name = _event.Name, - Description = _event.Description, - Date = _event.Date, - Type = _event.Type, - Start = _event.Start, - End = _event.End, - Location = _event.Location, - Host = _event.Host, - Language = _event.Language, - Capacity = _event.Capacity, - TicketCount = _event.Tickets.Count() - }) - .ToListAsync(); - } -*/ - - - public async Task> GetUserTopics(User user) - { - return await _context.NotificationTopic.Where(_topic => _topic.User == user).ToListAsync(); - } - public async Task> GetTopicSubscribers(NotificationTopic topic) - { - return await _context.NotificationTopic.Where(_topic => _topic.Topic == topic.Topic).Select(_topic => _topic.User).ToListAsync(); - } - - - public async Task Add(TopicType topic, User user) - { - _context.NotificationTopic.Add(new NotificationTopic { Topic = topic, User = user }); - await _context.SaveChangesAsync(); - } - - - public async Task Delete(NotificationTopic NotificationTopic) - { - _context.NotificationTopic.Remove(NotificationTopic); - await _context.SaveChangesAsync(); - } - } -} diff --git a/Nexpo/Repositories/UserNotificationRepository.cs b/Nexpo/Repositories/UserNotificationRepository.cs new file mode 100644 index 0000000..b6b81d6 --- /dev/null +++ b/Nexpo/Repositories/UserNotificationRepository.cs @@ -0,0 +1,52 @@ +using Nexpo.Models; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System; + +namespace Nexpo.Repositories +{ + public interface IUserNotificationRepository + { + public Task Get(int userId, int notificationId); + public Task Add(UserNotification _userNotification); + public Task Update(UserNotification _userNotification); + public Task Remove(UserNotification _userNotification); + + } + + public class UserNotificationRepository : IUserNotificationRepository + { + private readonly ApplicationDbContext _context; + + public UserNotificationRepository(ApplicationDbContext context) + { + _context = context; + } + + public Task Get(int userId, int notificationId) + { + return _context.UserNotification.FirstOrDefaultAsync(_userNotification => _userNotification.UserId == userId + && _userNotification.NotificationId == notificationId); + } + public async Task Add(UserNotification _userNotification) + { + _context.UserNotification.Add(_userNotification); + await _context.SaveChangesAsync(); + } + public async Task Remove(UserNotification _userNotification) + { + _context.UserNotification.Remove(_userNotification); + await _context.SaveChangesAsync(); + } + + public Task Update(UserNotification _userNotification){ + _context.Entry(_userNotification).State = EntityState.Modified; + return _context.SaveChangesAsync(); + + } + + + } +} diff --git a/Nexpo/Repositories/UserRepository.cs b/Nexpo/Repositories/UserRepository.cs index 99f31f5..415d0f3 100644 --- a/Nexpo/Repositories/UserRepository.cs +++ b/Nexpo/Repositories/UserRepository.cs @@ -15,6 +15,7 @@ public interface IUserRepository public Task Add(User user); public Task Remove(User user); public Task Update(User user); + public Task AddToken(string Token, User user); } public class UserRepository : IUserRepository @@ -66,5 +67,11 @@ public async Task Update(User user) _context.Entry(user).State = EntityState.Modified; await _context.SaveChangesAsync(); } + + public async Task AddToken(string Token, User user) + { + user.notificationToken = Token; + await Update(user); + } } } From a16df4b98a07b52bf2bf9dfcac92f51c54e68c63 Mon Sep 17 00:00:00 2001 From: theolli999 Date: Thu, 12 Sep 2024 19:39:01 +0200 Subject: [PATCH 3/3] Updated notify function --- Nexpo/Controllers/NotificationsController.cs | 76 +++++++++++--------- Nexpo/DTO/Notifications/NotificationDTO.cs | 6 +- Nexpo/appsettings.json | 2 +- 3 files changed, 47 insertions(+), 37 deletions(-) diff --git a/Nexpo/Controllers/NotificationsController.cs b/Nexpo/Controllers/NotificationsController.cs index 8e110e2..f49e147 100644 --- a/Nexpo/Controllers/NotificationsController.cs +++ b/Nexpo/Controllers/NotificationsController.cs @@ -10,7 +10,9 @@ using Nexpo.DTO; using Nexpo.Models; using Nexpo.Repositories; - +using System.Net.Http; +using System.Text; +using System.Text.Json; namespace Nexpo.Controllers { [Route("api/[controller]")] @@ -34,7 +36,7 @@ IUserRepository iUserRepo static NotificationController() { history = new Queue(10); - history.Enqueue(new NotificationDTO { Title = "Welcome", Message = "Welcome to the app", Topic = "all" }); + history.Enqueue(new NotificationDTO { Title = "Welcome", Message = "Welcome to the app"}); } /// @@ -45,7 +47,7 @@ static NotificationController() [HttpPost("register")] [Authorize] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task RegisterUser(RegisterUserDTO dto) + public async Task RegisterUser(int id, RegisterUserDTO dto) { if (string.IsNullOrEmpty(dto.Token)) { @@ -55,7 +57,7 @@ public async Task RegisterUser(RegisterUserDTO dto) try { - await _userRepo.AddToken(dto.Token, await _userRepo.Get(dto.UserId)); + await _userRepo.AddToken(dto.Token, await _userRepo.Get(id)); return Ok(new { success = true, detail = "Successfully registered for topic" }); @@ -75,43 +77,49 @@ public async Task RegisterUser(RegisterUserDTO dto) [HttpPut] [Authorize(Roles = nameof(Role.Administrator))] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task NotifyAll(NotificationDTO dto) - { - if (string.IsNullOrEmpty(dto.Topic)) - { - return BadRequest("Topic is required input."); - } +public async Task Notify(NotificationDTO dto, Role role) +{ - if (string.IsNullOrEmpty(dto.Message)) - { - return BadRequest("Message is required input."); - } + if (string.IsNullOrEmpty(dto.Message)) + { + return BadRequest("Message is required input."); + } - try - { - var messaging = FirebaseMessaging.DefaultInstance; - var message = new Message - { - Notification = new Notification { Title = dto.Title, Body = dto.Message }, - Topic = dto.Topic - }; + try + { + var client = new HttpClient(); + var payload = new + { + to = dto.Token, + title = dto.Title, + body = dto.Message, + }; - var result = await messaging.SendAsync(message); + var jsonPayload = JsonSerializer.Serialize(payload); + var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); - if (history.Count >= 10) - { - history.Dequeue(); - } - history.Enqueue(dto); + var response = await client.PostAsync("https://exp.host/--/api/v2/push/send", content); - return Ok(new { success = true, detail = "Successfully sent notification" }); - } - catch (Exception) - { - return StatusCode(StatusCodes.Status500InternalServerError, new { success = false, detail = "An error occurred while sending notification" }); - } + if (!response.IsSuccessStatusCode) + { + return StatusCode(StatusCodes.Status500InternalServerError, new { success = false, detail = "An error occurred while sending notification" }); } + if (history.Count >= 10) + { + history.Dequeue(); + } + history.Enqueue(dto); + + return Ok(new { success = true, detail = "Successfully sent notification" }); + + } + catch (Exception) + { + return StatusCode(StatusCodes.Status500InternalServerError, new { success = false, detail = "An error occurred while sending notification" }); + } +} + /// /// Returns the past few notifications /// At most 10 notifications will be stored at once diff --git a/Nexpo/DTO/Notifications/NotificationDTO.cs b/Nexpo/DTO/Notifications/NotificationDTO.cs index 500f681..aca9608 100644 --- a/Nexpo/DTO/Notifications/NotificationDTO.cs +++ b/Nexpo/DTO/Notifications/NotificationDTO.cs @@ -1,3 +1,4 @@ +using System; using System.ComponentModel.DataAnnotations; namespace Nexpo.DTO @@ -8,10 +9,11 @@ public class NotificationDTO public string Title { get; set; } [Required] - public string Message { get; set; } + public string Token { get; set; } [Required] - public string Topic { get; set; } + public string Message { get; set; } + } diff --git a/Nexpo/appsettings.json b/Nexpo/appsettings.json index 3aca971..d27c7c7 100644 --- a/Nexpo/appsettings.json +++ b/Nexpo/appsettings.json @@ -1,4 +1,4 @@ -{ +{ "Logging": { "LogLevel": { "Default": "Information",