diff --git a/.gitignore b/.gitignore index 05c865c6c5..522f674c9f 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,4 @@ portal/js/templates.js /stack/core/src/main/java/org/apache/usergrid/persistence/query/tree/QueryFilterParser.java !/stack/corepersistence/common/src/test/resources/usergrid-UNIT.properties *.iml +sdks/dotnet/samples/notifications/packages/* diff --git a/portal/js/push/push-config.html b/portal/js/push/push-config.html index 8dbdf38811..8cacab0d05 100644 --- a/portal/js/push/push-config.html +++ b/portal/js/push/push-config.html @@ -165,7 +165,7 @@
A Notifier allows App Services to connect to and deliver a message to a communication provider such as Windows Notifications Service (WNS). Copy and paste your API key to create a bridge between your app - and GCM for push notifications on Android devices.. + and WNS for push notifications on windows devices..

For more help: see our getting started page page. @@ -189,10 +189,12 @@
- API Key + Secret
+
+ Secret will not be returned in other api calls for security reasons.
diff --git a/sdks/dotnet/samples/notifications/Usergrid.Notifications.sln b/sdks/dotnet/samples/notifications/Usergrid.Notifications.sln new file mode 100644 index 0000000000..5474b5b7f1 --- /dev/null +++ b/sdks/dotnet/samples/notifications/Usergrid.Notifications.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Usergrid.Notifications", "Usergrid.Notifications\Usergrid.Notifications.csproj", "{EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Debug|ARM.ActiveCfg = Debug|ARM + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Debug|ARM.Build.0 = Debug|ARM + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Debug|ARM.Deploy.0 = Debug|ARM + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Debug|x86.ActiveCfg = Debug|x86 + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Debug|x86.Build.0 = Debug|x86 + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Debug|x86.Deploy.0 = Debug|x86 + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Release|Any CPU.Build.0 = Release|Any CPU + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Release|Any CPU.Deploy.0 = Release|Any CPU + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Release|ARM.ActiveCfg = Release|ARM + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Release|ARM.Build.0 = Release|ARM + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Release|ARM.Deploy.0 = Release|ARM + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Release|x86.ActiveCfg = Release|x86 + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Release|x86.Build.0 = Release|x86 + {EB364B8E-B7C1-45C2-BF13-1CBF731EA8B6}.Release|x86.Deploy.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/sdks/dotnet/samples/notifications/Usergrid.Notifications/App.xaml b/sdks/dotnet/samples/notifications/Usergrid.Notifications/App.xaml index 8a363591d4..486a2fdf55 100644 --- a/sdks/dotnet/samples/notifications/Usergrid.Notifications/App.xaml +++ b/sdks/dotnet/samples/notifications/Usergrid.Notifications/App.xaml @@ -3,5 +3,25 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Usergrid.Notifications"> - + \ No newline at end of file diff --git a/sdks/dotnet/samples/notifications/Usergrid.Notifications/App.xaml.cs b/sdks/dotnet/samples/notifications/Usergrid.Notifications/App.xaml.cs index 9bf62ac99b..eb079fbba1 100644 --- a/sdks/dotnet/samples/notifications/Usergrid.Notifications/App.xaml.cs +++ b/sdks/dotnet/samples/notifications/Usergrid.Notifications/App.xaml.cs @@ -1,4 +1,23 @@ -using System; +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. The ASF licenses this file to You + * * under the Apache License, Version 2.0 (the "License"); you may not + * * use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. For additional information regarding + * * copyright in this work, please see the NOTICE file in the top level + * * directory of this distribution. + * + */ +using System; using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/EntityResponse.cs b/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/EntityResponse.cs new file mode 100644 index 0000000000..0be267a061 --- /dev/null +++ b/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/EntityResponse.cs @@ -0,0 +1,80 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. The ASF licenses this file to You + * * under the Apache License, Version 2.0 (the "License"); you may not + * * use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. For additional information regarding + * * copyright in this work, please see the NOTICE file in the top level + * * directory of this distribution. + * + */ + +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Usergrid.Notifications.Client +{ + public class EntityResponse : JObject + { + private HttpResponseMessage response; + + private EntityResponse(HttpResponseMessage response, JObject jObject) + : base() + { + this.response = response; + parseResponse(jObject); + } + + private void parseResponse(JObject jobject) + { + foreach (var kv in jobject) + { + this[kv.Key] = kv.Value; + } + } + + public HttpStatusCode Status + { + get { return this.response.StatusCode; } + } + + public static async Task Parse(HttpResponseMessage httpResponseMessage) + { + JObject jobject; + + using (var stream = await httpResponseMessage.Content.ReadAsStreamAsync()) + { + using (var reader = new StreamReader(stream, Encoding.UTF8)) + { + jobject = JObject.Parse(reader.ReadToEnd()); + } + } + + return new EntityResponse(httpResponseMessage, jobject); + } + + public bool StatusIsOk + { + get + { + return this.Status == HttpStatusCode.OK; + } + } + } +} diff --git a/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/IUsergridClient.cs b/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/IUsergridClient.cs new file mode 100644 index 0000000000..3f4fb82242 --- /dev/null +++ b/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/IUsergridClient.cs @@ -0,0 +1,123 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. The ASF licenses this file to You + * * under the Apache License, Version 2.0 (the "License"); you may not + * * use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. For additional information regarding + * * copyright in this work, please see the NOTICE file in the top level + * * directory of this distribution. + * + */ + +using Newtonsoft.Json.Linq; +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Windows.Networking.PushNotifications; +namespace Usergrid.Notifications.Client +{ + /// + /// encapsulates usergrid calls, use UsergridFactory + /// + public interface IUsergridClient + { + /// + /// Authenticate your calls + /// + /// + /// + /// + /// + Task Authenticate(string user, string password, bool isManagement); + /// + /// Send a message + /// + /// + /// + /// + /// + Task SendAsync(HttpMethod method, string url, object obj); + /// + /// Send a message + /// + /// + /// + /// + /// + /// + Task SendAsync(HttpMethod method, string url, object obj, bool useManagementUrl); + /// + /// Reference the push client, you should call register before using + /// + IPushClient Push { get; } + + Exception LastException { get; } + + } + + /// + /// Only show http calls + /// + public interface IUsergridHttpClient + { + /// + /// Send Http call async + /// + /// + /// + /// + /// use management endpoint + /// + Task SendAsync(HttpMethod method, string url, object obj, bool useManagementUrl); + /// + /// send Http call async + /// + /// + /// + /// + /// + Task SendAsync(HttpMethod method, string url, object obj); + } + + /// + /// Push client, call register + /// + public interface IPushClient + { + /// + /// the notifier you are currently using + /// + string Notifier { get; set; } + + /// + /// Device id in usergrid + /// + Guid DeviceId { get; set; } + /// + /// send a toast + /// + /// + /// + Task SendToast(string message); + + /// + /// Send a badge update + /// + /// + /// + Task SendBadge(T message); + + Exception LastException { get; } + + } + +} diff --git a/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/PushClient.cs b/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/PushClient.cs new file mode 100644 index 0000000000..8668626fec --- /dev/null +++ b/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/PushClient.cs @@ -0,0 +1,153 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. The ASF licenses this file to You + * * under the Apache License, Version 2.0 (the "License"); you may not + * * use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. For additional information regarding + * * copyright in this work, please see the NOTICE file in the top level + * * directory of this distribution. + * + */ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Windows.Networking.PushNotifications; +using Windows.Storage; + +namespace Usergrid.Notifications.Client +{ + public class PushClient : IPushClient + { + const string DEVICE_KEY = "currentDeviceId"; + private IUsergridHttpClient usergrid; + private ApplicationDataContainer settings; + private PushNotificationChannel channel; + + public PushClient(IUsergridHttpClient usergrid, string notifier) + { + this.usergrid = usergrid; + this.settings = ApplicationData.Current.LocalSettings; + this.Notifier = notifier; + this.init().ContinueWith(t => + { + LastException = t.Exception; + } + ); + } + + + public async Task SendToast(string message) + { + if (DeviceId == null) + { + throw new Exception("Please call PushClient.RegisterDevice first."); + } + var jsonObject = new JObject(); + var payloads = new JObject(); + var payload = new JObject(); + payload.Add("toast", new JValue(message)); + payloads.Add(Notifier, payload); + jsonObject.Add("payloads", payloads); + jsonObject.Add("debug", true); + var jsonResponse = await usergrid.SendAsync(HttpMethod.Post, String.Format("devices/{0}/notifications", this.DeviceId), jsonObject); + return jsonResponse.StatusIsOk; + } + + public async Task SendBadge(T message) + { + if (DeviceId == null) + { + throw new Exception("Please call PushClient.RegisterDevice first."); + } + var jsonObject = new JObject(); + var payloads = new JObject(); + var payload = new JObject(); + payload.Add("badge", new JValue(message)); + payloads.Add(Notifier, payload); + jsonObject.Add("payloads", payloads); + jsonObject.Add("debug", true); + var jsonResponse = await usergrid.SendAsync(HttpMethod.Post, String.Format("devices/{0}/notifications", this.DeviceId), jsonObject); + return jsonResponse.StatusIsOk; + } + + private async Task init() + { + channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync().AsTask(); + if (settings.Values[DEVICE_KEY] == null) + { + Guid uuid = await registerDevice(true); + settings.Values.Add(DEVICE_KEY, uuid); + this.DeviceId = uuid; + } + else + { + object tempId; + settings.Values.TryGetValue(DEVICE_KEY, out tempId); + this.DeviceId = Guid.Parse(tempId.ToString()); + var device = await GetDevice(DeviceId); + if (device == null) + { + Guid uuid = await registerDevice(true); + settings.Values[DEVICE_KEY] = uuid; + this.DeviceId = uuid; + } + else + { + await registerDevice(false); + } + } + } + + + private async Task GetDevice(Guid deviceId) + { + var jsonResponse = await usergrid.SendAsync(HttpMethod.Get, "devices/" + deviceId, null); + + if (jsonResponse.StatusIsOk) + { + var body = jsonResponse.GetValue("entities"); + return body != null && body.Value().Count > 0 ? body.Value()[0] : null; + } + else { return null; } + } + + private async Task registerDevice(bool isNew) + { + JObject obj = new JObject(); + obj.Add(Notifier + ".notifier.id", new JValue(channel.Uri)); + var jsonResponse = await usergrid.SendAsync( + (isNew ? HttpMethod.Post : HttpMethod.Put), + "devices/" + (isNew ? "" : this.DeviceId.ToString()), + obj + ); + + if (jsonResponse.StatusIsOk) + { + var entity = jsonResponse.GetValue("entities").Value()[0]; + var uuid = Guid.Parse(entity.Value("uuid")); + return uuid; + } + else { + return Guid.Empty; + } + } + + public string Notifier { get; set; } + public Guid DeviceId { get; set; } + public Exception LastException { get; set; } + + } +} diff --git a/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/Usergrid.cs b/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/Usergrid.cs new file mode 100644 index 0000000000..cd0330df3b --- /dev/null +++ b/sdks/dotnet/samples/notifications/Usergrid.Notifications/Client/Usergrid.cs @@ -0,0 +1,120 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. The ASF licenses this file to You + * * under the Apache License, Version 2.0 (the "License"); you may not + * * use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. For additional information regarding + * * copyright in this work, please see the NOTICE file in the top level + * * directory of this distribution. + * + */ + +using System; +using System.Threading.Tasks; +using System.Net; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System.Net.Http; +using System.Net.Http.Headers; + +namespace Usergrid.Notifications.Client +{ + + /// + /// Usergrid client + /// + + public class Usergrid : IUsergridHttpClient, IUsergridClient + { + private string appUrl; + private string token; + private HttpClient client; + private IPushClient push; + private string managementUrl; + + /// + /// Constructor + /// + /// + /// + /// + /// + internal Usergrid(string serverUrl, string org, string app, string notifier) + { + string serverUrlWithSlash = serverUrl.EndsWith("/", StringComparison.CurrentCulture) ? serverUrl : serverUrl + "/"; + this.appUrl = String.Format("{0}{1}/{2}/", serverUrlWithSlash, org, app); + this.managementUrl = serverUrlWithSlash + "management/"; + this.client = new HttpClient(); + this.push = new PushClient(this,notifier); + } + + public async Task Authenticate(string user, string password, bool isManagement) + { + var jsonObject = new JObject(); + jsonObject.Add("username", user); + jsonObject.Add("password", password); + jsonObject.Add("grant_type", "password"); + + var response = await SendAsync(HttpMethod.Post,"token", jsonObject, isManagement); + + if (response.StatusIsOk) + { + this.token = response.GetValue("access_token").Value(); + client.DefaultRequestHeaders.Add("X-Authorization", token); + } + else + { + throw new Exception("Authentication failed: "+response.ToString()); + } + } + + private async Task GetJsonResponse(HttpResponseMessage response) + { + return await EntityResponse.Parse(response); + } + + public async Task SendAsync(HttpMethod method, string url, object obj) + { + return await SendAsync(method, url, obj, false); + } + + public async Task SendAsync(HttpMethod method, string url, object obj, bool useManagementUrl) + { + HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, (useManagementUrl ? this.managementUrl : this.appUrl) + url); + if (obj != null) + { + message.Content = getJsonBody(obj); + } + message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue( "application/json")); + var response = await this.client.SendAsync(message); + return await EntityResponse.Parse(response); + } + + public IPushClient Push + { + get { return push; } + } + + private HttpContent getJsonBody(Object jsonObject) + { + return new StringContent(JsonConvert.SerializeObject(jsonObject)); + } + + + public Exception LastException + { + get; + set; + } + } + +} diff --git a/sdks/dotnet/samples/notifications/Usergrid.Notifications/MainPage.xaml b/sdks/dotnet/samples/notifications/Usergrid.Notifications/MainPage.xaml index 3e0affdb58..f22c8b6616 100644 --- a/sdks/dotnet/samples/notifications/Usergrid.Notifications/MainPage.xaml +++ b/sdks/dotnet/samples/notifications/Usergrid.Notifications/MainPage.xaml @@ -7,14 +7,32 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> - + - -