Changed
- Add support for moving feeds to another folder from the sidebar feed menu (#2707)
- Persist the filter state and show unread items by default (#2704)
Fixed
- Fix undefined item when using `j` and `k` keyboards shortcuts in an empty feed (#2689)
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
add: more feed moving implementation
add: finish feed moving and update changelog
add: try more ways to reload feed list
add: do folder and feed reloading
Signed-off-by: Patrizio Bekerle <patrizio@bekerle.com>
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
Changed
- added alternative development environment (#2670)
- Implement `j` and `k` keyboards shortcuts for navigating through feed items (#2671)
- Implement `s`, `i` and `l` keyboards shortcuts for staring current feed item (#2677)
- Implement `o` keyboards shortcut for opening the URL of current feed item (#2677)
- Implement `u` keyboards shortcut for marking current feed item read/unread (#2677)
- Implement highlighting of active feed item (#2677)
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
* add: highlighting of active item
* add: keyboard shortcuts "u", "s", "i", "l" and "o"
* dev: force running commands on stale session
* add: prepare scrolling to the current item
Signed-off-by: Patrizio Bekerle <patrizio@bekerle.com>
add: make first attempt to jump to previous and next feed item
fix: linter errors
fix: use correct feed items
fix: use filterSortedItems()
add: trigger click event programmatically to benefit from item handling
inside FeedItemRow component
add: use a proper item if none is selected
fix: remove not needed MUTATIONS import
add: attempt to scroll to clicked item
doc: add changelog text
Signed-off-by: Patrizio Bekerle <patrizio@bekerle.com>
When enabling the app for the very first time and opening the view, a
toast notification pops up with the following message:
> TypeError: a.data.items is undefined
This is caused by a silenced exception in lib/Controller/ItemController.
Due to it, not a single key is set in the $return array.
Responses returned from such a controller will be serialized as JSON.
However, the returned value is no longer a key-value array, but an
(empty) list and the serializer will convert it to `[]` instead of `{}`
what it should've been.
Now it will return a dummy response containing all the keys but
empty values, causing the serializer to return an object.
Signed-off-by: Vincent Neubauer <v.neubauer@darlor.de>
Changed
- Improve layout of feed item row (#2569)
Fixed
- Reset content scroll position when feed item is changed (#2569)
- Fix link to feed in article header (#2569)
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
Changed
- make occ news:updater:job exit with code 2 if last update was too long ago (#2590)
- Fix deprecated variable reference in ExportController.php (#2602)
- Add support for Nextcloud 29 (#2611)
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
Signed-off-by: Petra Mirelli <80395360+iNtEgraIR2021@users.noreply.github.com>
Co-authored-by: Sean Molenaar <SMillerDev@users.noreply.github.com>
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
Changed
- Add DB index for news_feeds.deleted_at (#2526)
Fixed
- PostgreSQL implement fix for marking over 65535 unread items as "read" (#2557)
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
If there are more than 65535 unread items, then when checking “mark as read” you will get an SQL error (SQLSTATE[HY000]: General error: 7 number of parameters must be between 0 and 65535 at) due to the limitation of the number of parameters. The array is divided into smaller ones.
Signed-off-by: IgorA100 <igora100@gmail.com>
The CCMixter favicon was responsible for browsers emitting
a mixed content warning. While at it, I changed all other
http URLs to https.
Signed-off-by: Christof Dorner <christof@chdorner.com>
Changed
- Add support for Nextcloud 28
- Use Nextcloud vue components for item list and article view (#2401)
- Fix aspect ratio of article images (#2401)
Fixed
- Adjust search urls to match changed Vue routes (#2408)
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
Changed
- Major Rewrite of the Frontend with Vue JS (#748)
For comments and suggestions for the new UI, please use this: https://github.com/nextcloud/news/discussions/2388
- Set User Agent for curl in Scraper (#2380)
- Drop support for Nextcloud 26, Supported 27
Signed-off-by: Benjamin Brahmer <info@b-brahmer.de>
- started on unread component and using load-more callback from VirtualScroll component
- realized we need to change to a 3-panel display because VirtualScroll removes the rendered component even when open if you scroll too much
- created FeedItemDisplay component to display a selected feed item details
Signed-off-by: Devlin Junker <devlin.junker@gmail.com>
All notable changes to this project will be documented in this file.
The format is mostly based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), older entries don't fully match.
You can also check [on GitHub](https://github.com/nextcloud/news/releases), the release notes there are generated automatically and include every pull request.
# Unreleased
## [24.x.x]
## [25.x.x]
### Changed
### Fixed
# Releases
## [25.0.0-alpha8] - 2024-07-07
### Changed
- Add support for moving feeds to another folder from the sidebar feed menu (#2707)
- Persist the filter state and show unread items by default (#2704)
### Fixed
- Fix undefined item when using `j` and `k` keyboards shortcuts in an empty feed (#2689)
## [25.0.0-alpha7] - 2024-06-10
### Changed
- added alternative development environment (#2670)
- Implement `j` and `k` keyboards shortcuts for navigating through feed items (#2671)
- Implement `s`, `i` and `l` keyboards shortcuts for staring current feed item (#2677)
- Implement `o` keyboards shortcut for opening the URL of current feed item (#2677)
- Implement `u` keyboards shortcut for marking current feed item read/unread (#2677)
- Implement highlighting of active feed item (#2677)
# Releases
## [25.0.0-alpha6] - 2024-05-07
### Changed
- Improve layout of feed item row (#2569)
### Fixed
- Reset content scroll position when feed item is changed (#2569)
- Fix link to feed in article header (#2569)
## [25.0.0-alpha5] - 2024-04-01
### Changed
- make occ news:updater:job exit with code 2 if last update was too long ago (#2590)
- Fix deprecated variable reference in ExportController.php (#2602)
- Add support for Nextcloud 29 (#2611)
## [25.0.0-alpha4] - 2023-01-25
### Changed
- Add DB index for news_feeds.deleted_at (#2526)
### Fixed
- PostgreSQL implement fix for marking over 65535 unread items as "read" (#2557)
## [25.0.0-alpha3] - 2023-12-24
### Changed
- Changed default page when starting app (#2515)
- Downgrade feed-io to 5.3.1 (#2497)
### Fixed
- Fix search support for Nextcloud 28 (#2432)
## [25.0.0-alpha2] - 2023-11-08
### Changed
- Add support for Nextcloud 28
- Use Nextcloud vue components for item list and article view (#2401)
- Fix aspect ratio of article images (#2401)
### Fixed
- Adjust search urls to match changed Vue routes (#2408)
## [25.0.0-alpha1] - 2023-10-24
### Changed
- Major Rewrite of the Frontend with Vue JS (#748)
For comments and suggestions for the new UI, please use this: https://github.com/nextcloud/news/discussions/2388
The News app is an RSS/Atom feed aggregator. It offers a [RESTful API](https://nextcloud.github.io/news/developer/#apis) for app developers. The source code is [available on GitHub](https://github.com/nextcloud/news)
if version_greater "$installed_version""$image_version";then
echo"Can't start Nextcloud because the version of the data ($installed_version) is higher than the docker image version ($image_version) and downgrading is not supported. Are you sure you have pulled the newest image version?"
exit1
fi
if version_greater "$image_version""$installed_version";then
echo"Initializing nextcloud $image_version ..."
if["$installed_version" !="0.0.0.0"];then
echo"Upgrading nextcloud from $installed_version ..."
run_as 'php /var/www/html/occ app:list'| sed -n "/Enabled:/,/Disabled:/p" > /tmp/list_before
Welcome to the Admin documentation this page explains some of the configuration options for news.
## System Cron
Welcome to the Admin documentation.
## Administration via OCC
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:
```bash
sudo -u www-data php ./occ list news
```
More information about occ here: [Nextcloud Admin Manual](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/occ_command.html)
## Settings
The following sections explain some of the more complicated settings on the admin page.
### 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
### Auto purge count
- The default value is 200.
- To disable this feature, use -1.
- Unread and starred items are not deleted.
@ -17,30 +39,35 @@ 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
### 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
### 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 **<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](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) in your API, otherwise the request will fail!**
## Update Interval
### 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?
#### 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.
#### Can I set individual update intervals per feed/user?
@ -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.: <https://yournextcloud.com/index.php/apps/news/api/v1-2>)
### 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:
@ -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.: <https://yournextcloud.com/index.php/apps/news/api/v1-3>)
### 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:
@ -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 **<https://yourNextcloud.com/index.php/apps/news/api/v2/sync>**
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. <https://the-url.com>. 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.
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,27 +18,55 @@ 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`.
For linting JavaScript, a [jshint file](https://github.com/nextcloud/news/blob/master/js/.jshintrc) is used that is run before compiling the JavaScript.
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.
Change into the news directory and run make to build the app, you will need php, composer, node, npm and maybe more.
Change into the news directory and run `make` to build the app, you will need php, composer, node, npm and maybe more.
Now you can basically use the news app and test your changes.
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.
## Alternative Developer setup
With [PR 2670](https://github.com/nextcloud/news/pull/2670) new options to create a development environment were added.
See the README in the docker directory.
There is also a nix-shell config and zellij layout prepared.
If you have issues with the setup create a [new discussion](https://github.com/nextcloud/news/discussions).
### 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.
### Frontend Unit Tests
Frontend unit tests are written with Jest and can be run with `npm run test`.
### API and CLI Integration Tests
## Running Integration tests locally
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.
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 \<link> attribute (e.g.: \<link>https://www.google.de/path?my=query \</link>)
* Extract the Domain from the URL (e.g.: www.google.de)
* Take the URL from the \<link> attribute (e.g.: \<link><https://www.google.de/path?my=query> \</link>)
* Extract the Domain from the URL (e.g.: <www.google.de>)
* 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
1. In the *Description* field, enter a description for the RSS reader entry. 'NextCloud News' is a reasonable name.
1. In the *Description* field, enter a description for the RSS reader entry. 'NextCloud News' is a reasonable name.
1. Enter `https://<NEXTCLOUD_BASE_PATH>/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
* 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>
@ -9,157 +9,49 @@ 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). If you want you can [take a look at the developer docs](https://docs.nextcloud.org/server/latest/developer_manual/app/index.html) or [dig into the tutorial](https://docs.nextcloud.org/server/latest/developer_manual/app/tutorial.html).
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.
First create the following directories and files:
First create a skeleton app using the [web interface](https://apps.nextcloud.com/developer/apps/generate)
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**
The first folder name affects the name and namespace of your plugin and only one app can exist using the same name. Choose wisely.
First let's add some meta ata about our app. Open the **newsplugin/appinfo/info.xml** and add the following contents:
```xml
<?xml version="1.0"?>
<info>
<id>newsplugin</id>
<name>Example News Plugin</name>
<description>This plugin allows you to share articles via Twitter</description>
<licence>AGPL</licence>
<author>Your Name Here</author>
<version>0.0.1</version>
<dependencies>
<nextcloudmin-version="10"/>
<owncloudmin-version="9.1"/>
<phpmin-version="5.6"/>
</dependencies>
</info>
```
* **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!
Then we want to make sure that our code is only run if the News app is enabled. To do that put the following PHP code into the **newsplugin/appinfo/app.php** file:
Then we want to make sure that our code is only run if the News app is enabled. To do that put the following PHP code into the **newsplugin/lib/AppInfo/Application.php** file:
```php
<?php
namespace OCA\NewsPlugin\AppInfo;
use OCP\App;
declare(strict_types=1);
if (App::isEnabled('news')) {
// your code here
namespace OCA\NewsBookmarkPlugin\AppInfo;
use OCP\AppFramework\App;
use OCP\Util;
use OCP\App as Test;
class Application extends App {
public const APP_ID = 'newsbookmarkplugin';
public function __construct() {
parent::__construct(self::APP_ID);
// your code here
}
}
```
If your plugin integrates with another Nextcloud app, make sure to also require it be installed. If you depend on the Bookmarks app for instance use:
```php
<?php
namespace OCA\MyNewsPlugin\AppInfo;
use OCP\App;
if (App::isEnabled('news') && App::isEnabled('bookmarks')) {
// your code here
}
```
Now you are ready to enable the app. Head over to the apps section and choose the **Not enabled** section. Your app should be listed under the name **Example News Plugin** (or whatever name you set in the **info.xml**).
With the basics set up, you can now choose how to progress further. In our case we just want to add some additional CSS and JavaScript, so we are going to create a client-side plugin.
## Client-Side Plugin
A client-side plugin is adding additional JavaScript and/or CSS to the News app. Remember the **app.php**? Open it and place the following contents inside:
```php
<?php
namespace OCA\MyNewsPlugin\AppInfo;
use OCP\App;
if (App::isEnabled('news') && class_exists('OCA\News\Plugin\Client\Plugin')) {
This will tell the News app to load the following files after its own JavaScript and CSS files have been included:
* **newsplugin/js/script.js**
* **newspluing/css/style.css**
### Adding Basic JavaScript Functionality
You can basically add any JavaScript you want. If you want to add a new article action, this is a bit more complicated because it's hard to hook into Angular from the outside. Therefore, the News app provides an API which makes creating additional article actions a breeze.
.attr('title', t('newsplugin', 'Share on Twitter'));
var text = 'Read this: ' + article.url;
var url = 'https://twitter.com/intent/tweet?text=' + encodeURIComponent(text);
$button.click(function (event) {
window.open(url);
window.opener = null; // prevent twitter being from able to access the DOM
event.stopPropagation(); // prevent expanding in compact mode
});
$li.append($button);
$actionsElement.append($li);
});
```
Great! Now the only thing left is to add some styles.
### Adding Styles
Now let's add some styles to our app. We want to style the button to look like a Twitter icon, so simply download an icon (e.g. [from Wikipedia](https://commons.wikimedia.org/wiki/File:Twitter_icon.png)) and place it at **newsplugin/img/twitter.png**.
Then open the **newspluing/css/style.css** file and add the following CSS:
```css
.article-plugin-twitter button {
background-image: url('../img/twitter.png');
}
```
Reload the News app and click the three dots menu, sit back and enjoy :)
## 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 News app. Because all Classes are registered in the **news/app/application.php** it takes almost no effort to use the same infrastructure.
@ -200,3 +92,109 @@ class Application extends App {
Using automatic container assembly you can then use it from your code by simply adding the type to your constructors.
# TODO: Update the following
If your plugin integrates with another Nextcloud app, make sure to also require it be installed. If you depend on the Bookmarks app for instance use:
```php
<?php
namespace OCA\MyNewsPlugin\AppInfo;
use OCP\App;
if (App::isEnabled('news') && App::isEnabled('bookmarks')) {
// your code here
}
```
Now you are ready to enable the app. Head over to the apps section and choose the **Not enabled** section. Your app should be listed under the name **Example News Plugin** (or whatever name you set in the **info.xml**).
With the basics set up, you can now choose how to progress further. In our case we just want to add some additional CSS and JavaScript, so we are going to create a client-side plugin.
## Client-Side Plugin
A client-side plugin is adding additional JavaScript and/or CSS to the News app. Remember the **app.php**? Open it and place the following contents inside:
```php
<?php
namespace OCA\MyNewsPlugin\AppInfo;
use OCP\App;
if (App::isEnabled('news') && class_exists('OCA\News\Plugin\Client\Plugin')) {
This will tell the News app to load the following files after its own JavaScript and CSS files have been included:
* **newsplugin/js/script.js**
* **newspluing/css/style.css**
### Adding Basic JavaScript Functionality
You can basically add any JavaScript you want. If you want to add a new article action, this is a bit more complicated because it's hard to hook into Angular from the outside. Therefore, the News app provides an API which makes creating additional article actions a breeze.
.attr('title', t('newsplugin', 'Share on Twitter'));
var text = 'Read this: ' + article.url;
var url = 'https://twitter.com/intent/tweet?text=' + encodeURIComponent(text);
$button.click(function (event) {
window.open(url);
window.opener = null; // prevent twitter being from able to access the DOM
event.stopPropagation(); // prevent expanding in compact mode
});
$li.append($button);
$actionsElement.append($li);
});
```
Great! Now the only thing left is to add some styles.
### Adding Styles
Now let's add some styles to our app. We want to style the button to look like a Twitter icon, so simply download an icon (e.g. [from Wikipedia](https://commons.wikimedia.org/wiki/File:Twitter_icon.png)) and place it at **newsplugin/img/twitter.png**.
Then open the **newspluing/css/style.css** file and add the following CSS:
```css
.article-plugin-twitter button {
background-image: url('../img/twitter.png');
}
```
Reload the News app and click the three dots menu, sit back and enjoy :)
This is a brief list of common issues that come up with NextCloud News.
This is a brief list of common issues that come up with NextCloud News.
## My browser shows a mixed content warning (Connection is Not Secure)
If you are serving your Nextcloud over HTTPS your browser will very likely warn you with a yellow warnings sign about your connection not being secure.
* Chrome will show no green HTTPS lock sign.
* Firefox will show you the following image Mixed Passive Content ![Mixed Content Type](https://ffp4g1ylyit3jdyti1hqcvtb-wpengine.netdna-ssl.com/security/files/2015/10/mixed-passive-click1-600x221.png)
* Chrome will show no green HTTPS lock sign.
* Firefox will show you the following image Mixed Passive Content ![Mixed Content Type](https://ffp4g1ylyit3jdyti1hqcvtb-wpengine.netdna-ssl.com/security/files/2015/10/mixed-passive-click1-600x221.png)
Note that this warning **is not red and won't block the page like the following images** which signal a serious issue:
Something is wrong with the news cronjob, execution delay exceeded the configured interval.
```
If you think the job is stuck you can reset it, this may lead to issues if the job is currently running!
```bash
@ -82,7 +97,9 @@ Last Execution was 2023-03-20 12:20:03 UTC
Attempting to reset the job.
Done, job should execute on next schedule.
```
The output of the command should have changed.
```bash
sudo -u www-data php ./occ news:updater:job
Checking update Status
@ -140,7 +157,7 @@ The command `occ news:updater:after-update [--purge-unread] [<purge-count>]` can
The purge count only applies to the items that are purged. For example, when purging a feed that has 100 unread items, 100 starred read items and 100 unstarred read items, using a purge-count of 50 would keep all unread and starred items and the latest 50 read items. Using a `purge-count` of 50 along with `--purge-unread` would keep the all starred items plus the latest 50 from the set of unread and read items.
This is likely caused by your feed using emojis in the feed title or text.
@ -148,4 +165,4 @@ The DB is then not able to store the feed and runs into strange decoding errors.
You need to convert your DB to support 4 bytes, check the [Nextcloud documentation](https://docs.nextcloud.com/server/stable/admin_manual/configuration_database/mysql_4byte_support.html).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.