diff --git a/apps/weather_status/lib/Capabilities.php b/apps/weather_status/lib/Capabilities.php index c9de0039a3985..b58b11e83db66 100644 --- a/apps/weather_status/lib/Capabilities.php +++ b/apps/weather_status/lib/Capabilities.php @@ -45,6 +45,8 @@ public function __construct() { /** * @inheritDoc + * + * @return array{weather_status: array{enabled: bool}} */ public function getCapabilities() { return [ diff --git a/apps/weather_status/lib/Controller/WeatherStatusController.php b/apps/weather_status/lib/Controller/WeatherStatusController.php index 01bdf78f4107e..40216be675267 100644 --- a/apps/weather_status/lib/Controller/WeatherStatusController.php +++ b/apps/weather_status/lib/Controller/WeatherStatusController.php @@ -25,6 +25,7 @@ */ namespace OCA\WeatherStatus\Controller; +use OCA\WeatherStatus\ResponseDefinitions; use OCA\WeatherStatus\Service\WeatherStatusService; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; @@ -32,6 +33,9 @@ use OCP\ILogger; use OCP\IRequest; +/** + * @psalm-import-type WeatherStatusForecast from ResponseDefinitions + */ class WeatherStatusController extends OCSController { /** @var string */ @@ -59,7 +63,7 @@ public function __construct(string $appName, * * Try to use the address set in user personal settings as weather location * - * @return DataResponse with success state and address information + * @return DataResponse */ public function usePersonalAddress(): DataResponse { return new DataResponse($this->service->usePersonalAddress()); @@ -73,7 +77,7 @@ public function usePersonalAddress(): DataResponse { * - use the user defined address * * @param int $mode New mode - * @return DataResponse success state + * @return DataResponse */ public function setMode(int $mode): DataResponse { return new DataResponse($this->service->setMode($mode)); @@ -88,7 +92,7 @@ public function setMode(int $mode): DataResponse { * @param string|null $address Any approximative or exact address * @param float|null $lat Latitude in decimal degree format * @param float|null $lon Longitude in decimal degree format - * @return DataResponse with success state and address information + * @return DataResponse */ public function setLocation(?string $address, ?float $lat, ?float $lon): DataResponse { $currentWeather = $this->service->setLocation($address, $lat, $lon); @@ -100,7 +104,7 @@ public function setLocation(?string $address, ?float $lat, ?float $lon): DataRes * * Get stored user location * - * @return DataResponse which contains coordinates, formatted address and current weather status mode + * @return DataResponse */ public function getLocation(): DataResponse { $location = $this->service->getLocation(); @@ -112,7 +116,10 @@ public function getLocation(): DataResponse { * * Get forecast for current location * - * @return DataResponse which contains success state and filtered forecast data + * @return DataResponse|DataResponse + * + * 200: Forecast returned + * 404: Forecast not found */ public function getForecast(): DataResponse { $forecast = $this->service->getForecast(); @@ -128,7 +135,7 @@ public function getForecast(): DataResponse { * * Get favorites list * - * @return DataResponse which contains the favorite list + * @return DataResponse */ public function getFavorites(): DataResponse { return new DataResponse($this->service->getFavorites()); @@ -139,8 +146,8 @@ public function getFavorites(): DataResponse { * * Set favorites list * - * @param array $favorites - * @return DataResponse success state + * @param string[] $favorites Favorite addresses + * @return DataResponse */ public function setFavorites(array $favorites): DataResponse { return new DataResponse($this->service->setFavorites($favorites)); diff --git a/apps/weather_status/lib/ResponseDefinitions.php b/apps/weather_status/lib/ResponseDefinitions.php new file mode 100644 index 0000000000000..08f8049b96483 --- /dev/null +++ b/apps/weather_status/lib/ResponseDefinitions.php @@ -0,0 +1,87 @@ + + * + * @author Kate Döen + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\WeatherStatus; + +/** + * https://api.met.no/doc/ForecastJSON + * @psalm-type WeatherStatusForecast = array{ + * time: string, + * data: array{ + * instant: array{ + * details: array{ + * air_pressure_at_sea_level: float, + * air_temperature: float, + * cloud_area_fraction: float, + * cloud_area_fraction_high: float, + * cloud_area_fraction_low: float, + * cloud_area_fraction_medium: float, + * dew_point_temperature: float, + * fog_area_fraction: float, + * relative_humidity: float, + * ultraviolet_index_clear_sky: float, + * wind_from_direction: float, + * wind_speed: float, + * wind_speed_of_gust: float, + * }, + * }, + * next_12_hours: array{ + * summary: array{ + * symbol_code: string, + * }, + * details: array{ + * probability_of_precipitation: float, + * }, + * }, + * next_1_hours: array{ + * summary: array{ + * symbol_code: string, + * }, + * details: array{ + * precipitation_amount: float, + * precipitation_amount_max: float, + * precipitation_amount_min: float, + * probability_of_precipitation: float, + * probability_of_thunder: float, + * }, + * }, + * next_6_hours: array{ + * summary: array{ + * symbol_code: string, + * }, + * details: array{ + * air_temperature_max: float, + * air_temperature_min: float, + * precipitation_amount: float, + * precipitation_amount_max: float, + * precipitation_amount_min: float, + * probability_of_precipitation: float, + * }, + * }, + * }, + * } + */ +class ResponseDefinitions { +} diff --git a/apps/weather_status/lib/Service/WeatherStatusService.php b/apps/weather_status/lib/Service/WeatherStatusService.php index 5b1d926f0909b..968dd7ecff635 100644 --- a/apps/weather_status/lib/Service/WeatherStatusService.php +++ b/apps/weather_status/lib/Service/WeatherStatusService.php @@ -131,8 +131,7 @@ public function setMode(int $mode): array { /** * Get favorites list - * @param array $favorites - * @return array success state + * @return string[] */ public function getFavorites(): array { $favoritesJson = $this->config->getUserValue($this->userId, Application::APP_ID, 'favorites', ''); @@ -141,7 +140,7 @@ public function getFavorites(): array { /** * Set favorites list - * @param array $favorites + * @param string[] $favorites * @return array success state */ public function setFavorites(array $favorites): array { diff --git a/apps/weather_status/openapi.json b/apps/weather_status/openapi.json new file mode 100644 index 0000000000000..d5959f6d42d24 --- /dev/null +++ b/apps/weather_status/openapi.json @@ -0,0 +1,915 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "weather_status", + "description": "Weather status in your dashboard", + "license": { + "name": "agpl" + }, + "version": "1.7.0" + }, + "paths": { + "/ocs/v2.php/apps/weather_status/api/v1/mode": { + "put": { + "tags": [ + "weather_status" + ], + "summary": "Change the weather status mode. There are currently 2 modes: - ask the browser - use the user defined address", + "operationId": "weather_status-set-mode", + "parameters": [ + { + "name": "mode", + "in": "query", + "description": "New mode", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "required": true, + "schema": { + "type": "string", + "default": "true" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "required": [ + "ocs" + ], + "type": "object", + "properties": { + "ocs": { + "required": [ + "meta", + "data" + ], + "type": "object", + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "required": [ + "success" + ], + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ] + } + }, + "/ocs/v2.php/apps/weather_status/api/v1/use-personal": { + "put": { + "tags": [ + "weather_status" + ], + "summary": "Try to use the address set in user personal settings as weather location", + "operationId": "weather_status-use-personal-address", + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "required": true, + "schema": { + "type": "string", + "default": "true" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "required": [ + "ocs" + ], + "type": "object", + "properties": { + "ocs": { + "required": [ + "meta", + "data" + ], + "type": "object", + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "required": [ + "success", + "lat", + "lon", + "address" + ], + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "lat": { + "type": "number", + "format": "float", + "nullable": true + }, + "lon": { + "type": "number", + "format": "float", + "nullable": true + }, + "address": { + "type": "string", + "nullable": true + } + } + } + } + } + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ] + } + }, + "/ocs/v2.php/apps/weather_status/api/v1/location": { + "get": { + "tags": [ + "weather_status" + ], + "summary": "Get stored user location", + "operationId": "weather_status-get-location", + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "required": true, + "schema": { + "type": "string", + "default": "true" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "required": [ + "ocs" + ], + "type": "object", + "properties": { + "ocs": { + "required": [ + "meta", + "data" + ], + "type": "object", + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "required": [ + "lat", + "lon", + "address", + "mode" + ], + "type": "object", + "properties": { + "lat": { + "type": "number", + "format": "float" + }, + "lon": { + "type": "number", + "format": "float" + }, + "address": { + "type": "string" + }, + "mode": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ] + }, + "put": { + "tags": [ + "weather_status" + ], + "summary": "Set address and resolve it to get coordinates or directly set coordinates and get address with reverse geocoding", + "operationId": "weather_status-set-location", + "parameters": [ + { + "name": "address", + "in": "query", + "description": "Any approximative or exact address", + "schema": { + "type": "string", + "nullable": true + } + }, + { + "name": "lat", + "in": "query", + "description": "Latitude in decimal degree format", + "schema": { + "type": "number", + "format": "float", + "nullable": true + } + }, + { + "name": "lon", + "in": "query", + "description": "Longitude in decimal degree format", + "schema": { + "type": "number", + "format": "float", + "nullable": true + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "required": true, + "schema": { + "type": "string", + "default": "true" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "required": [ + "ocs" + ], + "type": "object", + "properties": { + "ocs": { + "required": [ + "meta", + "data" + ], + "type": "object", + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "required": [ + "success", + "lat", + "lon", + "address" + ], + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "lat": { + "type": "number", + "format": "float", + "nullable": true + }, + "lon": { + "type": "number", + "format": "float", + "nullable": true + }, + "address": { + "type": "string", + "nullable": true + } + } + } + } + } + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ] + } + }, + "/ocs/v2.php/apps/weather_status/api/v1/forecast": { + "get": { + "tags": [ + "weather_status" + ], + "summary": "Get forecast for current location", + "operationId": "weather_status-get-forecast", + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "required": true, + "schema": { + "type": "string", + "default": "true" + } + } + ], + "responses": { + "200": { + "description": "Forecast returned", + "content": { + "application/json": { + "schema": { + "required": [ + "ocs" + ], + "type": "object", + "properties": { + "ocs": { + "required": [ + "meta", + "data" + ], + "type": "object", + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Forecast" + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Forecast not found", + "content": { + "application/json": { + "schema": { + "required": [ + "ocs" + ], + "type": "object", + "properties": { + "ocs": { + "required": [ + "meta", + "data" + ], + "type": "object", + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "required": [ + "success" + ], + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ] + } + }, + "/ocs/v2.php/apps/weather_status/api/v1/favorites": { + "get": { + "tags": [ + "weather_status" + ], + "summary": "Get favorites list", + "operationId": "weather_status-get-favorites", + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "required": true, + "schema": { + "type": "string", + "default": "true" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "required": [ + "ocs" + ], + "type": "object", + "properties": { + "ocs": { + "required": [ + "meta", + "data" + ], + "type": "object", + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ] + }, + "put": { + "tags": [ + "weather_status" + ], + "summary": "Set favorites list", + "operationId": "weather_status-set-favorites", + "parameters": [ + { + "name": "favorites", + "in": "query", + "description": "Favorite addresses", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "required": true, + "schema": { + "type": "string", + "default": "true" + } + } + ], + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "required": [ + "ocs" + ], + "type": "object", + "properties": { + "ocs": { + "required": [ + "meta", + "data" + ], + "type": "object", + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "required": [ + "success" + ], + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + } + }, + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ] + } + } + }, + "components": { + "schemas": { + "Capabilities": { + "required": [ + "weather_status" + ], + "type": "object", + "properties": { + "weather_status": { + "required": [ + "enabled" + ], + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + } + } + } + }, + "Forecast": { + "required": [ + "time", + "data" + ], + "type": "object", + "properties": { + "time": { + "type": "string" + }, + "data": { + "required": [ + "instant", + "next_12_hours", + "next_1_hours", + "next_6_hours" + ], + "type": "object", + "properties": { + "instant": { + "required": [ + "details" + ], + "type": "object", + "properties": { + "details": { + "required": [ + "air_pressure_at_sea_level", + "air_temperature", + "cloud_area_fraction", + "cloud_area_fraction_high", + "cloud_area_fraction_low", + "cloud_area_fraction_medium", + "dew_point_temperature", + "fog_area_fraction", + "relative_humidity", + "ultraviolet_index_clear_sky", + "wind_from_direction", + "wind_speed", + "wind_speed_of_gust" + ], + "type": "object", + "properties": { + "air_pressure_at_sea_level": { + "type": "number", + "format": "float" + }, + "air_temperature": { + "type": "number", + "format": "float" + }, + "cloud_area_fraction": { + "type": "number", + "format": "float" + }, + "cloud_area_fraction_high": { + "type": "number", + "format": "float" + }, + "cloud_area_fraction_low": { + "type": "number", + "format": "float" + }, + "cloud_area_fraction_medium": { + "type": "number", + "format": "float" + }, + "dew_point_temperature": { + "type": "number", + "format": "float" + }, + "fog_area_fraction": { + "type": "number", + "format": "float" + }, + "relative_humidity": { + "type": "number", + "format": "float" + }, + "ultraviolet_index_clear_sky": { + "type": "number", + "format": "float" + }, + "wind_from_direction": { + "type": "number", + "format": "float" + }, + "wind_speed": { + "type": "number", + "format": "float" + }, + "wind_speed_of_gust": { + "type": "number", + "format": "float" + } + } + } + } + }, + "next_12_hours": { + "required": [ + "summary", + "details" + ], + "type": "object", + "properties": { + "summary": { + "required": [ + "symbol_code" + ], + "type": "object", + "properties": { + "symbol_code": { + "type": "string" + } + } + }, + "details": { + "required": [ + "probability_of_precipitation" + ], + "type": "object", + "properties": { + "probability_of_precipitation": { + "type": "number", + "format": "float" + } + } + } + } + }, + "next_1_hours": { + "required": [ + "summary", + "details" + ], + "type": "object", + "properties": { + "summary": { + "required": [ + "symbol_code" + ], + "type": "object", + "properties": { + "symbol_code": { + "type": "string" + } + } + }, + "details": { + "required": [ + "precipitation_amount", + "precipitation_amount_max", + "precipitation_amount_min", + "probability_of_precipitation", + "probability_of_thunder" + ], + "type": "object", + "properties": { + "precipitation_amount": { + "type": "number", + "format": "float" + }, + "precipitation_amount_max": { + "type": "number", + "format": "float" + }, + "precipitation_amount_min": { + "type": "number", + "format": "float" + }, + "probability_of_precipitation": { + "type": "number", + "format": "float" + }, + "probability_of_thunder": { + "type": "number", + "format": "float" + } + } + } + } + }, + "next_6_hours": { + "required": [ + "summary", + "details" + ], + "type": "object", + "properties": { + "summary": { + "required": [ + "symbol_code" + ], + "type": "object", + "properties": { + "symbol_code": { + "type": "string" + } + } + }, + "details": { + "required": [ + "air_temperature_max", + "air_temperature_min", + "precipitation_amount", + "precipitation_amount_max", + "precipitation_amount_min", + "probability_of_precipitation" + ], + "type": "object", + "properties": { + "air_temperature_max": { + "type": "number", + "format": "float" + }, + "air_temperature_min": { + "type": "number", + "format": "float" + }, + "precipitation_amount": { + "type": "number", + "format": "float" + }, + "precipitation_amount_max": { + "type": "number", + "format": "float" + }, + "precipitation_amount_min": { + "type": "number", + "format": "float" + }, + "probability_of_precipitation": { + "type": "number", + "format": "float" + } + } + } + } + } + } + } + } + }, + "OCSMeta": { + "type": "object", + "required": [ + "status", + "statuscode" + ], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + } + }, + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + } + }, + "tags": [] +} \ No newline at end of file