Cloudron makes it easy to run web apps like WordPress, Nextcloud, GitLab on your server. Find out more or install now.


Skip to content
  • 1 Votes
    1 Posts
    4 Views
    No one has replied
  • 1 Votes
    3 Posts
    95 Views
    M

    Out of curiosity I've built what @luckow suggested, only with Cloudron API (notifications endpoint) -> n8n -> some magic -> ntfy.sh-app and it looks like this:

    f036453c-4190-48d2-bae2-33c5e16133b5-image.png

    Action gets triggered (either automatically or manually), n8n checks the cloudron api https://my.example1.com/api/v1/notifications (create a readonly access token in your profile and update the Bearer token with it) with the parameters acknowledged = false, so only unread notifications are collected.

    The code-node does the following (filteredTitles because I don't care about app-updates, only actual issues, can be adjusted of course):

    const notifications = items[0].json.notifications; const types = notifications.map(notification => notification.type); const titles = notifications.map(notification => notification.title); // Filter notifications to remove those with type "appUpdated" const filteredNotifications = notifications.filter(notification => notification.type != "appUpdated"); // Extract titles of the filtered notifications const filteredTitles = filteredNotifications.map(notification => notification.title); //return [{ json: { types, titles } }]; return [{ json: { filteredTitles } }];

    This will result in an array of current notifications, e.g.

    [ { "filteredTitles": [ "Email is not configured properly", "The app at cms.example.com ran out of memory." ] } ] The if-node checks if there's actual content. If it's empty, nothing will happen, if it's not, it will make a http request to your nfty instance and topic of your choice (saved credentials in n8n) and send the notifications:

    2ae64242-ff94-44d3-843d-fb0154436eed-image.png

    Since I was working with readonly tokens, I had no intentions of marking the notifications as read after sending out the message. So there's room for improvement, but I thought I would throw it in here as a PoC 🙂

    Complete code (My_Cloudron_workflow.json) is here:

    { "name": "My Cloudron workflow", "nodes": [ { "parameters": {}, "id": "0dcf1d60-f8e7-4ffe-be14-64399a5c924d", "name": "When clicking \"Test workflow\"", "type": "n8n-nodes-base.manualTrigger", "typeVersion": 1, "position": [ 240, 620 ] }, { "parameters": { "url": "https://my.example1.com/api/v1/notifications", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "acknowledged", "value": "false" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer 123" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "id": "073de174-b658-480e-bb3c-6be103304bd9", "name": "EX1", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 460, 620 ], "alwaysOutputData": false }, { "parameters": { "url": "https://my.example2.com/api/v1/notifications", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "acknowledged", "value": "false" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer 456" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "id": "c29eae02-51b5-417c-a103-d35b4bcb15e8", "name": "EX2", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 460, 780 ], "alwaysOutputData": false }, { "parameters": { "url": "https://my.example3.com/api/v1/notifications", "sendQuery": true, "queryParameters": { "parameters": [ { "name": "acknowledged", "value": "false" } ] }, "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Authorization", "value": "Bearer 789" } ] }, "sendBody": true, "bodyParameters": { "parameters": [ {} ] }, "options": {} }, "id": "a00d01ae-fca9-41e8-b16f-3456459f414a", "name": "EX3", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 460, 460 ], "alwaysOutputData": false }, { "parameters": { "jsCode": "const notifications = items[0].json.notifications;\nconst types = notifications.map(notification => notification.type);\nconst titles = notifications.map(notification => notification.title);\n\n// Filter notifications to remove those with type \"appUpdated\"\nconst filteredNotifications = notifications.filter(notification => notification.type != \"appUpdated\");\n\n// Extract titles of the filtered notifications\nconst filteredTitles = filteredNotifications.map(notification => notification.title);\n\n//return [{ json: { types, titles } }];\nreturn [{ json: { filteredTitles } }];" }, "id": "fb776916-d0d4-46b6-8a7d-7de5694e650c", "name": "Code", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 620, 460 ] }, { "parameters": { "jsCode": "const notifications = items[0].json.notifications;\nconst types = notifications.map(notification => notification.type);\nconst titles = notifications.map(notification => notification.title);\n\n// Filter notifications to remove those with type \"appUpdated\"\nconst filteredNotifications = notifications.filter(notification => notification.type != \"appUpdated\");\n\n// Extract titles of the filtered notifications\nconst filteredTitles = filteredNotifications.map(notification => notification.title);\n\n//return [{ json: { types, titles } }];\nreturn [{ json: { filteredTitles } }];" }, "id": "968f2566-7983-46ef-b14a-3677a3a6fc88", "name": "Code1", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 620, 620 ] }, { "parameters": { "jsCode": "const notifications = items[0].json.notifications;\nconst types = notifications.map(notification => notification.type);\nconst titles = notifications.map(notification => notification.title);\n\n// Filter notifications to remove those with type \"appUpdated\"\nconst filteredNotifications = notifications.filter(notification => notification.type != \"appUpdated\");\n\n// Extract titles of the filtered notifications\nconst filteredTitles = filteredNotifications.map(notification => notification.title);\n\n//return [{ json: { types, titles } }];\nreturn [{ json: { filteredTitles } }];" }, "id": "5463ace4-ed1f-408a-a13c-a153fbda2ca3", "name": "Code2", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 620, 780 ] }, { "parameters": { "method": "POST", "url": "https://ntfy.nftyserver.com/cloudron-notifications", "authentication": "genericCredentialType", "genericAuthType": "httpBasicAuth", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Title", "value": "Current example3.com notifications" } ] }, "sendBody": true, "contentType": "raw", "rawContentType": "Title", "body": "={{ $json.filteredTitles.join(\"\\n\"); }}", "options": {} }, "id": "83bc0ca8-d7e1-4fb5-8dd9-0b3360f6763e", "name": "HTTP Request", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 940, 460 ], "credentials": { "httpBasicAuth": { "id": "5tUu1DjoNUxl0M5a", "name": "ntfy token" } } }, { "parameters": { "method": "POST", "url": "https://ntfy.nftyserver.com/cloudron-notifications", "authentication": "genericCredentialType", "genericAuthType": "httpBasicAuth", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Title", "value": "Current example1.com notifications" } ] }, "sendBody": true, "contentType": "raw", "rawContentType": "Title", "body": "={{ $json.filteredTitles.join(\"\\n\"); }}", "options": {} }, "id": "92815612-9381-444f-86b5-7c3c3cf8a371", "name": "HTTP Request1", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 940, 620 ], "credentials": { "httpBasicAuth": { "id": "5tUu1DjoNUxl0M5a", "name": "ntfy token" } } }, { "parameters": { "method": "POST", "url": "https://ntfy.nftyserver.com/cloudron-notifications", "authentication": "genericCredentialType", "genericAuthType": "httpBasicAuth", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Title", "value": "Current example2.com notifications" } ] }, "sendBody": true, "contentType": "raw", "rawContentType": "Title", "body": "={{ $json.filteredTitles.join(\"\\n\"); }}", "options": {} }, "id": "bc221e4f-8817-4c19-a74d-9333a4783319", "name": "HTTP Request2", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 940, 780 ], "credentials": { "httpBasicAuth": { "id": "5tUu1DjoNUxl0M5a", "name": "ntfy token" } } }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "43482a2f-b2b0-4f0a-b970-7b11e8f6ee03", "leftValue": "={{ $json.filteredTitles }}", "rightValue": "", "operator": { "type": "array", "operation": "notEmpty", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "id": "af3ebb14-32db-4afb-8c9d-84eb593eae96", "name": "If1", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [ 780, 620 ] }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "1811bb6f-55ca-4b2d-9f6b-97c489ef4d21", "leftValue": "={{ $json.filteredTitles }}", "rightValue": "", "operator": { "type": "array", "operation": "notEmpty", "singleValue": true } } ], "combinator": "or" }, "options": {} }, "id": "e354d631-5daf-495d-a5e2-e0fb64ef212d", "name": "If2", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [ 780, 780 ] }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "43482a2f-b2b0-4f0a-b970-7b11e8f6ee03", "leftValue": "={{ $json.filteredTitles }}", "rightValue": "", "operator": { "type": "array", "operation": "notEmpty", "singleValue": true } } ], "combinator": "and" }, "options": {} }, "id": "a3fc1a27-f94d-4651-884f-34c683b0a2da", "name": "If", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [ 780, 460 ] } ], "pinData": {}, "connections": { "When clicking \"Test workflow\"": { "main": [ [ { "node": "EX1", "type": "main", "index": 0 }, { "node": "EX2", "type": "main", "index": 0 }, { "node": "EX3", "type": "main", "index": 0 } ] ] }, "EX1": { "main": [ [ { "node": "Code1", "type": "main", "index": 0 } ] ] }, "EX2": { "main": [ [ { "node": "Code2", "type": "main", "index": 0 } ] ] }, "EX3": { "main": [ [ { "node": "Code", "type": "main", "index": 0 } ] ] }, "Code1": { "main": [ [ { "node": "If1", "type": "main", "index": 0 } ] ] }, "Code2": { "main": [ [ { "node": "If2", "type": "main", "index": 0 } ] ] }, "Code": { "main": [ [ { "node": "If", "type": "main", "index": 0 } ] ] }, "If1": { "main": [ [ { "node": "HTTP Request1", "type": "main", "index": 0 } ] ] }, "If2": { "main": [ [ { "node": "HTTP Request2", "type": "main", "index": 0 } ] ] }, "If": { "main": [ [ { "node": "HTTP Request", "type": "main", "index": 0 } ] ] } }, "active": false, "settings": { "executionOrder": "v1" }, "versionId": "b1689af0-81c6-453c-a8aa-1d7c84d7a85e", "meta": { "templateCredsSetupCompleted": true, "instanceId": "8903125d64295093a384f52f480a1738308c71ada8db56c53efba4894aefbff2" }, "id": "I2Mq9Y8GOPIDIh8i", "tags": [] }

    I threw out a module last minute, so hopefully no oversights in there. Improvements are welcome! 😉

    TL;DR: Adjust the URLs to your Cloudrons, create and add readonly tokens, add a ntfy token to your n8n credentials and adjust the URL to your ntfy instance.

  • Import previous emails

    FreeScout
    1
    0 Votes
    1 Posts
    5 Views
    No one has replied
  • 5 Votes
    5 Posts
    85 Views
    L

    I would like to be able to leave a note alongside a particular application backup, too.

  • Cost of Hosting Videos

    PeerTube
    4
    0 Votes
    4 Posts
    40 Views
    L

    One starting point is the average display size in the community you are serving:
    https://www.designrush.com/agency/web-development-companies/trends/website-dimensions

    You could pick a streaming resolution from there, and then move onto fps (frames per second) and format you will have for the videos. There is a calculator here:
    https://www.omnicalculator.com/other/video-size

    You can considerably reduce the file size and therefore the bandwidth requirement by encoding video using AV1. Hardware encoding for AV1 is available on some CPUs, eg the latest Ryzens from AMD.

    If you manage to get Object Storage to work with Peertube, some of us here would be keen to hear how you managed it. Peertube also supports HLS (HTTP live streaming), though this isn't working properly with AV1, yet.

    You can try side-by-side comparisons. 480p video is pretty good, and this also helps people with poor internet connections in some parts of the world.

  • A decent CRM

    Moved Discuss
    16
    1 Votes
    16 Posts
    532 Views
    marcusquinnM

    @zonzonzon It's the best FOSS you'll find. Don't know your other experience, but you can pretty much get Espo to do anything you please. If you need accounting done for you, though, Odoo is also a consideration, and their SaaS pricing ain't too bad for what you get.

  • 1 Votes
    1 Posts
    11 Views
    No one has replied
  • 4 Votes
    4 Posts
    647 Views
    32463

    I have now tried it and got it working well (so far). You can find out how I did it in my latest guide.

  • App store not showing - unable to connect calendar

    Unsolved Cal.com
    15
    0 Votes
    15 Posts
    272 Views
    32463

    Sadly, this is the way cal.com works. When you self-host it, you need to provision the apps you want your users to be able to use, which cannot be done after the initial install it seems. It might be worth asking upstream in their Github about options do amend this via CLI or otherwise.

  • 16 Votes
    20 Posts
    933 Views
    jdaviescoatesJ

    NocoDB does nice forms.

  • 0 Votes
    1 Posts
    8 Views
    No one has replied
  • 3 Votes
    1 Posts
    36 Views
    No one has replied
  • 2 Votes
    28 Posts
    1k Views
    L

    If only we could mark this "Solved - Permanently"!

  • Add a Text Field notes per apps

    Locked Solved Feature Requests
    2
    2 Votes
    2 Posts
    23 Views
    girishG

    @jrl-abstract27 Dup of https://forum.cloudron.io/topic/11559/possibility-to-add-app-notes-for-admins-operators-users/ .

    We have already implemented this for next release. Feel free to comment in the other thread, please.

  • GitLab - Package updates

    Pinned GitLab
    162
    1 Votes
    162 Posts
    9k Views
    girishG

    [1.90.0]

    Update GitLab to 16.11.1 Release announcement Autocomplete support for links to wiki pages Sidebar for metadata on the project overview page Option to cancel a pipeline immediately if any jobs fails Custom webhook headers Test project hooks with the REST API Group comment templates
  • Invidious - Package Updates

    Pinned Invidious
    10
    0 Votes
    10 Posts
    272 Views
    girishG

    [1.3.0]

    Update Invidious to v2.20240427 Full changelog Videos: Use android test suite client (#4650, thanks @SamantazFox) Trending: Un-nest category if this is the only one (#4600, thanks @ChunkyProgrammer) Comments: Add support for new format (#4576, thanks @ChunkyProgrammer) API: Add bitrate to formatStreams too (#4590, thanks @absidue) API: Add 'authorVerified' field on recommended videos (#4562, thanks @ChunkyProgrammer) Videos: Add support for new likes format (#4462, thanks @ChunkyProgrammer) Proxy: Handle non-200 HTTP codes on DASH manifests (#4429, thanks @absidue)
  • 4 Votes
    18 Posts
    475 Views
    girishG

    1.5.7 blocked by https://github.com/LibreTranslate/LibreTranslate/issues/614

  • Ghost - Package Updates

    Pinned Ghost
    379
    1 Votes
    379 Posts
    27k Views
    girishG

    [4.82.4]

    Update Ghost to 5.82.4 Full changelog
  • JupyterHub - Package Updates

    Pinned JupyterHub
    49
    0 Votes
    49 Posts
    1k Views
    girishG

    [1.45.3]

    Update datascience notebook image to lab-4.1.6
  • AppStore returns 424

    Solved Support
    22
    1 Votes
    22 Posts
    198 Views
    osoboO

    @girish Sorry for the delayed response. My server is also hosted in Singapore (by Hostinger). I've noted a couple of seconds delay to open Cloudron's app store but it is definitively back. Thank you again for the support 🙂 !