This commit is contained in:
foobar
2022-08-21 21:39:06 +02:00
commit 27c1969aaa
7354 changed files with 897064 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\City;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class CityController extends Controller
{
public function show()
{
$DatabaseController = new DatabaseController();
return view('cities', [
'cities' => $DatabaseController->getNewestWeatherDataForAllCities()
]);
}
public function create(Request $request) {
$request->validate([
'name' => 'required|max:85|regex:/^[a-zA-Z\säöüÄÖÜß]+$/',
]);
$city = $request->name;
$response = WeatherstackController::requestByCity($city);
$WeatherstackController = new WeatherstackController();
$isValidResponse = $WeatherstackController->checkResponse($city, $response);
($isValidResponse[0]) ? DatabaseController::store($response) : redirect('/')->withErrors(['name' => $isValidResponse[1]]);
return redirect('/');
}
public function delete($id) {
City::findOrFail($id)->delete();
return redirect('/');
}
public function refresh() {
$cities = DB::table('cities')
->select('id', 'location_name', 'location_country')
->get();
foreach ($cities as $city) {
$city = "$city->location_name,$city->location_country";
$response = WeatherstackController::requestByCity($city);
($response->successful() === false) ? redirect('/')->withErrors(['name' => "Aktualisierung fehlgeschlagen"])
: DatabaseController::store($response);
}
return redirect('/');
}
public function setup() {
$credentials = [
'email' => 'admin@admin.com',
'password' => 'password'
];
if (!Auth::attempt($credentials)) {
$user = new \App\Models\User();
$user->name = 'Admin';
$user->email = $credentials['email'];
$user->password = Hash::make($credentials['password']);
$user->save();
if (Auth::attempt($credentials)) {
$user = Auth::user();
$adminToken = $user->createToken('admin-token', ['create','update','delete']);
$updateToken = $user->createToken('update-token', ['create','update']);
$basicToken = $user->createToken('basic-token', ['none']);
return [
'admin' => $adminToken->plainTextToken,
'update' => $updateToken->plainTextToken,
'basic' => $basicToken->plainTextToken,
];
}
}
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

View File

@@ -0,0 +1,97 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use App\Models\City;
use App\Models\WeatherData;
use Illuminate\Http\Client\Response as ClientResponse;
use App\Http\Requests\StoreCityRequest;
use App\Http\Requests\UpdateCityRequest;
class DatabaseController extends Controller
{
public static function getNewestWeatherDataByCityID($city_id) {
return DB::table('cities')
->join('weather_data', 'cities.id', '=', 'weather_data.city_id')
->select('cities.id', 'cities.location_name', 'cities.location_country', 'weather_data.current_temperature', 'weather_data.weather_icon', 'weather_data.weather_description', 'weather_data.wind_speed', 'weather_data.wind_dir', 'weather_data.localtime_epoch')
->where('cities.id', '=', $city_id)
->orderBy('localtime_epoch', 'desc')
->first();
}
public function getNewestWeatherDataForAllCities () {
$city_ids = DB::table('cities')->pluck('id');
$responses = collect();
foreach ($city_ids as $city_id) {
$response = $this->getNewestWeatherDataByCityID($city_id);
$responses->push($response);
}
return $responses;
}
public static function store(ClientResponse $response) {
$city = City::firstOrNew([
'location_name' => $response->json('location.name'),
'location_country' => $response->json('location.country')
]);
$city->save();
$weatherData = WeatherData::firstOrNew([
'city_id' => $city->id,
'current_temperature' => $response->json('current.temperature'),
'weather_icon' => $response->json("current.weather_icons")[0],
'weather_description' => $response->json('current.weather_descriptions')[0],
'wind_speed' => $response->json('current.wind_speed'),
'wind_dir' => $response->json('current.wind_dir'),
'localtime_epoch' => $response->json('location.localtime_epoch')
]);
$weatherData->save();
}
public static function storeApiRequest(StoreCityRequest $request) {
$city = City::firstOrNew([
'location_name' => $request->location_name,
'location_country' => $request->location_country
]);
$city->save();
$weatherData = WeatherData::firstOrNew([
'city_id' => $city->id,
'current_temperature' => $request->currentTemperature,
'weather_icon' => $request->weatherIcon,
'weather_description' => $request->weatherDescription,
'wind_speed' => $request->windSpeed,
'wind_dir' => $request->windDir,
'localtime_epoch' => $request->localtimeEpoch
]);
$weatherData->save();
return $city->id;
}
public function updateApiRequest($id, UpdateCityRequest $request) {
$city = $this->getNewestWeatherDataByCityID($id);
DB::table('cities')
->join('weather_data', 'cities.id', '=', 'weather_data.city_id')
->select('cities.location_name', 'cities.location_country', 'weather_data.current_temperature', 'weather_data.weather_icon', 'weather_data.weather_description', 'weather_data.wind_speed', 'weather_data.wind_dir', 'weather_data.localtime_epoch')
->where('cities.id', '=', $id)
->where('weather_data.localtime_epoch', '=', $city->localtime_epoch)
->update([
'cities.location_name' => $request->location_name,
'cities.location_country' => $request->location_country,
'weather_data.current_temperature' => $request->currentTemperature,
'weather_data.weather_icon' => $request->weatherIcon,
'weather_data.weather_description' => $request->weatherDescription,
'weather_data.wind_speed' => $request->windSpeed,
'weather_data.wind_dir' => $request->windDir,
'weather_data.localtime_epoch' => $request->localtimeEpoch
]);
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\Response as ClientResponse;
use App\Models\City;
class WeatherstackController extends Controller
{
public static function requestByCity($city) {
$access_key = config('app.weatherstack_api_key');
$units = 'm'; /* m for Metric, s for Scientific, f for Fahrenheit */
$url = 'http://api.weatherstack.com/current';
return Http::acceptJson()->get($url, [
'access_key' => $access_key,
'units' => $units,
'query' => $city
]);
}
public function checkResponse($city, ClientResponse $response) {
if ($response->successful()) {
[$isValidResponse, $error] = $this->checkErrorMessage($city, $response);
}
elseif ($response->failed()) {
$isValidResponse = false;
$error = 'Request failed.';
}
return [$isValidResponse, $error];
}
public static function checkErrorMessage($city, ClientResponse $response) {
$isValidResponse = true;
$error = '';
if ($response->json('success') === false) {
$isValidResponse = false;
($response->json('error.type') === 'usage_limit_reached') ? $error = 'The usage limit of your API key has been reached.'
: $error = "No city named '{$city}' could be found.";
}
elseif (City::where('location_name', $response->json('location.name'))->exists()) {
$isValidResponse = false;
$error = "'{$response->json('location.name')}, {$response->json('location.country')}' has been already added.";
}
return [$isValidResponse, $error];
}
}

67
app/Http/Kernel.php Normal file
View File

@@ -0,0 +1,67 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array<int, class-string|string>
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* @var array<string, array<int, class-string|string>>
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array<string, class-string|string>
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array<int, string>
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware;
class PreventRequestsDuringMaintenance extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array<int, string>
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @param string|null ...$guards
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
}
return $next($request);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
class TrimStrings extends Middleware
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array<int, string>
*/
protected $except = [
'current_password',
'password',
'password_confirmation',
];
}

View File

@@ -0,0 +1,20 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustHosts as Middleware;
class TrustHosts extends Middleware
{
/**
* Get the host patterns that should be trusted.
*
* @return array<int, string|null>
*/
public function hosts()
{
return [
$this->allSubdomainsOfApplicationUrl(),
];
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array<int, string>|string|null
*/
protected $proxies;
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB;
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Routing\Middleware\ValidateSignature as Middleware;
class ValidateSignature extends Middleware
{
/**
* The names of the parameters that should be ignored.
*
* @var array<int, string>
*/
protected $ignore = [
// 'fbclid',
// 'utm_campaign',
// 'utm_content',
// 'utm_medium',
// 'utm_source',
// 'utm_term',
];
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array<int, string>
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreCityRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
$user = $this->user();
return $user != null && $user->tokenCan('create');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'locationName' => ['required'],
'locationCountry' => ['required'],
'currentTemperature' => ['required'],
'weatherIcon' => ['required'],
'weatherDescription' => ['required'],
'windSpeed' => ['required'],
'localtimeEpoch' => ['required'],
];
}
protected function prepareForValidation() {
$this->merge([
'location_name' => $this->locationName,
'location_country' => $this->locationCountry,
'current_temperature' => $this->currentTemperature,
'weather_icon' => $this->weatherIcon,
'weather_description' => $this->weatherDescription,
'wind_speed' => $this->wind_speed,
'localtime_epoch' => $this->localtime_epoch
]);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateCityRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
$user = $this->user();
return $user != null && $user->tokenCan('update');
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
if ($this->method() == 'PUT') {
return [
'locationName' => ['required'],
'locationCountry' => ['required'],
'currentTemperature' => ['required'],
'weatherIcon' => ['required'],
'weatherDescription' => ['required'],
'windSpeed' => ['required'],
'localtimeEpoch' => ['required'],
];
}
}
protected function prepareForValidation() {
$this->merge([
'location_name' => $this->locationName,
'location_country' => $this->locationCountry,
'current_temperature' => $this->currentTemperature,
'weather_icon' => $this->weatherIcon,
'weather_description' => $this->weatherDescription,
'wind_speed' => $this->wind_speed,
'localtime_epoch' => $this->localtime_epoch
]);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class CityCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'data' => $this->collection,
'meta' => ['count' => $this->collection->count()]
];
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class CityResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'locationName' => $this->location_name,
'locationCountry' => $this->location_country,
'weatherData' => new WeatherDataCollection($this->weatherData)
];
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class WeatherDataCollection extends ResourceCollection
{
/**
* Transform the resource collection into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'data' => $this->collection
];
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class WeatherDataResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'currentTemperature' => $this->current_temperature,
'weatherIcon' => $this->weather_icon,
'weatherDescription' => $this->weather_description,
'windSpeed' => $this->wind_speed,
'windDir' => $this->wind_dir,
'localtimeEpoch' => $this->localtime_epoch,
];
}
}