Skip to content

Commit 5e86be7

Browse files
committed
Merge branch 'push-notifications-one-signal'
2 parents 8da18b6 + 6b6ee73 commit 5e86be7

8 files changed

Lines changed: 316 additions & 15 deletions

File tree

RequestTests.paw

2.21 KB
Binary file not shown.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
11
using System;
2+
using SimpleToDoService.Entities;
3+
24
namespace SimpleToDoService
35
{
46
public class ServiceError
57
{
68
public string Message { get; set; }
79
}
810
}
11+
12+
static class Extensions
13+
{
14+
public static DateTime? CheckedTargetDate(this Task task)
15+
{
16+
if (!task.TargetDate.HasValue)
17+
return null;
18+
19+
var notificationDate = task.TargetDate.Value.ToUniversalTime();
20+
21+
if (!task.TargetDateIncludeTime)
22+
return new DateTime(notificationDate.Year, notificationDate.Month, notificationDate.Day, 0, 0, 0, notificationDate.Kind);
23+
24+
return task.TargetDate;
25+
}
26+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
using System;
2+
using SimpleToDoService.Entities;
3+
using SimpleToDoService.Repository;
4+
using System.Linq;
5+
using System.Text;
6+
using Newtonsoft.Json.Linq;
7+
using System.Net;
8+
using System.IO;
9+
10+
namespace SimpleToDoService.Common
11+
{
12+
public class PushNotificationScheduler
13+
{
14+
private readonly IToDoRepository repository;
15+
16+
public PushNotificationScheduler(IToDoRepository repository)
17+
{
18+
this.repository = repository;
19+
}
20+
21+
bool HasEqualDueDatest(Task task, PushNotification notification)
22+
{
23+
var taskDate = task.CheckedTargetDate();
24+
var notificationDate = notification?.DueDate;
25+
26+
if (taskDate.HasValue && notificationDate.HasValue)
27+
{
28+
return taskDate.Value.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fffzz") ==
29+
notificationDate.Value.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fffzz");
30+
}
31+
else
32+
return false;
33+
}
34+
35+
public async System.Threading.Tasks.Task SchedulePushNotifications(Task task)
36+
{
37+
var currentNotification = task.PushNotifications.FirstOrDefault();
38+
39+
if (!task.Completed && HasEqualDueDatest(task, currentNotification))
40+
return;
41+
42+
await DeletePushNotification(currentNotification);
43+
44+
if (!task.Completed)
45+
await CreatePushNotification(task);
46+
}
47+
48+
async System.Threading.Tasks.Task DeletePushNotification(PushNotification notification)
49+
{
50+
if (notification == null)
51+
return;
52+
53+
var url = String.Format("https://onesignal.com/api/v1/notifications/{0}?app_id={1}",
54+
notification.ServiceId.ToString(), Environment.GetEnvironmentVariable("ONE_SIGNAL_APP_ID"));
55+
var request = WebRequest.Create(url) as HttpWebRequest;
56+
57+
request.ContentType = "application/json; charset=utf-8";
58+
request.Method = "DELETE";
59+
request.Headers["authorization"] = String.Format("Basic {0}", Environment.GetEnvironmentVariable("ONE_SIGNAL_KEY"));
60+
61+
try
62+
{
63+
using (var writer = await request.GetRequestStreamAsync())
64+
{
65+
writer.Write(new Byte[0], 0, 0);
66+
}
67+
await request.GetResponseAsync();
68+
}
69+
#if DEBUG
70+
catch (WebException ex)
71+
{
72+
System.Diagnostics.Debug.WriteLine(ex.Message);
73+
System.Diagnostics.Debug.WriteLine(new StreamReader(ex.Response.GetResponseStream()).ReadToEnd());
74+
}
75+
#else
76+
catch { }
77+
#endif
78+
79+
repository.DeletePushNotification(notification);
80+
}
81+
82+
async System.Threading.Tasks.Task CreatePushNotification(Task task)
83+
{
84+
var notificationDate = task.CheckedTargetDate();
85+
if (!notificationDate.HasValue)
86+
return;
87+
88+
var request = WebRequest.Create("https://onesignal.com/api/v1/notifications") as HttpWebRequest;
89+
90+
request.Method = "POST";
91+
request.ContentType = "application/json; charset=utf-8";
92+
93+
request.Headers["authorization"] = String.Format("Basic {0}", Environment.GetEnvironmentVariable("ONE_SIGNAL_KEY"));
94+
95+
var sendJson = JObject.FromObject(new
96+
{
97+
app_id = Environment.GetEnvironmentVariable("ONE_SIGNAL_APP_ID"),
98+
contents = new { en = task.Description },
99+
filters = new[] { new { field = "tag", key = "user_id", relation = "=", value = repository.User(task.UserUuid).FirebaseId } },
100+
send_after = notificationDate.Value.ToString("yyyy-MM-dd HH:mm:ss 'GMT'zzzz")
101+
});
102+
103+
var byteArray = Encoding.UTF8.GetBytes(sendJson.ToString());
104+
105+
try
106+
{
107+
using (var writer = await request.GetRequestStreamAsync())
108+
{
109+
writer.Write(byteArray, 0, byteArray.Length);
110+
}
111+
112+
using (var response = await request.GetResponseAsync())
113+
using (var reader = new StreamReader(response.GetResponseStream()))
114+
{
115+
var json = JObject.Parse(reader.ReadToEnd());
116+
var notificationId = json["id"].ToString();
117+
if (notificationId != null && notificationId.Length > 0)
118+
{
119+
var notification = new PushNotification()
120+
{
121+
ServiceId = new Guid(notificationId),
122+
TaskUuid = task.Uuid,
123+
UserUuid = task.UserUuid,
124+
DueDate = notificationDate.Value
125+
};
126+
127+
repository.CreatePushNotification(notification);
128+
}
129+
}
130+
}
131+
#if DEBUG
132+
catch (WebException ex)
133+
{
134+
System.Diagnostics.Debug.WriteLine(ex.Message);
135+
System.Diagnostics.Debug.WriteLine(new StreamReader(ex.Response.GetResponseStream()).ReadToEnd());
136+
}
137+
#else
138+
catch { }
139+
#endif
140+
}
141+
}
142+
}
Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
1-
using Microsoft.AspNetCore.Mvc;
1+
using System;
2+
using System.IO;
3+
using System.Net;
4+
using System.Net.Security;
5+
using System.Net.Sockets;
6+
using System.Security.Authentication;
7+
using System.Security.Cryptography.X509Certificates;
8+
using System.Threading.Tasks;
9+
using Microsoft.AspNetCore.Hosting;
10+
using Microsoft.AspNetCore.Mvc;
11+
using System.Text;
12+
using Newtonsoft.Json.Linq;
213

314
namespace SimpleToDoService
415
{
516
[Route("/")]
617
public class RootController : Controller
7-
{
18+
{
19+
private readonly IHostingEnvironment _hostingEnvironment;
20+
21+
public RootController(IHostingEnvironment hostingEnvironment)
22+
{
23+
_hostingEnvironment = hostingEnvironment;
24+
}
25+
826
[HttpGet]
927
public IActionResult Get()
1028
{
1129
return Ok();
12-
}
30+
}
1331
}
1432
}

src/SimpleToDoService/Controllers/TasksController.cs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Security.Claims;
55
using Microsoft.AspNetCore.Authorization;
66
using Microsoft.AspNetCore.Mvc;
7+
using SimpleToDoService.Common;
78
using SimpleToDoService.Entities;
89
using SimpleToDoService.Middleware;
910
using SimpleToDoService.Repository;
@@ -39,7 +40,7 @@ public IEnumerable<Task> Get(Guid? uuid)
3940

4041
if (uuid != null)
4142
entries = entries.Where(o => o.Uuid == uuid);
42-
43+
4344
return entries;
4445
}
4546

