diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/404.html b/404.html new file mode 100644 index 0000000000..5c7e49a7ff --- /dev/null +++ b/404.html @@ -0,0 +1,707 @@ + + + +
+ + + + + + + + + + + + + + + + + + +Welcome to the Admin documentation.
+News integrates with Nextclouds command line tool occ.
+To get an overview over the available commands simply execute ./occ list news
In most environments you will have to call occ like this:
+ +More information about occ here: Nextcloud Admin Manual
+The following sections explain some of the more complicated settings on the admin page.
+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, in this case you need to disable the system cron in the settings.
+Auto purging automatically removes the oldest read items of every feed after every update. +The value you enter here is used as the limit of read items per feed, unless the feed comes with more items in it's feed. +The individual limit per feed is only adjusted when it's bigger. Let's say last feed update came with 210 items, +then that will be the limit for that feed as long as no bigger update with more items is fetched. +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.
+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.
+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:
+GET https://domain.com/directory/feeds.de.json
+
Do not forget to implement CORS in your API, otherwise the request will fail!
+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.
+Starting with News 25.2.0, the app can dynamically adjust update schedules based on feed activity. This feature, disabled by default, can be enabled by the Nextcloud administrator.
+By analyzing feed data, the app can optimize update frequencies, potentially reducing server load and network traffic. However, this feature may not work correctly with all feeds.
+Users can check the calculated next update time in the app's settings. This information will only be displayed when the dynamic update scheduling feature is enabled.
+ + + + + + + + + + + + + +The News app 1.2 offers a RESTful API
+The API level will change if the following occurs:
+The API level will not change if:
+You have to design your app with these things in mind!:
+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:
+https://yournextcloud.com/index.php/apps/news/api/v1-2/
+
All defined routes in the Specification are appended to this url. To access all feeds for instance use this url:
+https://yournextcloud.com/index.php/apps/news/api/v1-2/feeds
+
Credentials need to be passed as an HTTP header using HTTP basic auth:
+Authorization: Basic $CREDENTIALS
+
where $CREDENTIALS is:
+base64(USER:PASSWORD)
+
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)
+The initial 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:
+The JSON response structures can be viewed further down.
+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:
+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:
+$.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);
+ }
+});
+
An example with AngularJS would look like this:
+angular.module('YourApp', [])
+ .config(['$httpProvider', '$provide', function ($httpProvider, $provide) {
+ $provide.factory('AuthInterceptor', ['Credentials', '$q', function (Credentials, $q) {
+ return {
+ request: function (config) {
+ // only set auth headers if url matches the api url
+ if(config.url.indexOf(Credentials.url) === 0) {
+ auth = btoa(Credentials.userName + ':' + Credentials.password);
+ config.headers['Authorization'] = 'Basic ' + auth;
+ }
+ return config || $q.when(config);
+ }
+ };
+ }]);
+ $httpProvider.interceptors.push('AuthInterceptor');
+ }])
+ .factory('Credentials', function () {
+ return {
+ userName: 'user',
+ password: 'password',
+ url: 'https://yournextcloud.com/index.php/apps/news/api'
+ };
+ })
+ .run(['$http', function($http) {
+ $http({
+ method: 'GET',
+ url: 'https://yournextcloud.com/index.php/apps/news/api/v1-2/version'
+ }).success(function (data, status, header, config) {
+ // handle success
+ }).error(function (data, status, header, config) {
+ // handle error
+ });
+ }]);
+
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:
+ +will be treated the same as
+/?id=3
+
It is recommended though that you use the following convention:
+The output is JSON.
+Creates a new folder and returns a new folder object
+Deletes a folder with the id folderId and all the feeds it contains
+Only the name can be updated
+{
+ // 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
+}
+
The following attributes are not sanitized meaning: including them in your web application can lead to XSS:
+{
+ "feeds": [
+ {
+ "id": 39,
+ "url": "http://feeds.feedburner.com/oatmealfeed",
+ "title": "The Oatmeal - Comics, Quizzes, & Stories",
+ "faviconLink": "http://theoatmeal.com/favicon.ico",
+ "added": 1367063790,
+ "folderId": 4,
+ "unreadCount": 9,
+ "nextUpdateTime": 2071387335,
+ "ordering": 0, // 0 means no special ordering, 1 means oldest first, 2 newest first, new in 5.1.0
+ "link": "http://theoatmeal.com/",
+ "pinned": true // if a feed should be sorted before other feeds, added in 6.0.3,
+ "updateErrorCount": 0, // added in 8.6.0, 0 if no errors occurred during the last update,
+ // otherwise is incremented for each failed update.
+ // Once it reaches a threshold, a message should be displayed to the user
+ // indicating that the feed has failed to update that many times.
+ // The webapp displays the message after 50 failed updates
+ "lastUpdateError": "error message here" // added in 8.6.0, empty string or null if no update
+ // error happened, otherwise contains the last update error message
+ }, // etc
+ ],
+ "starredCount": 2,
+ "newestItemId": 3443 // only sent if there are items
+}
+
Creates a new feed and returns the feed
+{
+ "url": "http:\/\/www.cyanogenmod.org\/wp-content\/themes\/cyanogenmod\/images\/favicon.ico",
+ "folderId": 81 // id of the parent folder, null for root
+}
+
{
+ "feeds": [
+ {
+ "id": 39,
+ "url": "http://feeds.feedburner.com/oatmealfeed",
+ "title": "The Oatmeal - Comics, Quizzes, & Stories",
+ "faviconLink": "http://theoatmeal.com/favicon.ico",
+ "added": 1367063790,
+ "nextUpdateTime": 2071387335,
+ "folderId": 4,
+ "unreadCount": 9,
+ "ordering": 0, // 0 means no special ordering, 1 means oldest first, 2 newest first, new in 5.1.0
+ "link": "http://theoatmeal.com/",
+ "pinned": true // if a feed should be sorted before other feeds, added in 6.0.3
+ }
+ ],
+ "newestItemId": 23 // only sent if there are items
+}
+
Deletes a feed with the id feedId and all of its items
+{
+ // 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
+}
+
The following attributes are not sanitized meaning: including them in your web application can lead to XSS:
+Name | +Default | +Types | +
---|---|---|
author | +null | +string|null | +
body | ++ | string|null | +
contentHash | ++ | string|null | +
enclosureLink | ++ | string|null | +
enclosureMime | ++ | string|null | +
feedId | ++ | int | +
fingerprint | ++ | string|null | +
guid | ++ | string | +
guidHash | ++ | string | +
id | ++ | int | +
lastModified | +\"0\" | +string|null | +
mediaDescription | ++ | string|null | +
mediaThumbnail | ++ | string|null | +
pubDate | ++ | int|null | +
rtl | +false | +bool | +
starred | +false | +bool | +
title | ++ | string|null | +
unread | +false | +bool | +
updatedDate | ++ | string|null | +
url | ++ | string|null | +
{
+ "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
+ "type": 1, // the type of the query (Feed: 0, Folder: 1, Starred: 2, All: 3)
+ "id": 12, // the id of the folder or feed, Use 0 for Starred and All
+ "getRead": true, // if true it returns all items, false returns only unread items
+ "oldestFirst": false // implemented in 3.002, if true it reverse the sort order
+}
+
{
+ "items": [
+ {
+ "id": 3443,
+ "guid": "http://grulja.wordpress.com/?p=76",
+ "guidHash": "3059047a572cd9cd5d0bf645faffd077",
+ "url": "http://grulja.wordpress.com/2013/04/29/plasma-nm-after-the-solid-sprint/",
+ "title": "Plasma-nm after the solid sprint",
+ "author": "Jan Grulich (grulja)",
+ "pubDate": 1367270544,
+ "body": "<p>At first I have to say...</p>",
+ "enclosureMime": null,
+ "enclosureLink": null,
+ "mediaThumbnail": null, // new in 14.1.4-rc1
+ "mediaDescription": null, // new in 14.1.4-rc1
+ "feedId": 67,
+ "unread": true,
+ "starred": false,
+ "rtl": false, // new in 6.0.2
+ "lastModified": 1367273003,
+ "fingerprint": "aeaae2123" // new in 8.4.0 hash over title, enclosures, body and url. Same fingerprint means same item and it's advised to locally mark the other one read as well and filter out duplicates in folder and all articles view
+ }, // etc
+ ]
+}
+
Autopaging would work like this:
+GET /items:
+ +The item with the lowest item id is 43.
+This is used to stay up to date.
+{
+ "lastModified": 123231, // returns only items with a lastModified timestamp >= than this one
+ // this may also return already existing items whose read or starred status
+ // has been changed
+ "type": 1, // the type of the query (Feed: 0, Folder: 1, Starred: 2, All: 3)
+ "id": 12 // the id of the folder or feed, Use 0 for Starred and All
+}
+
{
+ "items": [
+ {
+ "id": 3443,
+ "guid": "http://grulja.wordpress.com/?p=76",
+ "guidHash": "3059047a572cd9cd5d0bf645faffd077",
+ "url": "http://grulja.wordpress.com/2013/04/29/plasma-nm-after-the-solid-sprint/",
+ "title": "Plasma-nm after the solid sprint",
+ "author": "Jan Grulich (grulja)",
+ "pubDate": 1367270544,
+ "body": "<p>At first I have to say...</p>",
+ "enclosureMime": null,
+ "enclosureLink": null,
+ "feedId": 67,
+ "unread": true,
+ "starred": false,
+ "lastModified": 1367273003,
+ "fingerprint": "aeaae2123" // new in 8.4.0 hash over title, enclosures, body and url. Same fingerprint means same item and it's advised to locally mark the other one read as well and filter out duplicates in folder and all articles view
+ }, // etc
+ ]
+}
+
{
+ // 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
+}
+
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.
+Updating should be done in the following fashion:
+This implementation in Python should give you a good idea how to design and run it.
+This is used to clean up the database. It deletes folders and feeds that are marked for deletion
+New in 8.1.0: The console command for achieving the same result is:
+ +New in 8.1.0, Removed in 16.0.0: The console command for achieving the same result is:
+ +New in 8.1.0: The console command for achieving the same result is:
+ +This is used to clean up the database. It removes old read articles which are not starred
+New in 8.1.0: The console command for achieving the same result is:
+ +This API can be used to display warnings and errors in your client if the web app is improperly configured or not working. It is a good idea to call this route on like every 10th update and after the server connection parameters have been changed since it's likely that the user set up a new instance and configured the app improperly.
+{
+ "version": "5.2.4",
+ "warnings": {
+ "improperlyConfiguredCron": false, // if true the webapp will fail to update the feeds correctly
+ "incorrectDbCharset": false
+ }
+}
+
If improperlyConfiguredCron is true you should display a warning that the app will not receive updates properly.
+This is due to the fact that the installation runs the cron in ajax mode to update the feeds. This is the default if you don't change anything and means that the app will only receive feed updates if the webinterface is accessed which will lead to lost updates.
+You should show the following warning and the link should be clickable:
+The News App updater is improperly configured and you will lose updates.
+See http://hisdomain.com/index.php/apps/news for instructions on how to fix it.
+
If incorrectDbCharset is true you should display a warning that database charset is set up incorrectly and updates with unicode characters might fail
+This API can be used to retrieve metadata about the current user.
+DEPRECATED: This API is deprecated, use the Nextcloud APIs instead.
+https://nc.url/avatar/{userid}/{size}?v={1|2}
for the avatarThe News app 1.3 offers a RESTful API.
+The API level will change if the following occurs:
+The API level will not change if:
+You have to design your app with these things in mind!:
+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:
+https://yournextcloud.com/index.php/apps/news/api/v1-3/
+
All defined routes in the Specification are appended to this url. To access all feeds for instance use this url:
+https://yournextcloud.com/index.php/apps/news/api/v1-3/feeds
+
Credentials need to be passed as an HTTP header using HTTP basic auth:
+Authorization: Basic $CREDENTIALS
+
where $CREDENTIALS is:
+base64(USER:PASSWORD)
+
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)
+The initial 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:
+The JSON response structures can be viewed further down.
+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:
+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:
+$.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);
+ }
+});
+
An example with AngularJS would look like this:
+angular.module('YourApp', [])
+ .config(['$httpProvider', '$provide', function ($httpProvider, $provide) {
+ $provide.factory('AuthInterceptor', ['Credentials', '$q', function (Credentials, $q) {
+ return {
+ request: function (config) {
+ // only set auth headers if url matches the api url
+ if(config.url.indexOf(Credentials.url) === 0) {
+ auth = btoa(Credentials.userName + ':' + Credentials.password);
+ config.headers['Authorization'] = 'Basic ' + auth;
+ }
+ return config || $q.when(config);
+ }
+ };
+ }]);
+ $httpProvider.interceptors.push('AuthInterceptor');
+ }])
+ .factory('Credentials', function () {
+ return {
+ userName: 'user',
+ password: 'password',
+ url: 'https://yournextcloud.com/index.php/apps/news/api'
+ };
+ })
+ .run(['$http', function($http) {
+ $http({
+ method: 'GET',
+ url: 'https://yournextcloud.com/index.php/apps/news/api/v1-3/version'
+ }).success(function (data, status, header, config) {
+ // handle success
+ }).error(function (data, status, header, config) {
+ // handle error
+ });
+ }]);
+
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:
+ +will be treated the same as
+/?id=3
+
It is recommended though that you use the following convention:
+The output is JSON.
+Creates a new folder and returns a new folder object
+Deletes a folder with the id folderId and all the feeds it contains
+Only the name can be updated
+{
+ // 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
+}
+
The following attributes are not sanitized meaning: including them in your web application can lead to XSS:
+{
+ "feeds": [
+ {
+ "id": 39,
+ "url": "http://feeds.feedburner.com/oatmealfeed",
+ "title": "The Oatmeal - Comics, Quizzes, & Stories",
+ "faviconLink": "http://theoatmeal.com/favicon.ico",
+ "added": 1367063790,
+ "nextUpdateTime": 2071387335,
+ "folderId": 4,
+ "unreadCount": 9,
+ "ordering": 0, // 0 means no special ordering, 1 means oldest first, 2 newest first, new in 5.1.0
+ "link": "http://theoatmeal.com/",
+ "pinned": true // if a feed should be sorted before other feeds, added in 6.0.3,
+ "updateErrorCount": 0, // added in 8.6.0, 0 if no errors occurred during the last update,
+ // otherwise is incremented for each failed update.
+ // Once it reaches a threshold, a message should be displayed to the user
+ // indicating that the feed has failed to update that many times.
+ // The webapp displays the message after 50 failed updates
+ "lastUpdateError": "error message here" // added in 8.6.0, empty string or null if no update
+ // error happened, otherwise contains the last update error message
+ }, // etc
+ ],
+ "starredCount": 2,
+ "newestItemId": 3443 // only sent if there are items
+}
+
Creates a new feed and returns the feed
+{
+ "url": "http:\/\/www.cyanogenmod.org\/wp-content\/themes\/cyanogenmod\/images\/favicon.ico",
+ "folderId": 81 // id of the parent folder, null for root
+}
+
{
+ "feeds": [
+ {
+ "id": 39,
+ "url": "http://feeds.feedburner.com/oatmealfeed",
+ "title": "The Oatmeal - Comics, Quizzes, & Stories",
+ "faviconLink": "http://theoatmeal.com/favicon.ico",
+ "added": 1367063790,
+ "nextUpdateTime": 2071387335,
+ "folderId": 4,
+ "unreadCount": 9,
+ "ordering": 0, // 0 means no special ordering, 1 means oldest first, 2 newest first, new in 5.1.0
+ "link": "http://theoatmeal.com/",
+ "pinned": true // if a feed should be sorted before other feeds, added in 6.0.3
+ }
+ ],
+ "newestItemId": 23 // only sent if there are items
+}
+
Deletes a feed with the id feedId and all of its items
+{
+ // 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
+}
+
The following attributes are not sanitized meaning: including them in your web application can lead to XSS:
+Name | +Default | +Types | +
---|---|---|
author | +null | +string|null | +
body | ++ | string|null | +
contentHash | ++ | string|null | +
enclosureLink | ++ | string|null | +
enclosureMime | ++ | string|null | +
feedId | ++ | int | +
fingerprint | ++ | string|null | +
guid | ++ | string | +
guidHash | ++ | string | +
id | ++ | int | +
lastModified | +\"0\" | +string|null | +
mediaDescription | ++ | string|null | +
mediaThumbnail | ++ | string|null | +
pubDate | ++ | int|null | +
rtl | +false | +bool | +
starred | +false | +bool | +
title | ++ | string|null | +
unread | +false | +bool | +
updatedDate | ++ | string|null | +
url | ++ | string|null | +
{
+ "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
+ "type": 1, // the type of the query (Feed: 0, Folder: 1, Starred: 2, All: 3)
+ "id": 12, // the id of the folder or feed, Use 0 for Starred and All
+ "getRead": true, // if true it returns all items, false returns only unread items
+ "oldestFirst": false // implemented in 3.002, if true it reverse the sort order
+}
+
{
+ "items": [
+ {
+ "id": 3443,
+ "guid": "http://grulja.wordpress.com/?p=76",
+ "guidHash": "3059047a572cd9cd5d0bf645faffd077",
+ "url": "http://grulja.wordpress.com/2013/04/29/plasma-nm-after-the-solid-sprint/",
+ "title": "Plasma-nm after the solid sprint",
+ "author": "Jan Grulich (grulja)",
+ "pubDate": 1367270544,
+ "body": "<p>At first I have to say...</p>",
+ "enclosureMime": null,
+ "enclosureLink": null,
+ "mediaThumbnail": null, // new in 14.1.4-rc1
+ "mediaDescription": null, // new in 14.1.4-rc1
+ "feedId": 67,
+ "unread": true,
+ "starred": false,
+ "rtl": false, // new in 6.0.2
+ "lastModified": 1367273003,
+ "fingerprint": "aeaae2123" // new in 8.4.0 hash over title, enclosures, body and url. Same fingerprint means same item and it's advised to locally mark the other one read as well and filter out duplicates in folder and all articles view
+ }, // etc
+ ]
+}
+
Autopaging would work like this:
+GET /items:
+ +The item with the lowest item id is 43.
+This is used to stay up to date.
+{
+ "lastModified": 123231, // returns only items with a lastModified timestamp >= than this one
+ // this may also return already existing items whose read or starred status
+ // has been changed
+ "type": 1, // the type of the query (Feed: 0, Folder: 1, Starred: 2, All: 3)
+ "id": 12 // the id of the folder or feed, Use 0 for Starred and All
+}
+
{
+ "items": [
+ {
+ "id": 3443,
+ "guid": "http://grulja.wordpress.com/?p=76",
+ "guidHash": "3059047a572cd9cd5d0bf645faffd077",
+ "url": "http://grulja.wordpress.com/2013/04/29/plasma-nm-after-the-solid-sprint/",
+ "title": "Plasma-nm after the solid sprint",
+ "author": "Jan Grulich (grulja)",
+ "pubDate": 1367270544,
+ "body": "<p>At first I have to say...</p>",
+ "enclosureMime": null,
+ "enclosureLink": null,
+ "feedId": 67,
+ "unread": true,
+ "starred": false,
+ "lastModified": 1367273003,
+ "fingerprint": "aeaae2123" // new in 8.4.0 hash over title, enclosures, body and url. Same fingerprint means same item and it's advised to locally mark the other one read as well and filter out duplicates in folder and all articles view
+ }, // etc
+ ]
+}
+
{
+ // 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
+}
+
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.
+Updating should be done in the following fashion:
+This implementation in Python should give you a good idea how to design and run it.
+This is used to clean up the database. It deletes folders and feeds that are marked for deletion
+New in 8.1.0: The console command for achieving the same result is:
+ +New in 8.1.0, Removed in 16.0.0: The console command for achieving the same result is:
+ +New in 8.1.0: The console command for achieving the same result is:
+ +This is used to clean up the database. It removes old read articles which are not starred
+New in 8.1.0: The console command for achieving the same result is:
+ +This API can be used to display warnings and errors in your client if the web app is improperly configured or not working. It is a good idea to call this route on like every 10th update and after the server connection parameters have been changed since it's likely that the user set up a new instance and configured the app improperly.
+{
+ "version": "5.2.4",
+ "warnings": {
+ "improperlyConfiguredCron": false, // if true the webapp will fail to update the feeds correctly
+ "incorrectDbCharset": false
+ }
+}
+
If improperlyConfiguredCron is true you should display a warning that the app will not receive updates properly.
+This is due to the fact that the installation runs the cron in ajax mode to update the feeds. This is the default if you don't change anything and means that the app will only receive feed updates if the webinterface is accessed which will lead to lost updates.
+You should show the following warning and the link should be clickable:
+The News App updater is improperly configured and you will lose updates.
+See http://hisdomain.com/index.php/apps/news for instructions on how to fix it.
+
If incorrectDbCharset is true you should display a warning that database charset is set up incorrectly and updates with unicode characters might fail
+This API can be used to retrieve metadata about the current user.
+DEPRECATED: This API is deprecated, use the Nextcloud APIs instead.
+https://nc.url/avatar/{userid}/{size}?v={1|2}
for the avatarDisclaimer: this API has not been fully implemented yet, help is welcome.
+The News app offers a RESTful API which can be used to sync folders, feeds and items. The API also supports CORS which means that you can access the API from your browser using JavaScript.
+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.
+This document uses the following conventions:
+In order to only specify the JSON objects once, comments are used to alias them.
+There are two types of aliases:
+Objects:
+ +means that the folder attributes will be listed inside the folder object
+Object arrays:
+ +means that folder objects will be listed inside the folders array.
+This means that the error object will not be explicitly shown in the examples. All HTTP 400 response status codes contain an error object:
+ +The API level will change if the following occurs:
+The API level will not change if:
+You have to design your app with these things in mind!:
+The base URL for all calls is:
+https://yournextcloud.com/index.php/apps/news/api/v2
+
Unless an absolute Url is specified, the relative Urls in the Specification are appended to this url. To access the route /sync for instance you'd use the following url:
+https://yournextcloud.com/index.php/apps/news/api/v2/sync
+
The required request headers are:
+Any request method except GET:
+Any route that allows caching:
+The request body is either passed in the URL in case of a GET request (e.g.: ?foo=bar&index=0) or as JSON, 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.
+Check the API level route
+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:
+Authorization: Basic $CREDENTIALS
+
where $CREDENTIALS is:
+base64(USER:PASSWORD)
+
This authentication/authorization method will be the recommended default until core provides an easy way to do OAuth
+Note: Even if login cookies are sent back to your client, they will not be considered for authentication.
+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:
+The following status codes are returned by News:
+The response headers are:
+The response body is a JSON structure that looks like this, which contains the actual data on the first level. The key is the resource in singular if it's a single resource or plural if its a collection. In case of HTTP 400, an error object is also present to help distinguishing between different error types:
+ +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.
+Read the following notes carefully to prevent being subject to security exploits:
+All routes are given relative to the base API url, e.g.: /sync becomes https://yourNextcloud.com/index.php/apps/news/api/v2/sync
+There are two usecases for syncing:
+The initial 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:
+This will return the following status codes:
+and the following HTTP headers:
+and the following request body:
+{
+ "folders": [ /* array of folder objects */ ],
+ "feeds": [ /* array of feed objects */ ],
+ "items": [ /* array of item objects */ ]
+}
+
Note: Each object is explained in more detail in a separate section:
+ +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:
+with the following request body:
+{
+ "items": [{
+ // read and starred
+ "id": 5,
+ "isStarred": false,
+ "isUnread": true,
+ "contentHash": "08ffbcf94bd95a1faa6e9e799cc29054"
+ }, {
+ // only read
+ "id": 6,
+ "isUnread": true,
+ "contentHash": "09ffbcf94bd95a1faa6e9e799cc29054"
+ }, {
+ // only starred
+ "id": 7,
+ "isStarred": false,
+ "contentHash": "18ffbcf94bd95a1faa6e9e799cc29054"
+ }, /* etc */]
+}
+
If no items have been read or starred, simply leave the items array empty, e.g.:
+ +The response matches the GET call, except there can be two different types of item objects:
+ +The deciding factor whether a full or reduced item object is being returned depends on the contentHash in the request: If the contentHash matches the record in the database a reduced item object is being returned, otherwise a full object is used. Both can occur in the same items array at the same time.
+The idea behind this special handling is that if the contentHash matches the record in the database, the actual item content did not change. Therefore it is enough to know the item status. This greatly reduces the amount sent over the Net which is especially important for mobile apps.
+This also applies to folders and feeds, however the reduced folder and feed objects will only include the id element. The deciding factor whether only an id or the full object will be returned is the last modified modified timestamp which is included in the sent etag.
+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 POSTing the following JSON:
+{
+ "items": [{
+ "id": 5,
+ "isStarred": false,
+ "isUnread": true,
+ "contentHash": "08ffbcf94bd95a1faa6e9e799cc29054"
+ }, {
+ "id": 6,
+ "isUnread": true,
+ "contentHash": "09ffbcf94bd95a1faa6e9e799cc29054"
+ }, {
+ "id": 7,
+ "isStarred": false,
+ "contentHash": "18ffbcf94bd95a1faa6e9e799cc29054"
+ }]
+}
+
and receive the following output in return:
+{
+ "items": [{
+ "id": 5,
+ "isStarred": false,
+ "isUnread": true
+ }, {
+ "id": 6,
+ "isUnread": true,
+ "isStarred": false
+ }]
+}
+
The item with the id 7 is missing from the response. This means that it was deleted on the server.
+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 are represented using the following data structure:
+ +The attributes mean the following:
+To delete a folder, use the following request:
+The following response is being returned:
+Status codes:
+In case of an HTTP 200, the deleted folder is returned in full in the response, e.g.:
+ +Note: Deleted folders will not appear during the next sync so you also need to delete the folder locally afterwards. Folders should only be deleted locally if an HTTP 200 or 404 was returned.
+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.
+To create a folder, use the following request:
+with the following request body:
+ +The following response is being returned:
+Status codes:
+In case of an HTTP 200, the created or already existing folder is returned in full in the response, e.g.:
+ +The following attributes can be changed on the folder:
+To change any number of attributes on a folder, use the following request and provide as much attributes that can be changed as you want:
+with the following request body:
+ +The following response is being returned:
+Status codes:
+In case of an HTTP 200, the changed or already existing folder is returned in full in the response, e.g.:
+ +Feeds are represented using the following data structure:
+{
+ "id": 4,
+ "name": "The Oatmeal - Comics, Quizzes, & Stories",
+ "faviconLink": "http://theoatmeal.com/favicon.ico",
+ "folderId": 3,
+ "ordering": 0,
+ "fullTextEnabled": false,
+ "updateMode": 0,
+ "isPinned": true,
+ "error": {
+ "code": 1,
+ "message": ""
+ }
+}
+
The attributes mean the following:
+To delete a feed, use the following request:
+The following response is being returned:
+Status codes:
+In case of an HTTP 200, the deleted feed is returned in full in the response, e.g.:
+ +Note: Deleted feeds will not appear during the next sync so you also need to delete the feed locally afterwards. Feeds should only be deleted locally if an HTTP 200 or 404 was returned.
+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.
+To create a feed, use the following request:
+with the following request body:
+{
+ "url": "https://feed.url.com",
+ "name": "Feed name",
+ "ordering": 0,
+ "folderId": 3,
+ "isPinned": true,
+ "fullTextEnabled": false,
+ "basicAuthUser": "user",
+ "basicAuthPassword": "password"
+}
+
The following response is being returned:
+Status codes:
+In case of an HTTP 200, the created feed is returned in full in the response, e.g.:
+ +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 again.
+To change a feed, use the following request:
+with the following request body:
+{
+ "url": "https://feed.url.com",
+ "name": "Feed name",
+ "ordering": 0,
+ "folderId": 3,
+ "isPinned": true,
+ "fullTextEnabled": false,
+ "basicAuthUser": "user",
+ "basicAuthPassword": "password"
+}
+
All parameters are optional
+The following response is being returned:
+Status codes:
+In case of an HTTP 200, the changed feed is returned in full in the response, e.g.:
+ +Note: Because the next sync would also pull in the changed feed and items again, the added or updated items will be omitted for saving bandwidth. This also means that after successfully updating a feed you will need to query the sync route again.
+Items can occur in two different formats:
+The attributes mean the following:
+A full item contains the full content:
+{
+ "id": 5,
+ "url": "http://grulja.wordpress.com/2013/04/29/plasma-nm-after-the-solid-sprint/",
+ "title": "Plasma-nm after the solid sprint",
+ "author": "Jan Grulich (grulja)",
+ "publishedAt": "2005-08-15T15:52:01+0000",
+ "lastModifiedAt": "2005-08-15T15:52:01+0000",
+ "enclosure": {
+ "mimeType": "video/webm",
+ "url": "http://video.webmfiles.org/elephants-dream.webm"
+ },
+ "body": "<p>At first I have to say...</p>",
+ "feedId": 4,
+ "isUnread": true,
+ "isStarred": true,
+ "fingerprint": "08ffbcf94bd95a1faa6e9e799cc29054",
+ "contentHash": "18ffbcf94bd95a1faa6e9e799cc29054"
+}
+
A reduced item only contains the item status:
+ +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:
+The reference implementation in Python should give you a good idea how to design your own updater.
+If the REST API is used, Authorization is required via Basic Auth and the user needs to be in the admin group. +If the Nextcloud console API is used, no authorization is required.
+This is used to clean up the database. It deletes folders and feeds that are marked for deletion.
+Console API:
+ +REST API:
+This call returns pairs of feed ids and user ids.
+Console API:
+ +REST API:
+Both APIs will return the following response body or terminal output:
+ +After all feed ids and user ids are known, feeds can be updated in parallel.
+Console API:
+REST API:
+This is used to clean up the database. It removes old read articles which are not starred.
+Console API:
+ +REST API:
+The retrieve meta data about the app, use the following request:
+The following response is being returned:
+Status codes:
+In case of an HTTP 200, the the following response is returned:
+{
+ "version": "9.0.0",
+ "issues": {
+ "improperlyConfiguredCron": false
+ },
+ "user": {
+ "userId": "john",
+ "displayName": "John Doe",
+ "avatar": {
+ "data": "asdiufadfasdfjlkjlkjljdfdf",
+ "mime": "image/jpeg"
+ }
+ }
+}
+
The attributes mean the following:
+To find out which API levels are supported, make a request to the following route:
+The following response is being returned:
+Status codes:
+In case of an HTTP 200, the supported API levels are returned as JSON, e.g.:
+ +apiLevels: An array of arbitrary long strings, strings represent the the supported api levels which directly correspond to the first fragment after the /api/ Url fragment.
+To find out if a user is running an older News version than 8.8.0, make a request to the following route:
+Status codes:
+Since these calls can be expensive you could first try to make a call to the sync route and if it fails with an HTTP 404 run the API level detection. Of course the choice which APIs you are going to support is entirely yours and you could also hard require v2.
+Note: Future News app versions may remove the v1-2 API level depending on how widespread the adoption has become. You should therefore always make sure which API levels are actually supported.
+ + + + + + + + + + + + + +{"use strict";/*!
+ * escape-html
+ * Copyright(c) 2012-2013 TJ Holowaychuk
+ * Copyright(c) 2015 Andreas Lubbe
+ * Copyright(c) 2015 Tiancheng "Timothy" Gu
+ * MIT Licensed
+ */var Va=/["'&<>]/;qn.exports=za;function za(e){var t=""+e,r=Va.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i