PageRenderTime 48ms CodeModel.GetById 33ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Server/DeviceHive.API/Controllers/DeviceController.cs

https://github.com/oryol/devicehive-.net
C# | 220 lines | 146 code | 20 blank | 54 comment | 60 complexity | 726879453e13364a0317c8fa9853aa2c MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.Linq;
  4using System.Net;
  5using System.Net.Http;
  6using System.Web.Http;
  7using DeviceHive.API.Filters;
  8using DeviceHive.API.Mapping;
  9using DeviceHive.Data.Model;
 10using Newtonsoft.Json.Linq;
 11
 12namespace DeviceHive.API.Controllers
 13{
 14    /// <resource cref="Device" />
 15    public class DeviceController : BaseController
 16    {
 17        /// <name>list</name>
 18        /// <summary>
 19        /// Gets list of devices.
 20        /// </summary>
 21        /// <returns cref="Device">If successful, this method returns array of <see cref="Device"/> resources in the response body.</returns>
 22        [AuthorizeUser(Roles = "Administrator")]
 23        public JArray Get()
 24        {
 25            return new JArray(DataContext.Device.GetAll().Select(n => Mapper.Map(n)));
 26        }
 27
 28        /// <name>get</name>
 29        /// <summary>
 30        /// Gets information about device.
 31        /// </summary>
 32        /// <param name="id">Device unique identifier.</param>
 33        /// <returns cref="Device">If successful, this method returns a <see cref="Device"/> resource in the response body.</returns>
 34        [AuthorizeUser]
 35        public JObject Get(Guid id)
 36        {
 37            var device = DataContext.Device.Get(id);
 38            if (device == null || !IsNetworkAccessible(device.NetworkID))
 39                ThrowHttpResponse(HttpStatusCode.NotFound, "Device not found!");
 40
 41            return Mapper.Map(device);
 42        }
 43
 44        public HttpResponseMessage Post(JObject json)
 45        {
 46            return HttpResponse(HttpStatusCode.MethodNotAllowed, "The method is not allowed, please use POST /device/{id} to register a device");
 47        }
 48
 49        /// <name>register</name>
 50        /// <summary>
 51        ///     <para>Registers a device.</para>
 52        ///     <para>If device with specified identifier has already been registered, it gets updated in case when valid key is provided in the authorization header.</para>
 53        /// </summary>
 54        /// <param name="id">Device unique identifier.</param>
 55        /// <param name="json" cref="Device">In the request body, supply a <see cref="Device"/> resource.</param>
 56        /// <returns cref="Device">If successful, this method returns a <see cref="Device"/> resource in the response body.</returns>
 57        /// <request>
 58        ///     <parameter name="network" mode="remove" />
 59        ///     <parameter name="deviceClass" mode="remove" />
 60        ///     <parameter name="network" type="integer, string, or object" required="true">
 61        ///         <para>Network identifier, network key or <see cref="Network"/> object.</para>
 62        ///         <para>If object is passed, the target network will be searched by name and automatically created if not found.</para>
 63        ///         <para>In case when existing network is protected with the key, the key value must be included.</para>
 64        ///     </parameter>
 65        ///     <parameter name="deviceClass" type="integer or object" required="true">
 66        ///         <para>Device class identifier or <see cref="DeviceClass"/> object.</para>
 67        ///         <para>If object is passed, the target device class will be searched by name and version, and automatically created if not found.</para>
 68        ///     </parameter>
 69        ///     <parameter name="equipment" type="array" required="false" cref="Equipment">
 70        ///         <para>Array of <see cref="Equipment"/> objects to be associated with the device class. If specified, all existing values will be replaced.</para>
 71        ///         <para>In case when device class is permanent, this value is ignored.</para>
 72        ///     </parameter>
 73        /// </request>
 74        public JObject Put(Guid id, JObject json)
 75        {
 76            // load device from repository
 77            var device = DataContext.Device.Get(id);
 78            if (device != null)
 79            {
 80                // if device exists, administrator or device authorization is required
 81                if ((RequestContext.CurrentUser == null || RequestContext.CurrentUser.Role != (int)UserRole.Administrator) &&
 82                    (RequestContext.CurrentDevice == null || RequestContext.CurrentDevice.GUID != id))
 83                {
 84                    ThrowHttpResponse(HttpStatusCode.Unauthorized, "Not authorized");
 85                }
 86            }
 87            else
 88            {
 89                // otherwise, create new device
 90                device = new Device(id);
 91            }
 92
 93            // map and save the device object
 94            ResolveNetwork(json, device.ID == 0);
 95            ResolveDeviceClass(json, device.ID == 0);
 96
 97            Mapper.Apply(device, json);
 98            Validate(device);
 99
100            DataContext.Device.Save(device);
101
102            // replace equipments for the corresponding device class
103            if (!device.DeviceClass.IsPermanent && json["equipment"] is JArray)
104            {
105                foreach (var equipment in DataContext.Equipment.GetByDeviceClass(device.DeviceClass.ID))
106                {
107                    DataContext.Equipment.Delete(equipment.ID);
108                }
109                foreach (JObject jEquipment in (JArray)json["equipment"])
110                {
111                    var equipment = GetMapper<Equipment>().Map(jEquipment);
112                    equipment.DeviceClass = device.DeviceClass;
113                    Validate(equipment);
114                    DataContext.Equipment.Save(equipment);
115                }
116            }
117
118            return Mapper.Map(device);
119        }
120
121        /// <name>delete</name>
122        /// <summary>
123        /// Deletes an existing device.
124        /// </summary>
125        /// <param name="id">Device unique identifier.</param>
126        [HttpNoContentResponse]
127        [AuthorizeUser(Roles = "Administrator")]
128        public void Delete(Guid id)
129        {
130            var device = DataContext.Device.Get(id);
131            if (device != null)
132            {
133                DataContext.Device.Delete(device.ID);
134            }
135        }
136
137        private IJsonMapper<Device> Mapper
138        {
139            get { return GetMapper<Device>(); }
140        }
141
142        private void ResolveNetwork(JObject json, bool isRequired)
143        {
144            var jNetwork = json.Property("network");
145            if (isRequired && jNetwork == null)
146                ThrowHttpResponse(HttpStatusCode.BadRequest, "Required 'network' property was not specified!");
147
148            Network network = null;
149            var verifyNetworkKey = RequestContext.CurrentUser == null;
150            if (jNetwork != null && jNetwork.Value is JValue)
151            {
152                var jNetworkValue = (JValue)jNetwork.Value;
153                if (jNetworkValue.Value is long)
154                {
155                    // search network by ID
156                    network = DataContext.Network.Get((int)jNetworkValue);
157                    if (verifyNetworkKey && network != null && network.Key != null)
158                        ThrowHttpResponse(HttpStatusCode.Forbidden, "Could not register a device because target network is protected with a key!");
159                }
160                else if (jNetworkValue.Value is string)
161                {
162                    // search network by key
163                    network = DataContext.Network.GetByKey((string)jNetworkValue);
164                    if (network == null)
165                        ThrowHttpResponse(HttpStatusCode.BadRequest, "Network with specified key was not found!");
166                    jNetwork.Value = (long)network.ID;
167                }
168            }
169            else if (jNetwork != null && jNetwork.Value is JObject)
170            {
171                // search network by name or auto-create
172                var jNetworkObj = (JObject)jNetwork.Value;
173                if (jNetworkObj["name"] == null)
174                    ThrowHttpResponse(HttpStatusCode.BadRequest, "Specified 'network' object must include 'name' property!");
175
176                network = DataContext.Network.Get((string)jNetworkObj["name"]);
177                if (network == null)
178                {
179                    // auto-create network if it does not exist
180                    network = new Network();
181                    GetMapper<Network>().Apply(network, jNetworkObj);
182                    DataContext.Network.Save(network);
183                }
184
185                // check passed network key
186                if (verifyNetworkKey && network.Key != null && (string)jNetworkObj["key"] != network.Key)
187                    ThrowHttpResponse(HttpStatusCode.Forbidden, "Could not register a device because target network is protected with a key!");
188
189                jNetwork.Value = (long)network.ID;
190            }
191        }
192
193        private void ResolveDeviceClass(JObject json, bool isRequired)
194        {
195            var jDeviceClass = json.Property("deviceClass");
196            if (isRequired && jDeviceClass == null)
197                ThrowHttpResponse(HttpStatusCode.BadRequest, "Required 'deviceClass' property was not specified!");
198            
199            if (jDeviceClass != null && jDeviceClass.Value is JObject)
200            {
201                // search device class by name/version or auto-create
202                var jDeviceClassObj = (JObject)jDeviceClass.Value;
203                if (jDeviceClassObj["name"] == null)
204                    ThrowHttpResponse(HttpStatusCode.BadRequest, "Specified 'deviceClass' object must include 'name' property!");
205                if (jDeviceClassObj["version"] == null)
206                    ThrowHttpResponse(HttpStatusCode.BadRequest, "Specified 'deviceClass' object must include 'version' property!");
207
208                var deviceClass = DataContext.DeviceClass.Get((string)jDeviceClassObj["name"], (string)jDeviceClassObj["version"]);
209                if (deviceClass == null)
210                {
211                    // auto-create device class if it does not exist
212                    deviceClass = new DeviceClass();
213                    GetMapper<DeviceClass>().Apply(deviceClass, jDeviceClassObj);
214                    DataContext.DeviceClass.Save(deviceClass);
215                }
216                jDeviceClass.Value = (long)deviceClass.ID;
217            }
218        }
219    }
220}