Completed
Pull Request — master (#33)
by Brandon
01:59
created

ApiController::image()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 35
Code Lines 18

Duplication

Lines 3
Ratio 8.57 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 3
loc 35
ccs 0
cts 16
cp 0
rs 8.8571
cc 3
eloc 18
nc 3
nop 1
crap 12
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use Validator;
6
use Illuminate\Http\Request;
7
use App\Device;
8
use App\Deviceimage;
9
use Illuminate\Support\Facades\Cache;
10
use Illuminate\Support\Facades\Storage;
11
12
class ApiController extends Controller
13
{
14
    /**
15
     * Creates a json response for all the devices.
16
     *
17
     * @return Response
18
     */    
19
    public function index()
20
    {
21
        return response()->json(['data' => 'SmartSettia API - Bad request type.'], 400);
22
    }
23
24
    /**
25
     * Creates a json response for a specifc device.
26
     *
27
     * @param  Device  $device
28
     * @return Response
29
     */    
30
    public function show(Device $device)
31
    {
32
        return response()->json($device, 200);
33
    }
34
35
    /**
36
     * Updates the status of a device.
37
     *
38
     * @param  Request  $request
39
     * @return Response
40
     */
41
    public function update(Request $request)
42
    {
43
        // Validate the request
44
        $validator = Validator::make($request->all(), [
45
            'uuid'          => 'required|string|max:255|exists:devices,uuid',
46
            'token'         => 'required|string|max:60',
47
            'version'       => 'nullable|string|max:32',
48
            'hostname'      => 'nullable|string|alpha_num|max:255',
49
            'ip'            => 'nullable|ip',
50
            'mac_address'   => 'nullable|string|min:16|max:16',
51
            'time'          => 'nullable|date',
52
            'cover_status'  => 'nullable|string|max:32',
53
            'error_msg'     => 'nullable|string',
54
            'limitsw_open'   => 'nullable|boolean',
55
            'limitsw_closed' => 'nullable|boolean',
56
            'light_in'      => 'nullable|numeric',
57
            'light_out'     => 'nullable|numeric',
58
            'cpu_temp'      => 'nullable|numeric',
59
            'temperature'   => 'nullable|numeric',
60
            'humidity'      => 'nullable|numeric',
61
        ]);
62
        
63
        // If validation fails, send the validation error back with status 400
64
        if ($validator->fails()) {
65
            return response()->json(['data' => $validator->toArray()], 400);
66
        }
67
        
68
        // Get the device record
69
        $device = Device::getDeviceByUUID($request->input('uuid'));
0 ignored issues
show
Bug introduced by
It seems like $request->input('uuid') targeting Illuminate\Http\Concerns...ractsWithInput::input() can also be of type array; however, App\Device::getDeviceByUUID() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
70
        
71
        // If token doesnt match then send 401 unauthorized.
72 View Code Duplication
        if ($request->input('token') != $device->token) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
73
            return response()->json(['data' => 'Bad token.'], 401);
74
        }
75
        
76
        // Update the device
77
        $device->version = $request->input('version');
78
        $device->hostname = $request->input('hostname');
79
        $device->ip = $request->input('ip');
80
        $device->mac_address = $request->input('mac_address');
81
        $device->time = $request->input('time');
82
        $device->cover_status = $request->input('cover_status');
83
        $device->error_msg = $request->input('error_msg');
84
        $device->limitsw_open = $request->input('limitsw_open');
85
        $device->limitsw_closed = $request->input('limitsw_closed');
86
        $device->light_in = $request->input('light_in');
87
        $device->light_out = $request->input('light_out');
88
        $device->cpu_temp = $request->input('cpu_temp');
89
        $device->temperature = $request->input('temperature');
90
        $device->humidity = $request->input('humidity');
91
        
92
        $device->save();
93
        
94
        // Create an api token for the new device.
95
        $device->generateToken();
96
        
97
        // A 'Registered' event is created and will trigger any relevant
98
        // observers, such as sending a confirmation email or any 
99
        // code that needs to be run as soon as the device is created.
100
        //event(new Registered(true));
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
101
        
102
        // Return the new device info including the token.
103
        return response()->json(['data' => $device->toArray()], 201);
104
    }
105
    
106
    /**
107
     * Registers a new device.
108
     *
109
     * @param  Request  $request
110
     * @return Response
111
     */
112
    public function register(Request $request)
113
    {
114
        // Validate the request
115
        $validator = Validator::make($request->all(), [
116
            'uuid' => 'required|string|max:255',
117
            'challenge' => 'required|string|min:6',
118
        ]);
119
        
120
        // If validation fails, send the validation error back with status 400
121
        if ($validator->fails()) {
122
            return response()->json(['data' => $validator->toArray()], 400);
123
        }
124
        
125
        // If challenge string doesnt match then send 401 unauthorized.
126
        if ($request->input('challenge') != env('API_CHALLENGE', 'temppass')) {
127
            return response()->json(['data' => 'Bad challenge.'], 401);
128
        }
129
        
130
        // If the uuid already exists then just send them the record.
131
        if ($device = Device::getDeviceByUUID($request->input('uuid'))) {
0 ignored issues
show
Bug introduced by
It seems like $request->input('uuid') targeting Illuminate\Http\Concerns...ractsWithInput::input() can also be of type array; however, App\Device::getDeviceByUUID() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
132
            return response()->json([ 'data' => [ 
133
                'name' => $device->name,
134
                'uuid' => $device->uuid,
135
                'id' => $device->id,
136
                'token' => $device->token,
137
            ]], 200);
138
        }
139
        
140
        // Create the new device
141
        $device = new Device;
142
        $device->name = 'New Device';
0 ignored issues
show
Documentation introduced by
The property name does not exist on object<App\Device>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
143
        $device->uuid = $request->input('uuid');
0 ignored issues
show
Documentation introduced by
The property uuid does not exist on object<App\Device>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
144
        $device->save();
145
        
146
        // Create an api token for the new device.
147
        $device->generateToken();
148
        
149
        // A 'Registered' event is created and will trigger any relevant
150
        // observers, such as sending a confirmation email or any 
151
        // code that needs to be run as soon as the device is created.
152
        //event(new Registered(true));
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
153
        
154
        // Return the new device info including the token.
155
        return response()->json([ 'data' => [ 
156
            'name' => $device->name,
0 ignored issues
show
Documentation introduced by
The property name does not exist on object<App\Device>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
157
            'uuid' => $device->uuid,
0 ignored issues
show
Documentation introduced by
The property uuid does not exist on object<App\Device>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
158
            'id' => $device->id,
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<App\Device>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
159
            'token' => $device->token,
0 ignored issues
show
Documentation introduced by
The property token does not exist on object<App\Device>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
160
        ]], 201);
161
    }
162
    
163
    /**
164
     * Updates the image for a device.
165
     *
166
     * @param  Request  $request
167
     * @return Response
168
     */
169
    public function image(Request $request) {
170
        // Validate the request
171
        $validator = Validator::make($request->all(), [
172
            'uuid'          => 'required|string|max:255|exists:devices,uuid',
173
            'token'         => 'required|string|max:60',
174
            'image'         => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
175
        ]);
176
        
177
        // If validation fails, send the validation error back with status 400.
178
        if ($validator->fails()) {
179
            return response()->json(['data' => $validator->toArray()], 400);
180
        }
181
        
182
        // Get the device record.
183
        $device = Device::getDeviceByUUID($request->input('uuid'));
0 ignored issues
show
Bug introduced by
It seems like $request->input('uuid') targeting Illuminate\Http\Concerns...ractsWithInput::input() can also be of type array; however, App\Device::getDeviceByUUID() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
184
        
185
        // If token doesnt match then send 401 unauthorized.
186 View Code Duplication
        if ($request->input('token') != $device->token) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
187
            return response()->json(['data' => 'Bad token.'], 401);
188
        }
189
        
190
        // Save the image to disk.
191
        $path = $request->file('image')->storeAs('deviceimage', $device['id'], 'private');
192
        
193
        // Update the url for the image
194
        $deviceimage = Deviceimage::updateOrCreate(
195
            ['device_id' => $device['id']],
196
            ['url' => $path]
197
        );
198
        
199
        return response()->json([ 'data' => [ 
200
            'id' => $deviceimage['id'],
201
            'url' => $path,
202
        ]], 201);
203
    }
204
}
205
206
// HTTP STATUS CODES:
207
// 200: OK. The standard success code and default option.
208
// 201: Object created. Useful for the store actions.
209
// 204: No content. When an action was executed successfully, but there is no content to return.
210
// 206: Partial content. Useful when you have to return a paginated list of resources.
211
// 400: Bad request. The standard option for requests that fail to pass validation.
212
// 401: Unauthorized. The user needs to be authenticated.
213
// 403: Forbidden. The user is authenticated, but does not have the permissions to perform an action.
214
// 404: Not found. This will be returned automatically by Laravel when the resource is not found.
215
// 500: Internal server error. Ideally you're not going to be explicitly returning this, but if something unexpected breaks, this is what your user is going to receive.
216
// 503: Service unavailable. Pretty self explanatory, but also another code that is not going to be returned explicitly by the application.