@@ -58,7 +59,7 @@ public IEnumerable<Task> GetAll([FromQuery] bool? completed,[FromQuery] int offs
5859
}
5960

6061
[HttpPost]
61-
public IActionResult Post([FromBody] Task entry)
62+
public async System.Threading.Tasks.Task<IActionResult> Post([FromBody] Task entry)
6263
{
6364
if (!ModelState.IsValid)
6465
return BadRequest(ModelState);
@@ -69,11 +70,14 @@ public IActionResult Post([FromBody] Task entry)
6970
entry.UserUuid = CurrentUserUuid;
7071

7172
var created = repository.CreateTask(entry);
73+
74+
await new PushNotificationScheduler(repository).SchedulePushNotifications(created);
75+
7276
return CreatedAtRoute("GetTask", new { Uuid = created.Uuid }, created);
7377
}
7478

7579
[HttpPut("{uuid:Guid?}")]
76-
public IActionResult Put(Guid? uuid, [FromBody] Task entry)
80+
public async System.Threading.Tasks.Task<IActionResult> Put(Guid? uuid, [FromBody] Task entry)
7781
{
7882
if (!uuid.HasValue)
7983
return BadRequest(new ServiceError() { Message = "Object Uuid not specified" });
@@ -89,25 +93,32 @@ public IActionResult Put(Guid? uuid, [FromBody] Task entry)
8993
if (updated == null)
9094
return NotFound(entry);
9195

96+
var reloaded = repository.Task(CurrentUserUuid, entry.Uuid);
97+
98+
await new PushNotificationScheduler(repository).SchedulePushNotifications(reloaded);
99+
92100
return Ok(updated);
93101
}
94102

