From 9834529005db898eec2dac2be11a1cca87cd2cdf Mon Sep 17 00:00:00 2001 From: Petra Mirelli <80395360+iNtEgraIR2021@users.noreply.github.com> Date: Sun, 10 Mar 2024 16:28:24 +0000 Subject: Chore(docs): enhance readability Signed-off-by: Petra Mirelli <80395360+iNtEgraIR2021@users.noreply.github.com> Signed-off-by: Benjamin Brahmer --- docs/admin.md | 13 ++- docs/api/api-v1-2.md | 225 ++++++++++++++++++++++++++++--------------- docs/api/api-v1-3.md | 223 ++++++++++++++++++++++++++++-------------- docs/api/api-v2.md | 81 +++++++++++----- docs/developer.md | 12 ++- docs/features/customCSS.md | 7 +- docs/features/integration.md | 22 ++--- docs/features/plugins.md | 51 +++++----- docs/features/themes.md | 3 +- docs/troubleshooting.md | 39 ++++---- 10 files changed, 441 insertions(+), 235 deletions(-) diff --git a/docs/admin.md b/docs/admin.md index b645219e5..8a180fbb0 100644 --- a/docs/admin.md +++ b/docs/admin.md @@ -1,10 +1,14 @@ # Admin + Welcome to the Admin documentation this page explains some of the configuration options for news. + ## System Cron + Nextcloud uses cron to run regular jobs, News relies on the Job system to execute the feed updates. Alternatively you may use an [external updater](https://nextcloud.github.io/news/clients/#update-clients), in this case you need to disable the system cron in the settings. ## Auto purge count + - The default value is 200. - To disable this feature, use -1. - Unread and starred items are not deleted. @@ -18,29 +22,34 @@ In this case the limit will be 210 instead of 200, for that feed. This is needed to prevent items from reappearing in the feed. ## Purge unread items + This changes the behavior of the auto purging to also purge unread items. This is useful if you have users with a lot of unread items. **Starred items are always kept.** ## Explore Service + If you are using the News app in your company/community, it might be interesting to offer your users a bunch of easily to discover default feeds. You could also create a website where people can add and up-vote news feeds like bigger cloud feed readers like Feedly do it or even convert their APIs into a service for the News app (if someone wants to provide one for the News app, feel free to contact us by creating an issue in the bug tracker). The URL should be a path to a directory which contains a JSON file in the format of **feeds.LANG_CODE.json** where LANG_CODE is a two character language code (e.g. **en** or **de**). -For example, entering the URL **https://domain.com/directory** as explore URL will produce the following request for German users: +For example, entering the URL **** as explore URL will produce the following request for German users: GET https://domain.com/directory/feeds.de.json **Do not forget to implement [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) in your API, otherwise the request will fail!** ## Update Interval + The update interval is used to determine when the next update of all feeds should be done. By default, the value is set to 3600 seconds (1 hour) You can configure this interval as an administrator. The new value is only applied after the next run of the updater. ### What is a good update interval? + That depends on your individual needs. Please keep in mind that the lower you set your update interval, the more traffic is generated. ### Can I set individual update intervals per feed/user? -No, that is not possible. \ No newline at end of file + +No, that is not possible. diff --git a/docs/api/api-v1-2.md b/docs/api/api-v1-2.md index 3d8b22426..e70eb9b73 100644 --- a/docs/api/api-v1-2.md +++ b/docs/api/api-v1-2.md @@ -23,6 +23,7 @@ You have to design your app with these things in mind!: * **Use a library to compare versions, ideally one that uses semantic versioning** ## Authentication & Basics + Because REST is stateless you have to send user and password each time you access the API. Therefore running Nextcloud **with SSL is highly recommended** otherwise **everyone in your network can log your credentials**. The base URL for all calls is: @@ -42,11 +43,13 @@ where $CREDENTIALS is: base64(USER:PASSWORD) ## How To Sync + This is a small overview over how you should sync your articles with the Nextcloud News app. For more fine-grained details about the API see further down. -All routes are given relative to the base API url (e.g.: https://yournextcloud.com/index.php/apps/news/api/v1-2) +All routes are given relative to the base API url (e.g.: ) ### Initial Sync + The intial sync happens, when a user adds a Nextcloud account in your app. In that case you should fetch all feeds, folders and unread or starred articles from the News app. Do not fetch all articles, not only because it syncs faster, but also because the user is primarily interested in unread articles. To fetch all unread and starred articles, you must call 4 routes: * **unread articles**: GET /items?type=3&getRead=false&batchSize=-1 @@ -57,6 +60,7 @@ The intial sync happens, when a user adds a Nextcloud account in your app. In th The JSON response structures can be viewed further down. ### Syncing + When syncing, you want to push read/unread and starred/unstarred items to the server and receive new and updated items, feeds and folders. To do that, call the following routes: * **Notify the News app of unread articles**: PUT /items/unread/multiple {"items": [1, 3, 5] } @@ -67,31 +71,32 @@ When syncing, you want to push read/unread and starred/unstarred items to the se * **Get new feeds**: GET /feeds * **Get new items and modified items**: GET /items/updated?lastModified=12123123123&type=3 - ## Accessing API from a web application **News 1.401** implements CORS which allows web applications to access the API. **To access the API in a webapp you need to send the correct authorization header instead of simply putting auth data into the URL!**. An example request in jQuery would look like this: ```js $.ajax({ - type: 'GET', - url: 'https://yournextcloud.com/index.php/apps/news/api/v1-2/version', - contentType: 'application/json', - success: function (response) { - // handle success - }, - error: function () { - // handle errors - }, - beforeSend: function (xhr) { - var username = 'john'; - var password = 'doe'; - var auth = btoa(username + ':' + password); - xhr.setRequestHeader('Authorization', 'Basic ' + auth); - } + type: 'GET', + url: 'https://yournextcloud.com/index.php/apps/news/api/v1-2/version', + contentType: 'application/json', + success: function (response) { + // handle success + }, + error: function () { + // handle errors + }, + beforeSend: function (xhr) { + var username = 'john'; + var password = 'doe'; + var auth = btoa(username + ':' + password); + xhr.setRequestHeader('Authorization', 'Basic ' + auth); + } }); ``` + An example with AngularJS would look like this: + ```js angular.module('YourApp', []) .config(['$httpProvider', '$provide', function ($httpProvider, $provide) { @@ -129,14 +134,17 @@ angular.module('YourApp', []) ``` ## Input + In general the input parameters can be in the URL or request body, the App Framework doesnt differentiate between them. So JSON in the request body like: -```jsonc + +```json { "id": 3 } ``` + will be treated the same as /?id=3 @@ -149,11 +157,13 @@ It is recommended though that you use the following convention: * **DELETE**: parameters as JSON in the request body ## Output + The output is JSON. ## API Endpoints ### Folders + #### Get all folders * **Status**: Implemented @@ -161,7 +171,8 @@ The output is JSON. * **Route**: /folders * **Parameters**: none * **Returns**: -```jsonc + +```json { "folders": [ { @@ -173,22 +184,26 @@ The output is JSON. ``` #### Create a folder + Creates a new folder and returns a new folder object * **Status**: Implemented * **Method**: POST * **Route**: /folders * **Parameters**: -```jsonc + +```json { "name": "folder name" } ``` + * **Return codes**: - * **HTTP 409**: If the folder exists already - * **HTTP 422**: If the folder name is invalid (for instance empty) +* **HTTP 409**: If the folder exists already +* **HTTP 422**: If the folder name is invalid (for instance empty) * **Returns**: -```jsonc + +```json { "folders": [ { @@ -200,6 +215,7 @@ Creates a new folder and returns a new folder object ``` #### Delete a folder + Deletes a folder with the id folderId and all the feeds it contains * **Status**: Implemented @@ -207,25 +223,28 @@ Deletes a folder with the id folderId and all the feeds it contains * **Route**: /folders/{folderId} * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the folder does not exist +* **HTTP 404**: If the folder does not exist * **Returns**: nothing #### Rename a folder + Only the name can be updated * **Status**: Implemented * **Method**: PUT * **Route**: /folders/{folderId} * **Parameters**: -```jsonc + +```json { "name": "folder name" } ``` + * **Return codes**: - * **HTTP 409**: If the folder name does already exist - * **HTTP 404**: If the folder does not exist - * **HTTP 422**: If the folder name is invalid (for instance empty) +* **HTTP 409**: If the folder name does already exist +* **HTTP 404**: If the folder does not exist +* **HTTP 422**: If the folder name is invalid (for instance empty) * **Returns**: nothing #### Mark items of a folder as read @@ -234,15 +253,17 @@ Only the name can be updated * **Method**: PUT * **Route**: /folders/{folderId}/read * **Parameters**: -```jsonc + +```json { // mark all items read lower than equal that id // this is mean to prevent marking items as read which the client/user does not yet know of "newestItemId": 10 } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing ### Feeds @@ -261,7 +282,8 @@ The following attributes are **not sanitized** meaning: including them in your w * **Route**: /feeds * **Parameters**: none * **Returns**: -```jsonc + +```json { "feeds": [ { @@ -290,23 +312,27 @@ The following attributes are **not sanitized** meaning: including them in your w ``` #### Create a feed + Creates a new feed and returns the feed * **Status**: Implemented * **Method**: POST * **Route**: /feeds * **Parameters**: -```jsonc + +```json { "url": "http:\/\/www.cyanogenmod.org\/wp-content\/themes\/cyanogenmod\/images\/favicon.ico", "folderId": 81 // id of the parent folder, null for root } ``` + * **Return codes**: - * **HTTP 409**: If the feed exists already - * **HTTP 422**: If the feed cant be read (most likely contains errors) +* **HTTP 409**: If the feed exists already +* **HTTP 422**: If the feed cant be read (most likely contains errors) * **Returns**: -```jsonc + +```json { "feeds": [ { @@ -327,6 +353,7 @@ Creates a new feed and returns the feed ``` #### Delete a feed + Deletes a feed with the id feedId and all of its items * **Status**: Implemented @@ -334,7 +361,7 @@ Deletes a feed with the id feedId and all of its items * **Route**: /feeds/{feedId} * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing #### Move a feed to a different folder @@ -343,13 +370,15 @@ Deletes a feed with the id feedId and all of its items * **Method**: PUT * **Route**: /feeds/{feedId}/move * **Parameters**: -```jsonc + +```json { "folderId": null // id of the parent folder, null for root } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing #### Rename a feed @@ -358,13 +387,15 @@ Deletes a feed with the id feedId and all of its items * **Method**: PUT * **Route**: /feeds/{feedId}/rename * **Parameters**: -```jsonc + +```json { "feedTitle": "New Title" } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing #### Mark items of a feed as read @@ -373,18 +404,19 @@ Deletes a feed with the id feedId and all of its items * **Method**: PUT * **Route**: /feeds/{feedId}/read * **Parameters**: -```jsonc + +```json { // mark all items read lower than equal that id // this is mean to prevent marking items as read which the client/user does not yet know of "newestItemId": 10 } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing - ### Items #### Sanitation @@ -400,6 +432,7 @@ The following attributes are **not sanitized** meaning: including them in your w * **mediaDescription** #### Types + | Name | Default | Types | |------------------|---------|--------------| | author | null | string\|null | @@ -422,13 +455,15 @@ The following attributes are **not sanitized** meaning: including them in your w | unread | false | bool | | updatedDate | | string\|null | | url | | string\|null | - + #### Get items + * **Status**: Implemented * **Method**: GET * **Route**: /items * **Parameters**: -```jsonc + +```json { "batchSize": 10, // the number of items that should be returned, defaults to -1, new in 5.2.3: -1 returns all items "offset": 30, // only return older (lower than equal that id) items than the one with id 30 @@ -438,8 +473,10 @@ The following attributes are **not sanitized** meaning: including them in your w "oldestFirst": false // implemented in 3.002, if true it reverse the sort order } ``` + * **Returns**: -```jsonc + +```json { "items": [ { @@ -467,12 +504,14 @@ The following attributes are **not sanitized** meaning: including them in your w ``` ##### Example + Autopaging would work like this: * Get the **first 20** items from a feed with **id 12** **GET /items**: -```jsonc + +```json { "batchSize": 20, "offset": 0, @@ -486,7 +525,7 @@ The item with the lowest item id is 43. * Get the next **20** items: **GET /items**: -```jsonc +```json { "batchSize": 20, "offset": 43, @@ -496,15 +535,16 @@ The item with the lowest item id is 43. } ``` - #### Get updated items + This is used to stay up to date. * **Status**: Implemented * **Method**: GET * **Route**: /items/updated * **Parameters**: -```jsonc + +```json { "lastModified": 123231, // returns only items with a lastModified timestamp >= than this one // this may also return already existing items whose read or starred status @@ -513,8 +553,10 @@ This is used to stay up to date. "id": 12 // the id of the folder or feed, Use 0 for Starred and All } ``` + * **Returns**: -```jsonc + +```json { "items": [ { @@ -539,62 +581,73 @@ This is used to stay up to date. ``` #### Mark an item as read + * **Status**: Implemented * **Method**: PUT * **Route**: /items/{itemId}/read * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the item does not exist +* **HTTP 404**: If the item does not exist * **Returns**: nothing #### Mark multiple items as read + * **Status**: Implemented in 1.2 * **Method**: PUT * **Route**: /items/read/multiple * **Parameters**: -```jsonc + +```json { "items": [2, 3] // ids of the items } ``` + * **Returns**: nothing #### Mark an item as unread + * **Status**: Implemented * **Method**: PUT * **Route**: /items/{itemId}/unread * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the item does not exist +* **HTTP 404**: If the item does not exist * **Returns**: nothing #### Mark multiple items as unread + * **Status**: Implemented in 1.2 * **Method**: PUT * **Route**: /items/unread/multiple * **Parameters**: -```jsonc + +```json { "items": [2, 3] // ids of the items } ``` + * **Returns**: nothing #### Mark an item as starred + * **Status**: Implemented * **Method**: PUT * **Route**: /items/{feedId}/{guidHash}/star * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the item does not exist +* **HTTP 404**: If the item does not exist * **Returns**: nothing #### Mark multiple items as starred + * **Status**: Implemented in 1.2 * **Method**: PUT * **Route**: /items/star/multiple * **Parameters**: -```jsonc + +```json { "items": [ { @@ -604,23 +657,27 @@ This is used to stay up to date. ] } ``` + * **Returns**: nothing #### Mark an item as unstarred + * **Status**: Implemented * **Method**: PUT * **Route**: /items/{feedId}/{guidHash}/unstar * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the item does not exist +* **HTTP 404**: If the item does not exist * **Returns**: nothing #### Mark multiple items as unstarred + * **Status**: Implemented in 1.2 * **Method**: PUT * **Route**: /items/unstar/multiple * **Parameters**: -```jsonc + +```json { "items": [ { @@ -630,6 +687,7 @@ This is used to stay up to date. ] } ``` + * **Returns**: nothing #### Mark all items as read @@ -638,18 +696,19 @@ This is used to stay up to date. * **Method**: PUT * **Route**: /items/read * **Parameters**: -```jsonc + +```json { // mark all items read lower than equal that id // this is mean to prevent marking items as read which the client/user does not yet know of "newestItemId": 10 } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing - ### Updater To enable people to write their own update scripts instead of relying on the sequential built in web and system cron, API routes and console commands have been created. @@ -664,6 +723,7 @@ Updating should be done in the following fashion: This [implementation in Python](https://github.com/nextcloud/news-updater) should give you a good idea how to design and run it. #### Trigger cleanup before update + This is used to clean up the database. It deletes folders and feeds that are marked for deletion * **Status**: Implemented in 1.601 @@ -674,7 +734,9 @@ This is used to clean up the database. It deletes folders and feeds that are mar **New in 8.1.0**: The console command for achieving the same result is: - php -f nextcloud/occ news:updater:before-update +```bash +php -f nextcloud/occ news:updater:before-update +``` #### Get feed ids and usernames for all feeds @@ -684,7 +746,8 @@ This is used to clean up the database. It deletes folders and feeds that are mar * **Route**: /feeds/all * **Parameters**: none * **Returns**: -```jsonc + +```json { "feeds": [ { @@ -697,8 +760,9 @@ This is used to clean up the database. It deletes folders and feeds that are mar **New in 8.1.0, Removed in 16.0.0**: The console command for achieving the same result is: - php -f nextcloud/occ news:updater:all-feeds - +```bash +php -f nextcloud/occ news:updater:all-feeds +``` #### Trigger a feed update @@ -707,21 +771,26 @@ This is used to clean up the database. It deletes folders and feeds that are mar * **Method**: GET * **Route**: /feeds/update * **Parameters**: -```jsonc + +```json { "userId": "john", "feedId": 3 } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: Nothing **New in 8.1.0**: The console command for achieving the same result is: - php -f nextcloud/occ news:updater:update-feed 3 john +```bash +php -f nextcloud/occ news:updater:update-feed 3 john +``` #### Trigger cleanup after update + This is used to clean up the database. It removes old read articles which are not starred * **Status**: Implemented in 1.601 @@ -732,7 +801,9 @@ This is used to clean up the database. It removes old read articles which are no **New in 8.1.0**: The console command for achieving the same result is: - php -f nextcloud/occ news:updater:after-update +```bash +php -f nextcloud/occ news:updater:after-update +``` ### Version @@ -743,7 +814,8 @@ This is used to clean up the database. It removes old read articles which are no * **Route**: /version * **Parameters**: none * **Returns**: -```jsonc + +```json { "version": "5.2.3" } @@ -760,7 +832,8 @@ This API can be used to display warnings and errors in your client if the web ap * **Route**: /status * **Parameters**: none * **Returns**: -```jsonc + +```json { "version": "5.2.4", "warnings": { @@ -786,8 +859,9 @@ If **incorrectDbCharset** is true you should display a warning that database cha This API can be used to retrieve metadata about the current user. DEPRECATED: This API is deprecated, use the Nextcloud APIs instead. -- https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-api-overview.html#user-metadata for user data -- `https://nc.url/avatar/{userid}/{size}?v={1|2}` for the avatar + +* for user data +* `https://nc.url/avatar/{userid}/{size}?v={1|2}` for the avatar #### Get the status @@ -796,7 +870,8 @@ DEPRECATED: This API is deprecated, use the Nextcloud APIs instead. * **Route**: /user * **Parameters**: none * **Returns**: -```jsonc + +```json { "userId": "john", "displayName": "John Doe", diff --git a/docs/api/api-v1-3.md b/docs/api/api-v1-3.md index 7464efb09..e0c28906d 100644 --- a/docs/api/api-v1-3.md +++ b/docs/api/api-v1-3.md @@ -23,6 +23,7 @@ You have to design your app with these things in mind!: * **Use a library to compare versions, ideally one that uses semantic versioning** ## Authentication & Basics + Because REST is stateless you have to send user and password each time you access the API. Therefore running Nextcloud **with SSL is highly recommended** otherwise **everyone in your network can log your credentials**. The base URL for all calls is: @@ -42,11 +43,13 @@ where $CREDENTIALS is: base64(USER:PASSWORD) ## How To Sync + This is a small overview over how you should sync your articles with the Nextcloud News app. For more fine-grained details about the API see further down. -All routes are given relative to the base API url (e.g.: https://yournextcloud.com/index.php/apps/news/api/v1-3) +All routes are given relative to the base API url (e.g.: ) ### Initial Sync + The intial sync happens, when a user adds a Nextcloud account in your app. In that case you should fetch all feeds, folders and unread or starred articles from the News app. Do not fetch all articles, not only because it syncs faster, but also because the user is primarily interested in unread articles. To fetch all unread and starred articles, you must call 4 routes: * **unread articles**: GET /items?type=3&getRead=false&batchSize=-1 @@ -57,6 +60,7 @@ The intial sync happens, when a user adds a Nextcloud account in your app. In th The JSON response structures can be viewed further down. ### Syncing + When syncing, you want to push read/unread and starred/unstarred items to the server and receive new and updated items, feeds and folders. To do that, call the following routes: * **Notify the News app of unread articles**: PUT /items/unread/multiple {"items": [1, 3, 5]} @@ -67,31 +71,32 @@ When syncing, you want to push read/unread and starred/unstarred items to the se * **Get new feeds**: GET /feeds * **Get new items and modified items**: GET /items/updated?lastModified=12123123123&type=3 - ## Accessing API from a web application **News 1.401** implements CORS which allows web applications to access the API. **To access the API in a webapp you need to send the correct authorization header instead of simply putting auth data into the URL!**. An example request in jQuery would look like this: ```js $.ajax({ - type: 'GET', - url: 'https://yournextcloud.com/index.php/apps/news/api/v1-3/version', - contentType: 'application/json', - success: function (response) { - // handle success - }, - error: function () { - // handle errors - }, - beforeSend: function (xhr) { - var username = 'john'; - var password = 'doe'; - var auth = btoa(username + ':' + password); - xhr.setRequestHeader('Authorization', 'Basic ' + auth); - } + type: 'GET', + url: 'https://yournextcloud.com/index.php/apps/news/api/v1-3/version', + contentType: 'application/json', + success: function (response) { + // handle success + }, + error: function () { + // handle errors + }, + beforeSend: function (xhr) { + var username = 'john'; + var password = 'doe'; + var auth = btoa(username + ':' + password); + xhr.setRequestHeader('Authorization', 'Basic ' + auth); + } }); ``` + An example with AngularJS would look like this: + ```js angular.module('YourApp', []) .config(['$httpProvider', '$provide', function ($httpProvider, $provide) { @@ -129,14 +134,17 @@ angular.module('YourApp', []) ``` ## Input + In general the input parameters can be in the URL or request body, the App Framework doesnt differentiate between them. So JSON in the request body like: -```jsonc + +```json { "id": 3 } ``` + will be treated the same as /?id=3 @@ -149,11 +157,13 @@ It is recommended though that you use the following convention: * **DELETE**: parameters as JSON in the request body ## Output + The output is JSON. ## API Endpoints ### Folders + #### Get all folders * **Status**: Implemented @@ -161,7 +171,8 @@ The output is JSON. * **Route**: /folders * **Parameters**: none * **Returns**: -```jsonc + +```json { "folders": [ { @@ -173,22 +184,26 @@ The output is JSON. ``` #### Create a folder + Creates a new folder and returns a new folder object * **Status**: Implemented * **Method**: POST * **Route**: /folders * **Parameters**: -```jsonc + +```json { "name": "folder name" } ``` + * **Return codes**: - * **HTTP 409**: If the folder exists already - * **HTTP 422**: If the folder name is invalid (for instance empty) +* **HTTP 409**: If the folder exists already +* **HTTP 422**: If the folder name is invalid (for instance empty) * **Returns**: -```jsonc + +```json { "folders": [ { @@ -200,6 +215,7 @@ Creates a new folder and returns a new folder object ``` #### Delete a folder + Deletes a folder with the id folderId and all the feeds it contains * **Status**: Implemented @@ -207,25 +223,28 @@ Deletes a folder with the id folderId and all the feeds it contains * **Route**: /folders/{folderId} * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the folder does not exist +* **HTTP 404**: If the folder does not exist * **Returns**: nothing #### Rename a folder + Only the name can be updated * **Status**: Implemented * **Method**: PUT * **Route**: /folders/{folderId} * **Parameters**: -```jsonc + +```json { "name": "folder name" } ``` + * **Return codes**: - * **HTTP 409**: If the folder name does already exist - * **HTTP 404**: If the folder does not exist - * **HTTP 422**: If the folder name is invalid (for instance empty) +* **HTTP 409**: If the folder name does already exist +* **HTTP 404**: If the folder does not exist +* **HTTP 422**: If the folder name is invalid (for instance empty) * **Returns**: nothing #### Mark items of a folder as read @@ -234,15 +253,17 @@ Only the name can be updated * **Method**: POST * **Route**: /folders/{folderId}/read * **Parameters**: -```jsonc + +```json { // mark all items read lower than equal that id // this is mean to prevent marking items as read which the client/user does not yet know of "newestItemId": 10 } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing ### Feeds @@ -261,7 +282,8 @@ The following attributes are **not sanitized** meaning: including them in your w * **Route**: /feeds * **Parameters**: none * **Returns**: -```jsonc + +```json { "feeds": [ { @@ -290,23 +312,27 @@ The following attributes are **not sanitized** meaning: including them in your w ``` #### Create a feed + Creates a new feed and returns the feed * **Status**: Implemented * **Method**: POST * **Route**: /feeds * **Parameters**: -```jsonc + +```json { "url": "http:\/\/www.cyanogenmod.org\/wp-content\/themes\/cyanogenmod\/images\/favicon.ico", "folderId": 81 // id of the parent folder, null for root } ``` + * **Return codes**: - * **HTTP 409**: If the feed exists already - * **HTTP 422**: If the feed cant be read (most likely contains errors) +* **HTTP 409**: If the feed exists already +* **HTTP 422**: If the feed cant be read (most likely contains errors) * **Returns**: -```jsonc + +```json { "feeds": [ { @@ -327,6 +353,7 @@ Creates a new feed and returns the feed ``` #### Delete a feed + Deletes a feed with the id feedId and all of its items * **Status**: Implemented @@ -334,7 +361,7 @@ Deletes a feed with the id feedId and all of its items * **Route**: /feeds/{feedId} * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing #### Move a feed to a different folder @@ -343,13 +370,15 @@ Deletes a feed with the id feedId and all of its items * **Method**: POST * **Route**: /feeds/{feedId}/move * **Parameters**: -```jsonc + +```json { "folderId": null // id of the parent folder, null for root } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing #### Rename a feed @@ -358,13 +387,15 @@ Deletes a feed with the id feedId and all of its items * **Method**: POST * **Route**: /feeds/{feedId}/rename * **Parameters**: -```jsonc + +```json { "feedTitle": "New Title" } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing #### Mark items of a feed as read @@ -373,18 +404,19 @@ Deletes a feed with the id feedId and all of its items * **Method**: POST * **Route**: /feeds/{feedId}/read * **Parameters**: -```jsonc + +```json { // mark all items read lower than equal that id // this is mean to prevent marking items as read which the client/user does not yet know of "newestItemId": 10 } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing - ### Items #### Sanitation @@ -400,6 +432,7 @@ The following attributes are **not sanitized** meaning: including them in your w * **mediaDescription** #### Types + | Name | Default | Types | |------------------|---------|--------------| | author | null | string\|null | @@ -424,11 +457,13 @@ The following attributes are **not sanitized** meaning: including them in your w | url | | string\|null | #### Get items + * **Status**: Implemented * **Method**: GET * **Route**: /items * **Parameters**: -```jsonc + +```json { "batchSize": 10, // the number of items that should be returned, defaults to -1, new in 5.2.3: -1 returns all items "offset": 30, // only return older (lower than equal that id) items than the one with id 30 @@ -438,8 +473,10 @@ The following attributes are **not sanitized** meaning: including them in your w "oldestFirst": false // implemented in 3.002, if true it reverse the sort order } ``` + * **Returns**: -```jsonc + +```json { "items": [ { @@ -467,12 +504,14 @@ The following attributes are **not sanitized** meaning: including them in your w ``` ##### Example + Autopaging would work like this: * Get the **first 20** items from a feed with **id 12** **GET /items**: -```jsonc + +```json { "batchSize": 20, "offset": 0, @@ -486,7 +525,7 @@ The item with the lowest item id is 43. * Get the next **20** items: **GET /items**: -```jsonc +```json { "batchSize": 20, "offset": 43, @@ -496,15 +535,16 @@ The item with the lowest item id is 43. } ``` - #### Get updated items + This is used to stay up to date. * **Status**: Implemented * **Method**: GET * **Route**: /items/updated * **Parameters**: -```jsonc + +```json { "lastModified": 123231, // returns only items with a lastModified timestamp >= than this one // this may also return already existing items whose read or starred status @@ -513,8 +553,10 @@ This is used to stay up to date. "id": 12 // the id of the folder or feed, Use 0 for Starred and All } ``` + * **Returns**: -```jsonc + +```json { "items": [ { @@ -539,87 +581,103 @@ This is used to stay up to date. ``` #### Mark an item as read + * **Status**: Implemented * **Method**: POST * **Route**: /items/{itemId}/read * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the item does not exist +* **HTTP 404**: If the item does not exist * **Returns**: nothing #### Mark multiple items as read + * **Status**: Implemented in API 1.2 * **Method**: POST * **Route**: /items/read/multiple * **Parameters**: -```jsonc + +```json { "itemIds": [2, 3] // ids of the items } ``` + * **Returns**: nothing #### Mark an item as unread + * **Status**: Implemented * **Method**: POST * **Route**: /items/{itemId}/unread * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the item does not exist +* **HTTP 404**: If the item does not exist * **Returns**: nothing #### Mark multiple items as unread + * **Status**: Implemented in API 1.2 * **Method**: POST * **Route**: /items/unread/multiple * **Parameters**: -```jsonc + +```json { "itemIds": [2, 3] // ids of the items } ``` + * **Returns**: nothing #### Mark an item as starred + * **Status**: Implemented in API 1.3 * **Method**: POST * **Route**: /items/{itemId}/star * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the item does not exist +* **HTTP 404**: If the item does not exist * **Returns**: nothing #### Mark multiple items as starred + * **Status**: Implemented in API 1.3 * **Method**: POST * **Route**: /items/star/multiple * **Parameters**: -```jsonc + +```json { "itemIds": [1, ...] } ``` + * **Returns**: nothing #### Mark an item as unstarred + * **Status**: Implemented in API 1.3 * **Method**: POST * **Route**: /items/{itemId}/unstar * **Parameters**: none * **Return codes**: - * **HTTP 404**: If the item does not exist +* **HTTP 404**: If the item does not exist * **Returns**: nothing #### Mark multiple items as unstarred + * **Status**: Implemented in API 1.3 * **Method**: POST * **Route**: /items/unstar/multiple * **Parameters**: -```jsonc + +```json { "itemIds": [1, ...] } ``` + * **Returns**: nothing #### Mark all items as read @@ -628,18 +686,19 @@ This is used to stay up to date. * **Method**: POST * **Route**: /items/read * **Parameters**: -```jsonc + +```json { // mark all items read lower than equal that id // this is mean to prevent marking items as read which the client/user does not yet know of "newestItemId": 10 } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: nothing - ### Updater To enable people to write their own update scripts instead of relying on the sequential built in web and system cron, API routes and console commands have been created. @@ -654,6 +713,7 @@ Updating should be done in the following fashion: This [implementation in Python](https://github.com/nextcloud/news-updater) should give you a good idea how to design and run it. #### Trigger cleanup before update + This is used to clean up the database. It deletes folders and feeds that are marked for deletion * **Status**: Implemented in News 1.601 @@ -664,7 +724,9 @@ This is used to clean up the database. It deletes folders and feeds that are mar **New in 8.1.0**: The console command for achieving the same result is: - php -f nextcloud/occ news:updater:before-update +```bash +php -f nextcloud/occ news:updater:before-update +``` #### Get feed ids and usernames for all feeds @@ -674,7 +736,8 @@ This is used to clean up the database. It deletes folders and feeds that are mar * **Route**: /feeds/all * **Parameters**: none * **Returns**: -```jsonc + +```json { "feeds": [ { @@ -687,8 +750,9 @@ This is used to clean up the database. It deletes folders and feeds that are mar **New in 8.1.0, Removed in 16.0.0**: The console command for achieving the same result is: - php -f nextcloud/occ news:updater:all-feeds - +```bash +php -f nextcloud/occ news:updater:all-feeds +``` #### Trigger a feed update @@ -697,21 +761,26 @@ This is used to clean up the database. It deletes folders and feeds that are mar * **Method**: GET * **Route**: /feeds/update * **Parameters**: -```jsonc + +```json { "userId": "john", "feedId": 3 } ``` + * **Return codes**: - * **HTTP 404**: If the feed does not exist +* **HTTP 404**: If the feed does not exist * **Returns**: Nothing **New in 8.1.0**: The console command for achieving the same result is: - php -f nextcloud/occ news:updater:update-feed 3 john +```bash +php -f nextcloud/occ news:updater:update-feed 3 john +``` #### Trigger cleanup after update + This is used to clean up the database. It removes old read articles which are not starred * **Status**: Implemented in News 1.601 @@ -722,7 +791,9 @@ This is used to clean up the database. It removes old read articles which are no **New in 8.1.0**: The console command for achieving the same result is: - php -f nextcloud/occ news:updater:after-update +```bash +php -f nextcloud/occ news:updater:after-update +``` ### Version @@ -733,7 +804,8 @@ This is used to clean up the database. It removes old read articles which are no * **Route**: /version * **Parameters**: none * **Returns**: -```jsonc + +```json { "version": "5.2.3" } @@ -750,7 +822,8 @@ This API can be used to display warnings and errors in your client if the web ap * **Route**: /status * **Parameters**: none * **Returns**: -```jsonc + +```json { "version": "5.2.4", "warnings": { @@ -776,8 +849,9 @@ If **incorrectDbCharset** is true you should display a warning that database cha This API can be used to retrieve metadata about the current user. DEPRECATED: This API is deprecated, use the Nextcloud APIs instead. -- https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-api-overview.html#user-metadata for user data -- `https://nc.url/avatar/{userid}/{size}?v={1|2}` for the avatar + +* for user data +* `https://nc.url/avatar/{userid}/{size}?v={1|2}` for the avatar #### Get the status @@ -786,7 +860,8 @@ DEPRECATED: This API is deprecated, use the Nextcloud APIs instead. * **Route**: /user * **Parameters**: none * **Returns**: -```jsonc + +```json { "userId": "john", "displayName": "John Doe", diff --git a/docs/api/api-v2.md b/docs/api/api-v2.md index ab6e19517..ecfce9230 100644 --- a/docs/api/api-v2.md +++ b/docs/api/api-v2.md @@ -7,6 +7,7 @@ The **News app** offers a RESTful API which can be used to sync folders, feeds a In addition, an updater API is exposed which enables API users to run feed updates in parallel using a REST API or Nextcloud console API. ## Conventions + This document uses the following conventions: * Object aliases as comments @@ -22,6 +23,7 @@ There are two types of aliases: * Object arrays **Objects**: + ```js { "folder": { /* folder object */ }, @@ -31,6 +33,7 @@ There are two types of aliases: means that the folder attributes will be listed inside the **folder** object **Object arrays**: + ```js { "folders": [ /* array of folder objects */ ], @@ -78,6 +81,7 @@ You have to design your app with these things in mind!: * **Use a library to compare versions**, ideally one that uses semantic versioning ## Request Format + The base URL for all calls is: https://yournextcloud.com/index.php/apps/news/api/v2 @@ -110,9 +114,11 @@ The request body is either passed in the URL in case of a **GET** request (e.g.: **Note**: The current Etag implementation contains a unix timestamp in milliseconds. This is an implementation detail and you should not rely on it. ### API Level Detection + Check the [API level route](#api-level) ### Authentication + Because REST is stateless you have to re-send user and password each time you access the API. Therefore running Nextcloud **with SSL is highly recommended** otherwise **everyone in your network can log your credentials**. Credentials are passed as an HTTP header using [HTTP basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side): @@ -128,6 +134,7 @@ This authentication/authorization method will be the recommended default until c **Note**: Even if login cookies are sent back to your client, they will not be considered for authentication. ## Response Format + The status codes are not always provided by the News app itself, but might also be returned because of Nextcloud internal errors. The following status codes can always be returned by Nextcloud: @@ -167,6 +174,7 @@ The response body is a JSON structure that looks like this, which contains the a In case of an **4xx** or **5xx** error the request was not successful and has to be retried. For instance marking items as read locally and syncing should send the same request again the next time the user syncs in case an error occurred. ## Security Guidelines + Read the following notes carefully to prevent being subject to security exploits: * You should always enforce SSL certificate verification and never offer a way to turn it off. Certificate verification is important to prevent MITM attacks which is especially important in the mobile world where users are almost always connected to untrusted networks. In case a user runs a self-signed certificate on his server ask him to either install his certificate on his device or direct him to one of the many ways to sign his certificate for free (most notably letsencrypt.com) @@ -176,7 +184,8 @@ Read the following notes carefully to prevent being subject to security exploits * If you are building a client in JavaScript or are using a link with **target="blank"**, remember to set the **window.opener** property to **null** and/or add a **rel="noreferrer"** to your link to prevent your app from being [target by an XSS attack](https://medium.com/@jitbit/target-blank-the-most-underestimated-vulnerability-ever-96e328301f4c#.wf2ddytbh) ## Syncing -All routes are given relative to the base API url, e.g.: **/sync** becomes **https://yourNextcloud.com/index.php/apps/news/api/v2/sync** + +All routes are given relative to the base API url, e.g.: **/sync** becomes **** There are two usecases for syncing: @@ -184,6 +193,7 @@ There are two usecases for syncing: * **Syncing local and remote changes**: the user has synced at least once and wants to submit and receive changes ### Initial Sync + The intial sync happens when a user adds an Nextcloud account in your app. In that case you want to download all folders, feeds and unread/starred items. To do this, make the following request: * **Method**: GET @@ -202,6 +212,7 @@ and the following HTTP headers: * **Etag**: A string containing a cache header, maximum size 64 ASCII characters, e.g. 6d82cbb050ddc7fa9cbb659014546e59 and the following request body: + ```js { "folders": [ /* array of folder objects */ ], @@ -216,8 +227,8 @@ and the following request body: * [Feeds](#feeds) * [Items](#items) - ### Sync Local And Remote Changes + After the initial sync the app has all folders, feeds and items. Now you want to push changes and retrieve updates from the server. To do this, make the following request: * **Method**: POST @@ -274,6 +285,7 @@ This also applies to folders and feeds, however the reduced folder and feed obje If you push a list of items to be marked read/starred, there can also be less items in the response than the ones which were initially sent. This means that the item was deleted by the cleanup job and should be removed from the client device. For instance let's take a look at the following example. You are **POST**ing the following JSON: + ```json { "items": [{ @@ -314,7 +326,9 @@ The item with the **id** **7** is missing from the response. This means that it For folders and feeds all ids will be returned so you can compare the existing ids with your locally available feeds and folders and remove the difference. ## Folders + Folders are represented using the following data structure: + ```json { "id": 3, @@ -328,6 +342,7 @@ The attributes mean the following: * **name**: Abitrary long text, folder's name ### Deleting A Folder + To delete a folder, use the following request: * **Method**: DELETE @@ -356,6 +371,7 @@ In case of an HTTP 200, the deleted folder is returned in full in the response, **Note**: If you delete a folder locally, you should also delete all feeds whose **folderId** attribute matches the folder's **id** attribute and also delete all items whose **feedId** attribute matches the feeds' **id** attribute. This is done automatically on the server and will also be missing on the next request. ### Creating A Folder + To create a folder, use the following request: * **Method**: POST @@ -363,6 +379,7 @@ To create a folder, use the following request: * **Authentication**: [required](#authentication) with the following request body: + ```json { "name": "Folder name" @@ -386,6 +403,7 @@ In case of an HTTP 200, the created or already existing folder is returned in fu ``` ### Changing A Folder + The following attributes can be changed on the folder: * **name** @@ -399,6 +417,7 @@ To change any number of attributes on a folder, use the following request and pr * **Authentication**: [required](#authentication) with the following request body: + ```json { "name": "New folder name" @@ -424,8 +443,8 @@ In case of an HTTP 200, the changed or already existing folder is returned in fu } ``` - ## Feeds + Feeds are represented using the following data structure: ```json @@ -464,8 +483,8 @@ The attributes mean the following: * **1**: Error occured during feed update * **message**: Translated error message depending on the user's configured server locale - ### Deleting A Feed + To delete a feed, use the following request: * **Method**: DELETE @@ -474,7 +493,6 @@ To delete a feed, use the following request: * **{id}**: feed's id * **Authentication**: [required](#authentication) - The following response is being returned: Status codes: @@ -483,7 +501,6 @@ Status codes: * **404**: Feed with given id was not found, no error object * Other Nextcloud errors, see [Response Format](#response-format) - In case of an HTTP 200, the deleted feed is returned in full in the response, e.g.: ```js @@ -497,14 +514,15 @@ In case of an HTTP 200, the deleted feed is returned in full in the response, e. **Note**: If you delete a feed locally, you should also delete all items whose **feedId** attribute matches the feeds' **id** attribute. This is done automatically on the server and will also be missing on the next request. ### Creating A feed + To create a feed, use the following request: * **Method**: POST * **Route**: /feeds * **Authentication**: [required](#authentication) - with the following request body: + ```json { "url": "https://feed.url.com", @@ -518,7 +536,7 @@ with the following request body: } ``` -* **url**: Abitrary long text, the url needs to have the full schema e.g. https://the-url.com. In case the user omits the schema, prepending **https** is recommended +* **url**: Abitrary long text, the url needs to have the full schema e.g. . In case the user omits the schema, prepending **https** is recommended * **folderId**: 64bit Integer, the feed's folder or **0** in case no folder is specified * **name (optional)**: Abitrary long text, the feeds name or if not given taken from the RSS/Atom feed * **basicAuthUser (optional)**: Abitrary long text, if given basic auth headers are sent for the feed @@ -527,7 +545,6 @@ with the following request body: * **isPinned (optional)**: See [Feeds](#feeds) * **fullTextEnabled (optional)**: See [Feeds](#feeds) - The following response is being returned: Status codes: @@ -557,6 +574,7 @@ In case of an HTTP 200, the created feed is returned in full in the response, e. **Note**: Because the next sync would also pull in the added feed and items again, the added items will be omitted for saving bandwidth. This also means that after successfully creating a feed you will need to query the [sync route](#sync-local-and-remote-changes) again. ### Changing A Feed + To change a feed, use the following request: * **Method**: PATCH @@ -565,8 +583,8 @@ To change a feed, use the following request: * **{id}**: feed's id * **Authentication**: [required](#authentication) - with the following request body: + ```json { "url": "https://feed.url.com", @@ -586,9 +604,9 @@ All parameters are optional * **name (optional)**: Abitrary long text, the feeds name or if not given taken from the RSS/Atom feed * **basicAuthUser (optional)**: Abitrary long text, if given basic auth headers are sent for the feed * **basicAuthPassword (optional)**: Abitrary long text, if given basic auth headers are sent for the feed -* **ordering (optional)**: See [feeds](#Feeds) -* **isPinned (optional)**: See [feeds](#Feeds) -* **fullTextEnabled (optional)**: See [feeds](#Feeds) +* **ordering (optional)**: See [feeds](#feeds) +* **isPinned (optional)**: See [feeds](#feeds) +* **fullTextEnabled (optional)**: See [feeds](#feeds) * **folderId (optional)**: 64bit Integer, the feed's folder or **0** in case no folder is specified The following response is being returned: @@ -648,7 +666,9 @@ The attributes mean the following: * **contentHash**: 64 ASCII characters, used to determine if the item on the client is up to or out of date. The difference between the contentHash and the fingerprint attribute is that contentHash is always calculated from a stable set of attributes (title, author, url, enclosure, body) whereas the fingerprint is calculated from a set of attributes depending on the feed. The reason for this is that some feeds use different URLs for the same article so you would not want to include the URL as uniqueness criteria in that case. If the fingerprint was used for syncing however, an URL update would never reach the client. ### Full + A full item contains the full content: + ```json { "id": 5, @@ -671,7 +691,9 @@ A full item contains the full content: ``` ### Reduced + A reduced item only contains the item status: + ```json { "id": 5, @@ -681,6 +703,7 @@ A reduced item only contains the item status: ``` ## Updater + Instead of using the built in, slow cron updater you can use the parallel update API to update feeds. The API can be accessed through REST or Nextcloud console API. The API should be used in the following way: @@ -696,11 +719,14 @@ If the REST API is used, Authorization is required via Basic Auth and the user n If the Nextcloud console API is used, no authorization is required. ### Clean Up Before Update + This is used to clean up the database. It deletes folders and feeds that are marked for deletion. **Console API**: - php -f /path/to/nextcloud/occ news:updater:before-update +```bash +php -f /path/to/nextcloud/occ news:updater:before-update +``` **REST API**: @@ -709,11 +735,14 @@ This is used to clean up the database. It deletes folders and feeds that are mar * **Authentication**: [admin](#authentication) ### Get All Feeds And User Ids + This call returns pairs of feed ids and user ids. **Console API**: - php -f /path/to/nextcloud/occ news:updater:all-feeds +```bash +php -f /path/to/nextcloud/occ news:updater:all-feeds +``` **REST API**: @@ -721,7 +750,6 @@ This call returns pairs of feed ids and user ids. * **Route**: /updater/all-feeds * **Authentication**: [admin](#authentication) - Both APIs will return the following response body or terminal output: ```js @@ -734,6 +762,7 @@ Both APIs will return the following response body or terminal output: ``` ### Update A User's Feed + After all feed ids and user ids are known, feeds can be updated in parallel. **Console API**: @@ -742,8 +771,9 @@ After all feed ids and user ids are known, feeds can be updated in parallel. * **{feedId}**: the feed's id * **{userId}**: the user's id - - php -f /path/to/nextcloud/occ news:updater:update-feed {feedId} {userId} +```bash +php -f /path/to/nextcloud/occ news:updater:update-feed {feedId} {userId} +``` **REST API**: @@ -754,13 +784,15 @@ After all feed ids and user ids are known, feeds can be updated in parallel. * **{userId}**: the user's id * **Authentication**: [admin](#authentication) - ### Clean Up After Update + This is used to clean up the database. It removes old read articles which are not starred. **Console API**: - php -f /path/to/nextcloud/occ news:updater:after-update +```bash +php -f /path/to/nextcloud/occ news:updater:after-update +``` **REST API**: @@ -769,13 +801,13 @@ This is used to clean up the database. It removes old read articles which are no * **Authentication**: [admin](#authentication) ## Meta Data + The retrieve meta data about the app, use the following request: * **Method**: GET * **Route**: / * **Authentication**: [required](#authentication) - The following response is being returned: Status codes: @@ -813,12 +845,12 @@ The attributes mean the following: * **data**: Abitrary long text, the user's image encoded as base64 * **mime**: Abitrary long text, avatar mimetype - ## API Level + To find out which API levels are supported, make a request to the following route: * **Method**: GET -* **Route**: https://yournextcloud.com/index.php/apps/news/api +* **Route**: * **Authentication**: none The following response is being returned: @@ -829,6 +861,7 @@ Status codes: * **404**: The user is either running a version prior to **8.8.0** or the News app is disabled or not installed. In case of an HTTP 200, the supported API levels are returned as JSON, e.g.: + ```json { "apiLevels": ["v1-2", "v2"] @@ -840,7 +873,7 @@ In case of an HTTP 200, the supported API levels are returned as JSON, e.g.: To find out if a user is running an older News version than **8.8.0**, make a request to the following route: * **Method**: GET -* **Route**: https://yournextcloud.com/index.php/apps/news/api/v1-2/version +* **Route**: * **Authentication**: [required](#authentication) Status codes: diff --git a/docs/developer.md b/docs/developer.md index 16cae9750..57b966829 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -1,4 +1,5 @@ # Developer + Welcome to the Nextcloud News App developer documentation. News is open for contributions, if you plan to implement a new feature make sure to open a [discussion](https://github.com/nextcloud/news/discussions/new?category=Features). Describe the feature that you are planing and your first idea how to implement it. @@ -7,6 +8,7 @@ This ensures that you don't start working on something which collides with the t For small fixes and improvements feel free to directly create a PR, the maintainers are happy to review your code. ## APIs + News offers an API that can be used by clients to synchronize with the server. There are two API declarations, so far only V1 has been fully implemented. Work on V2 has started with low priority. @@ -16,6 +18,7 @@ Work on V2 has started with low priority. - [API-V2](api/api-v2.md) ## Coding Style Guidelines + The PHP code should all adhere to [PSR-2](https://www.php-fig.org/psr/psr-2/). *Note that this is a different codestyle than Nextcloud itself uses.* To test the codestyle you can run `make phpcs`. @@ -23,6 +26,7 @@ To test the codestyle you can run `make phpcs`. The application Front End uses Vue 2.7 and the Nextcloud Libraries [Vue Components](https://github.com/nextcloud-libraries/nextcloud-vue) for building the Application running inside your Nextcloud instance. For linting these files, we are using eslint, see the [config file](https://github.com/nextcloud/news/blob/master/.eslintrc.js). We also have Unit Tests for the components that run with Jest, please ensure these pass when adding new features/fixing bugs. ## General Developer setup + Check the Nextcloud [documentation](https://docs.nextcloud.com/server/latest/developer_manual/getting_started/devenv.html) to learn how to setup a developer environment, alternatively to a proper web server you can also use the [builtin php server](https://www.php.net/manual/en/features.commandline.webserver.php) on demand, it is enough for development purposes. When your setup is running, clone the news repository in the `apps/` directory inside the server. @@ -32,22 +36,28 @@ Change into the news directory and run `make` to build the app, you will need ph Now you can basically use the news app and test any changes you make on your local development environment. Check out the `appinfo/routes.php` file and `lib/controller/` directory for details on API controllers. Or check out `package.json` for npm scripts and the `src/` directory for the front end Vue Application. ### Frontend Tips/Organization + - We use the Nextcloud Vue component library for most of the form controls and navigation - Vuex is used for state management, this is similar to Redux and has Actions/Mutations and Getters - We are using the Nextcloud Webpack Vue configuration and have enabled Typescript support and importing in the Vue components - We use ESLint and StyleLint for ensuring correct formatting of the Scripts and HTML ## Testing -Please make sure to run all tests before submitting any pull requests. + +Please make sure to run all tests before submitting any pull requests. ### Frontend Unit Tests + Frontend unit tests are written with Jest and can be run with `npm run test`. + ### API and CLI Integration Tests + We use [bats](https://bats-core.readthedocs.io/en/stable/) to run integration tests against the API and the cli. Check how to install bats on your system in the [official documentation](https://bats-core.readthedocs.io/en/stable/installation.html). You also need to pull the submodules of the news repo. + ```bash git submodules update --init ``` diff --git a/docs/features/customCSS.md b/docs/features/customCSS.md index 74f652eaf..264df1a34 100644 --- a/docs/features/customCSS.md +++ b/docs/features/customCSS.md @@ -1,8 +1,9 @@ # Custom CSS + Sometimes you want to add additional CSS for a feed to improve the rendering. This can very easily be done by adding a CSS class to **css/custom.css** following the following naming convention: -* Take the URL from the \ attribute (e.g.: \https://www.google.de/path?my=query \) -* Extract the Domain from the URL (e.g.: www.google.de) +* Take the URL from the \ attribute (e.g.: \ \) +* Extract the Domain from the URL (e.g.: ) * Strip the leading **www.** (e.g.: google.de) * Replace all . with - (e.g.: google-de) * Prepend **custom-** (e.g.: custom-google-de) @@ -13,4 +14,4 @@ Each class rule should be prefixed with **#app-content** and should only affect #app-content .custom-google-de .body { /* Custom CSS rules here */ } -``` \ No newline at end of file +``` diff --git a/docs/features/integration.md b/docs/features/integration.md index a69d3ac13..2e3974e7b 100644 --- a/docs/features/integration.md +++ b/docs/features/integration.md @@ -13,18 +13,18 @@ Ex. #### Chrome / Edge 1. Install [RSS Subscription Extension (by Google)](https://chrome.google.com/webstore/detail/rss-subscription-extensio/nlbjncdgjeocebhnmkbbbdekmmmcbfjd) extension -1. Open the extension's options menu -1. Click `Add..` -1. In the *Description* field, enter a description for the RSS reader entry. 'NextCloud News' is a reasonable name. -1. Enter `https:///index.php/apps/news?subscribe_to=%s` replacing <NEXTCLOUD_BASE_PATH> with the base URL path to your NextCloud instance. - * Domain based example: https://cloud.mydomain.com/index.php/apps/news?subscribe_to=%s - * Domain+subpath based example: https://cloud.mydomain.com/nextcloud/index.php/apps/news?subscribe_to=%s +2. Open the extension's options menu +3. Click `Add..` +4. In the *Description* field, enter a description for the RSS reader entry. 'NextCloud News' is a reasonable name. +5. Enter `https:///index.php/apps/news?subscribe_to=%s` replacing <NEXTCLOUD_BASE_PATH> with the base URL path to your NextCloud instance. + * Domain based example: + * Domain+subpath based example: #### Firefox 1. Install Firefox Add-on Extension [Awesome RSS](https://addons.mozilla.org/en-US/firefox/addon/awesome-rss/) -1. Open the `Preferences` for the extension -2. In the 'Subscribe using' section, select the `NextCloud` radio button -3. In the field link field, enter the base NextCloud URL. - * Domain based example: https://cloud.mydomain.com/ - * Domain+subpath based example: https://cloud.mydomain.com/nextcloud/ \ No newline at end of file +2. Open the `Preferences` for the extension +3. In the 'Subscribe using' section, select the `NextCloud` radio button +4. In the field link field, enter the base NextCloud URL. + * Domain based example: + * Domain+subpath based example: diff --git a/docs/features/plugins.md b/docs/features/plugins.md index ba75d1b60..b02283db0 100644 --- a/docs/features/plugins.md +++ b/docs/features/plugins.md @@ -9,6 +9,7 @@ There are essentially three different use cases for plugins: * Dropping in additional CSS or JavaScript ## The Basics + Whatever plugin you want to create, you first need to create a basic structure. A plugin is basically just an app, so you can take advantage of the full [Nextcloud app API](https://docs.nextcloud.org/server/latest/developer_manual/app/index.html). [Take a look at the developer docs](https://docs.nextcloud.com/server/latest/developer_manual/app_development/index.html) or [dig into the tutorial](https://docs.nextcloud.com/server/latest/developer_manual/app_development/tutorial.html). However, if you just want to start slow, the full process is described below. @@ -18,9 +19,9 @@ First create a skeleton app using the [web interface](https://apps.nextcloud.com The application name affects the name and namespace of your plugin and only one app can exist using the same name. Choose wisely. This will become the directory name in the Nextcloud `apps/` directory * **newsplugin/** - * **appinfo/** - * **app.php** - * **info.xml** + * **appinfo/** + * **app.php** + * **info.xml** **Note**: You must license your app under the [AGPL 3 or later](https://www.gnu.org/licenses/agpl-3.0.en.html) to comply with the News app's license. Don't forget to add the license as plain text file if you want to distribute your app! @@ -37,20 +38,20 @@ use OCP\Util; use OCP\App as Test; class Application extends App { - public const APP_ID = 'newsbookmarkplugin'; + public const APP_ID = 'newsbookmarkplugin'; - public function __construct() { - parent::__construct(self::APP_ID); + public function __construct() { + parent::__construct(self::APP_ID); // your code here - } + } } ``` - ## Server-Side Plugin + A Server-Side plugin is a plugin that uses the same infrastructure as the News app for its own purposes. An example would be a plugin that makes the starred entries of a user available via an interface or a bookmark app that also shows starred articles as bookmarks. It's very easy to interface with the