95103
[HttpDelete("{uuid:Guid?}")]
96-
public IActionResult Delete(Guid? uuid)
104+
public async System.Threading.Tasks.Task<IActionResult> Delete(Guid? uuid)
97105
{
98106
if (!uuid.HasValue)
99107
return BadRequest(new ServiceError() { Message = "Object Uuid not specified" });
100108

101-
var deleted = repository.DeleteTask(uuid.Value);
109+
var toDelete = repository.Task(CurrentUserUuid, uuid.Value);
110+
if(toDelete == null)
111+
return new NotFoundResult();
102112

103-
if (deleted)
104-
return new StatusCodeResult(204);
113+
toDelete.TargetDate = null;
114+
await new PushNotificationScheduler(repository).SchedulePushNotifications(toDelete);
105115

106-
return new NotFoundResult();
116+
repository.DeleteTask(toDelete);
117+
return new StatusCodeResult(204);
107118
}
108119

109120
[HttpPost("{uuid:Guid}/ChangeCompletionStatus/")]
110-
public IActionResult ChangeCompletionStatus(Guid uuid, [FromQuery] bool completed)
121+
public async System.Threading.Tasks.Task<IActionResult> ChangeCompletionStatus(Guid uuid, [FromQuery] bool completed)
111122
{
112123
var entry = repository.Task(CurrentUserUuid, uuid);
113124

@@ -117,6 +128,8 @@ public IActionResult ChangeCompletionStatus(Guid uuid, [FromQuery] bool complete
117128
entry.Completed = completed;
118129
repository.UpdateTask(entry);
119130

131+
await new PushNotificationScheduler(repository).SchedulePushNotifications(entry);
132+
120133
return Ok(entry);
121134
}
122135
}

src/SimpleToDoService/Database/DbContext.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public interface IToDoDbContext
99
{
1010
DbSet<User> Users { get; }
1111
DbSet<Task> Tasks { get; }
12+
DbSet<PushNotification> PushNotifications { get; }
1213

1314
int SaveChanges();
1415

@@ -25,6 +26,8 @@ public ToDoDbContext(DbContextOptions<ToDoDbContext> options) : base(options) {
2526

2627
public DbSet<Task> Tasks { get; set; }
2728

29+
public DbSet<PushNotification> PushNotifications { get; set; }
30+
2831
public Task UpdateTask(Task task)
2932
{
3033
if(Tasks.Where(o => o.Uuid == task.Uuid).Count() == 1)

src/SimpleToDoService/Database/Entities.cs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.ComponentModel.DataAnnotations;
34
using System.ComponentModel.DataAnnotations.Schema;
45
using System.Runtime.Serialization;
@@ -41,6 +42,11 @@ public class User
4142
[IgnoreDataMember]
4243
[Column("creationdate")]
4344
public DateTime CreationDate { get; set; }
45+
46+
[XmlIgnore]
47+
[JsonIgnore]
48+
[IgnoreDataMember]
49+
public IEnumerable<Task> Tasks { get; set; }
4450
}
4551

4652
[Table("task")]
@@ -79,12 +85,56 @@ public class Task
7985
[JsonIgnore]
8086
[IgnoreDataMember]
8187
[Column("owner")]
82-
[ForeignKey("User")]
8388
public Guid UserUuid { get; set; }
8489

8590
[XmlIgnore]
8691
[JsonIgnore]
8792
[IgnoreDataMember]
93+
[ForeignKey("UserUuid")]
8894
public User User { get; set; }
95+
96+
[XmlIgnore]
97+
[JsonIgnore]
98+
[IgnoreDataMember]
99+
public IEnumerable<PushNotification> PushNotifications { get; set; }
100+
}
101+
102+
[Table("pushnotification")]
103+
public class PushNotification
104+
{
105+
[Key]
106+
[Column("uuid")]
107+
public Guid Uuid { get; set; }
108+
109+
[Column("serviceid")]
110+
public Guid ServiceId { get; set; }
111+
112+
[XmlIgnore]
113+
[JsonIgnore]
114+
[IgnoreDataMember]
115+
[Column("userid")]
116+
public Guid UserUuid { get; set; }
117+
118+
[XmlIgnore]
119+
[JsonIgnore]
120+
[IgnoreDataMember]
121+
[ForeignKey("UserUuid")]
122+
public User User { get; set; }
123+
124+
[XmlIgnore]
125+
[JsonIgnore]
126+
[IgnoreDataMember]
127+
[Column("taskid")]
128+
public Guid TaskUuid { get; set; }
129+
130+
[XmlIgnore]
131+
[JsonIgnore]
132+
[IgnoreDataMember]
133+
[ForeignKey("TaskUuid")]
134+
public User Task { get; set; }
135+
136+
[Column("duedate")]
137+
public DateTime DueDate { get; set; }
89138
}
90139
}
140+

0 commit comments

Comments
 (0)