{"id":13674328,"url":"https://github.com/glosa/glosa-server","last_synced_at":"2025-04-28T14:31:14.274Z","repository":{"id":54369661,"uuid":"244964861","full_name":"glosa/glosa-server","owner":"glosa","description":"Comments for static sites. Clone of Disqus, but faster, Opensource and sexy.","archived":false,"fork":false,"pushed_at":"2024-03-19T09:34:52.000Z","size":30668,"stargazers_count":79,"open_issues_count":0,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-11-11T14:41:21.824Z","etag":null,"topics":["clojure","comment","comments-manager","comments-system","disqus","java","opensource"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/glosa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"tanrax","patreon":"androsfenollosa","ko_fi":"androsfenollosa"}},"created_at":"2020-03-04T17:40:40.000Z","updated_at":"2024-07-05T20:29:40.000Z","dependencies_parsed_at":"2024-11-11T14:34:47.376Z","dependency_job_id":"653b9ac6-b2c5-41b5-8842-eb2c824813f8","html_url":"https://github.com/glosa/glosa-server","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glosa%2Fglosa-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glosa%2Fglosa-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glosa%2Fglosa-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glosa%2Fglosa-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/glosa","download_url":"https://codeload.github.com/glosa/glosa-server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251330224,"owners_count":21572249,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","comment","comments-manager","comments-system","disqus","java","opensource"],"created_at":"2024-08-02T11:00:46.602Z","updated_at":"2025-04-28T14:31:13.279Z","avatar_url":"https://github.com/glosa.png","language":"HTML","funding_links":["https://github.com/sponsors/tanrax","https://patreon.com/androsfenollosa","https://ko-fi.com/androsfenollosa","https://ko-fi.com/androsfenollosa'"],"categories":["Software"],"sub_categories":["Communication - Social Networks and Forums"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"media/logo.png\" alt=\"logo\" width=\"200\"\u003e \n\u003c/p\u003e\n\u003ch1 align=\"center\"\u003eGlosa: Comments for static sites.\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n   \u003cstrong \u003eClone of Disqus, but faster, Opensource and sexy.\u003c/strong\u003e\n\u003c/p\u003e\n\n[![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/)\n\n## Amazing reasons to use it\n\n- **Opensource**.\n- **Very fast**, responses between 5ms and 15ms on average.\n- Easy to integrate with **static pages**.\n- **[PWA Admin for desktop and mobile](https://glosa.github.io/glosa-admin/#/) or [terminal](#terminal-cli)** to manage comments: Delete, update, find...\n- Easy to **[import from Disqus](https://github.com/glosa/glosa-disqus-import)**.\n- **No database**, everything is stored in a JSON.\n- Configuration in a **simple YAML**.\n- **Captcha** system included.\n- **Receive an email** for each new comment.\n- **Users are notified** by email if they are answered.\n- **Multisite**: Single server for multiple websites.\n\n## Resources\n\n### [Template static site (only HTML and Javascript)](https://github.com/glosa/glosa-static-integration)\n\n### [Import your comments from Disqus](https://github.com/glosa/glosa-disqus-import)\n\n### [PWA Admin](https://github.com/glosa/glosa-admin)\n\n### [Video Demo](https://cdn.jsdelivr.net/gh/glosa/glosa-static-integration/media/demo.mp4)\n\n---\n\n## Help me continue to improve\n\n\u003cp align=\"center\"\u003e\n  \u003ca href='https://ko-fi.com/androsfenollosa' target='_blank'\u003e\u003cimg height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi2.png?v=2' border='0' alt='Buy Me a Coffee at ko-fi.com' /\u003e\u003c/a\u003e\n\n---\n\n## Use it now\n\n- [How does it work?](#how-does-it-work)\n- [Origin](#origin)\n- [Run](#run)\n- [Notification template for email](#notification-template-for-email)\n- [API](#api)\n- [Terminal cli](#terminal-cli)\n- [Deployment](#deployment)\n- [Create your own JAR](#create-your-own-jar)\n\n---\n\n## How does it work?\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"media/explication.png\" alt=\"logo\" width=\"90%\"\u003e \n\u003c/p\u003e\n\nOn the one hand we have Glosa who would be our comment server. It **feeds in GET and POST requests**, and obediently **returns JSON**. It can only return **comments from a url** (it sorts comments by url, not ids) or **create a new comment** (**parent or child** of another comment). Nothing else. If you want to create a comment previously you will need to ask for the token to confirm that you are not a robot.\n\n**Optionally you can receive an email** automatically when a new comment is written.\n\nThe website, CMS or mobile application, must integrate a **logic with Javascript** to make the necessary requests and render the comments properly. To make this task easier we have created an example template that you can modify to your needs. You can find the link on this page.\n\n## Scenarios\n\n### 1 web page, share or not a server\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"media/scenary-1.png\" alt=\"logo\" width=\"500px\"\u003e \n\u003c/p\u003e\n\n### 3 web pages in different domains or servers\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"media/scenary-2.png\" alt=\"logo\" width=\"500px\"\u003e \n\u003c/p\u003e\n\n\n## Origin\n\nA Glosa is a **Spanish word**. It is defined as a **note**, usually brief, that is **written in the margin of a text** or even between its lines with the intention of clarifying some idea of it. \n\nThe software was born with the **intention that the author's static blog would no longer depend on an external company** (Disqus), and could have control of its content. To make it as easy as possible to deploy, develop and maintain; he programmed in **Clojure**. And from the beginning it was clear to him that he didn't need a conventional database, **plain text was enough**.\n\n## Run\n\n1) Make sure you have Java installed.\n\nDebian/Ubuntu\n\n``` sh\nsudo apt install default-jre\n```\n\nMac OS\n\n``` sh\nbrew install java\n```\n\n2) Create a file `config.yaml` with the following content. You can also use `config.yaml.example` as a base config and change it to fit your needs.\n\n``` yaml\n##### General #####\n# If it is active it will be accessible to any client\ndebug: false\n# It can be a domain in case of using a proxy: example.com\ndomain: localhost\nport: 4000\n# Access for APP\ntoken: mysecret\n# It indicates which domain can use it. Debug true so there are no limitations.\ndomain-cli: \"http://example-cli.com/\"\n\n##### Notify #####\n# Type of notification, currently valid: email\nnotify: email\nsubject: New comment\nfrom: server@example.com\nadmin: user@example.com\n# SMTP, only notify: email\nsmtp-host: smtp.example.com\nsmtp-user: smtpuser\nsmtp-password: smtppassword\nsmtp-port: 25\nsmtp-tls: true\n\n##### Captcha #####\n# Currently valid: time\ncaptcha: time\n\n##### Database #####\n# Currently valid: plain\ndatabase: plain\n```\n\n3) Download the latest version of Glosa (`glosa-{version}-standalone.jar`).\n\nhttps://github.com/glosa/glosa-server/releases\n\n\n4) Now you can execute glosa.\n\n```sh\njava -jar target/glosa-{version}-standalone.jar\n```\n\nGreat 🎉. You already have your 🔥 own comment server 🔥.\n\nThat's it, now you just have to test that it works properly.\n\n``` sh\ncurl localhost:4000/api/v1/captcha/?url=https://glosa.example/best-SO/'\n```\n\nIt will return a random token\n\n``` json\n{\"token\":\"OABWNONEOOKXRMMWADPF\"}\n```\n\n## Notification template for email\n\nThe first time Glosa is run it will create an HTML template with the name `template-email.html`. Edit freely.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"media/email.png\" alt=\"logo\" width=\"90%\"\u003e \n\u003c/p\u003e\n\n---\n\n## API\n\n\n- [Get Comments](#get-comments) (Public)\n- [Last comments](#last-comments) (Private)\n- [Add Comments](#add-comment) (Public)\n- [Update Comment](#update-comment) (Private)\n- [Delete Comment](#delete-comment) (Private)\n- [Search Threads](#search-threads) (Private)\n- [Get captcha token](#get-captcha-token) (Public)\n- [Check if he is alive](#check-if-he-is-alive) (Public)\n- [Check if token is valid](#check-if-token-is-valid) (Public)\n\n### Authorization\n\n**Only privates**.\n\nYou need a `token` to be able to interact (You will find it in your `config.yaml`). Use a **header with Bearer authorization** on each request.\n\nExample with `mysecret` token.\n\n``` sh\ncurl -XDELETE -H \"Authorization: Bearer mysecret\" -H \"Content-type: application/json\" ...\n```\n\n### Public\n\nNo `token` is required to interact. \n\n#### Get Comments\n\nGets all the comments on one page.\n\n**Method**: `GET`\n\n``` sh\n/api/v1/comments/?url={url}\n```\n\n| Param | Value  | Description |\n|---|---|---|\n| url  | string | Page where you want to get the comments. |\n\n##### Example\n\nGet from `http://glosa.example/best-SO/`.\n\n``` sh\ncurl 'http://localhost:4000/api/v1/comments/?url=https://glosa.example/best-SO/'\n```\n\n##### Success response\n\n``` json\n[\n    {\n        \"id\": 4812781236,\n        \"parent\": \"\",\n        \"deep\": 0,\n        \"createdAt\": 1584266634,\n        \"thread\": \"https://glosa.example/best-SO/\",\n        \"author\": \"Lexar\",\n        \"email\": \"\",\n        \"message\": \"Do you use Glosa too? It's an amazing technology.\"\n    },\n    {\n        \"id\": 4812781237,\n        \"parent\": \"4812781236\",\n        \"deep\": 1,\n        \"createdAt\": 1584266746,\n        \"thread\": \"https://glosa.example/best-SO/\",\n        \"author\": \"Lucia\",\n        \"email\": \"lucia@my.email\",\n        \"message\": \"I love the article.\"\n    }\n]\n```\n\n##### Fail response\n\n``` json\n[]\n```\n\n#### Last Comments\n\nGet the last 10 comments sorted by date. A pager is available.\n\n**Method**: `POST`\n\n``` sh\n/api/v1/comments/latest/{page}\n```\n\n| Param | Value  | Description |\n|---|---|---|\n| page  | number | Paginator. |\n\n##### Example\n\nI get the last 10 comments.\n\n``` sh\ncurl 'http://localhost:4000/api/v1/comments/latest/1'\n```\n\nLast comments between 30 and 40.\n\n``` sh\ncurl 'http://localhost:4000/api/v1/comments/latest/3'\n```\n\n##### Success response\n\n``` json\n[\n    {\n        \"id\": 4812781236,\n        \"parent\": \"\",\n        \"deep\": 0,\n        \"createdAt\": 1584266634,\n        \"thread\": \"https://glosa.example/best-SO/\",\n        \"author\": \"Lexar\",\n        \"email\": \"\",\n        \"message\": \"Do you use Glosa too? It's an amazing technology.\"\n    },\n    {\n        \"id\": 4812781237,\n        \"parent\": \"4812781236\",\n        \"deep\": 1,\n        \"createdAt\": 1584266746,\n        \"thread\": \"https://glosa.example/best-SO/\",\n        \"author\": \"Lucia\",\n        \"email\": \"lucia@my.email\",\n        \"message\": \"I love the article.\"\n    }\n    ...\n]\n```\n\n##### Fail response\n\n``` json\n[]\n```\n\n#### Add Comment\n\nAdd new comment on one page. **Require token generated by the [captcha endpoint](#get-captcha-token)**. After saving the comment the _captcha token_ will no longer be valid. At the same time a notification (email) will be sent to the administrator (in the configuration it is called `admin`), in case it is a sub-comment it will also be sent another notification to the parent of the comment if the address is present.\n\nThe steps must be.\n\n1. Get [captcha token](#get-captcha-token).\n2. Add comment.\n\n**Method**: `POST`\n\n``` sh\n/api/v1/comments/\n```\n\n| Param | Value | Description |\n|---|---|---|\n| parent  | number | If it's a sub-comment, the number of the parent comment. Otherwise leave empty. |\n| author  | string | Author's name. |\n| email  | string | Email that the user will be notified of the responses to his comment. Leave blank if not desired. |\n| message  | string | Message. It can be HTML or plain. |\n| token  | number | Number of the token generated by the [captcha endpoint](#get-captcha-token). |\n| thread  | string | Page where you want to save the comment. |\n\n##### Example\n\nSave comment from `https://glosa.example/best-SO/`.\n\n``` sh\ncurl -XPOST -H \"Content-type: application/json\" -d '{\n\t\"parent\": \"\",\n\t\"token\": \"VRJUOBBMTKFQUAFZOKJG\",\n\t\"author\": \"Juana\",\n\t\"email\": \"juana@my.email\",\n\t\"message\": \"I like it very much.\",\n\t\"thread\":\"https://glosa.example/best-SO/\"\n}' 'http://localhost:4000/api/v1/comments/'\n```\n\n##### Success response\n\n``` json\n{\n    \"added\": true\n}\n```\n\n##### Fail response\n\n\n``` json\n{\n    \"added\": false\n}\n```\n\n#### Get captcha token\n\nGet a token to validate that a new comment can be created. It has only one use. It must also be obtained 20 seconds before use or it will not work.\n\n**Method**: `GET`\n\n``` sh\n/api/v1/captcha/?url={url}\n```\n\n| Param | Value  | Description |\n|---|---|---|\n| url  | string | Page where you want to save the comment. |\n\n##### Example\n\nGet token for page `https://glosa.example/best-SO/`.\n\n``` sh\ncurl 'http://localhost:4000/api/v1/captcha/?url=https://glosa.example/best-SO/'\n```\n\n##### Success response\n\n``` json\n{\n    \"token\": \"ZRFOKXLALKNPOJPYJLVY\"\n}\n```\n\n##### Fail response\n\n\n``` json\n{\n    \"error\": \"Need URL\"\n}\n```\n\n#### Check if he is alive\n\nSimple answer to check that the service is working.\n\n**Method**: `GET`\n\n``` sh\n/api/v1/ping/\n```\n\n##### Example\n\n``` sh\ncurl 'http://localhost:4000/api/v1/ping/'\n```\n\n##### Success response\n\n``` json\n{\n    \"ping\": \"pong\"\n}\n```\n\n#### Check if token is valid\n\n**Method**: `POST`\n\n``` sh\n/api/v1/token/check/\n```\n\n| Param | Value  | Description |\n|---|---|---|\n| url  | string | Page where you want to save the comment. |\n\n##### Example\n\n``` sh\ncurl -XPOST -H \"Authorization: Bearer mysecret\" 'http://localhost:4000/api/v1/token/check/'\n```\n\n##### Success response\n\n``` json\n{\n    \"valid\": true\n}\n```\n\n##### Fail response\n\n\n``` json\n{\n    \"valid\": false\n}\n```\n\n### Private\n\n#### Update Comment\n\nUpdate a comment for ID. [Authorization required](#authorization).\n\n**Method**: `PUT`\n\n``` sh\n/api/v1/comments/\n```\n\n| Param | Value | Description |\n|---|---|---|\n| id  | number | Comment ID. |\n| author  | string | Author's name. |\n| email  | string | Email that the user will be notified of the responses to his comment. Leave blank if not desired. |\n| message  | string | Message. It can be HTML or plain. |\n\n\n##### Example\n\nUpdate comment with id `1234`.\n\n``` sh\ncurl -XPUT -H \"Authorization: Bearer mysecret\" -H \"Content-type: application/json\" -d '{\n    \"id\": 1234\n    \"author\": \"Alex\",\n    \"email\": \"alex@my.email\",\n    \"message\": \"I love the article.\"\n}' 'http://localhost:4000/api/v1/comments/\n```\n\n##### Success response\n\n``` json\n{\n  \"updated\": true,\n  \"id\": 1234\n}\n```\n\n##### Fail response\n\n\n``` json\n{\n  \"updated\": false,\n  \"id\": 1234\n}\n```\n\n\n#### Delete Comment\n\nDelete a comment for ID. [Authorization required](#authorization).\n\n**Method**: `DELETE`\n\n``` sh\n/api/v1/comments/{id}\n```\n\n| Param | Value | Description |\n|---|---|---|\n| id  | number | Comment ID. |\n\n##### Example\n\nDelete comment with id `1234`.\n\n``` sh\ncurl -XDELETE -H \"Authorization: Bearer mysecret\" -H \"Content-type: application/json\" http://localhost:4000/api/v1/comments/1234\n```\n\n##### Success response\n\n``` json\n{\n  \"deleted\": true,\n  \"id\": 1234\n}\n```\n\n##### Fail response\n\n\n``` json\n{\n  \"deleted\": false,\n  \"id\": 1234\n}\n```\n#### Search Threads\n\nSearch for all urls containing a certain string ignoring uppercase. [Authorization required](#authorization).\n\n**Method**: `POST`\n\n``` sh\n/api/v1/threads/search/{query}\n```\n\n| Param | Value | Description |\n|---|---|---|\n| query  | string | String to search. |\n\n##### Example\n\nSearch all threads with  `tadam`.\n\n``` sh\ncurl -XPOST -H \"Authorization: Bearer mysecret\" 'http://localhost:4000/api/v1/threads/search/tadam'\n```\n\n##### Success response\n\n``` json\n[\n  {\n    \"thread\": \"https://my.blog/tadam-vs-pedestal/\"\n  },\n  {\n    \"thread\": \"https://my.blog/best-web-framework-clojure-tadam\"\n  }\n]\n```\n\n##### Fail response\n\n\n``` json\n[]\n```\n\n---\n\n## Terminal cli\n\nTo **manage some minor features** you can use the `manager` script which will filter, modify or delete the database. Previously **remember to stop Glosa** to avoid problems.\n\nYou will need to have **Node installed** on your computer and give it **permission to run**.\n\n### Last comments\n\n``` sh\n./manager last [number of elements]\n```\n\nExample\n\n``` sh\n./manager last 3\n```\n\n### Take all comments by thread\n\n``` sh\n./manager get [thread]\n```\n\nExample\n\n``` sh\n./manager get https://glosa.example/best-SO/\n```\n\n### Update the text of a comment\n\n``` sh\n./manager update [id] [new message]\n```\n\nExample\n\n``` sh\n./manager update 1234 'I love your article.'\n```\n\n### Delete a comment\n\n``` sh\n./manager delete [id]\n```\n\nExample\n\n``` sh\n./manager delete 1234\n```\n\n## Deployment\n\nWith Nginx it's pretty quick and easy. You can use it as a reverse proxy, since Glosa contains its own web server (Jetty). You can see an example of configuration that can be useful.\n\n### Nginx\n\n``` nginx\nserver {        \n\n        server_name glosa.domain.com;\n\n        access_log /var/log/glosa_access.log;\n        error_log /var/log/glosa_error.log;\n\n        location / {\n            proxy_pass http://localhost:4000/;\n            proxy_set_header Host $http_host;\n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n            proxy_set_header X-Forwarded-Proto $scheme;\n            proxy_redirect  off;\n        }\n}\n```\n\n### Systemctl\n\nTo create a service in Linux is done like any application in Java. Below you can see an example.\n\nCreate a file in the following path: `/etc/systemd/system/glosa.service`\n\nAdd the content.\n\n``` Systemctl\n[Unit]\nDescription=Glosa\nAfter=network.target\n\n[Service]\nType=simple\nRestart=always\nWorkingDirectory=/folder/jar/\nExecStart=java -jar glosa.jar\n\n[Install]\nWantedBy=multi-user.target \n```\n\nFinally enable and start the service.\n\n``` sh\nsudo systemctl enable glosa\nsudo systemctl start glosa\n```\n\n## Create your own JAR\n\n1) Make sure you have **openjdk** or **oracle-jdk** installed, **clojure** and  **leiningen**.\n\n### MacOS\n\n``` sh\nbrew install openjdk clojure leiningen\n```\n\n### Debian/Ubuntu\n\n``` sh\nsudo apt install default-jdk clojure leiningen\n```\n\n2) Clone the repository and enter the generated folder.\n\n``` sh\ngit clone https://github.com/glosa/glosa-server.git\ncd glosa-server\n```\n\n3) Run the following command to build a `jar` file.\n\n`lein uberjar`\n\nAfter this two files should be created in `target/`. We will use the standalone version: `glosa-{version}-standalone.jar`.\n\n---\n\n## Dev tools\n\nIt needs to be executed at the root of the project and have `Leiningen` installed.\n\n### Lint\n\nIt checks linguistically and syntaxically if the code is correct.\n\n``` shell\nmake lint\n```\n\n### Build\n\nBuild a JAR ready to distribute.\n\n``` shell\nmake build\n```\n\n### Deploy\n\nDistributed in Clojars.\n\n``` shell\nmake deploy\n```\n\n---\n\n\u003cp align=\"center\"\u003e\n  Thanks to the power of \u003ca href=\"https://www.tadam-framework.dev/\"\u003e\u003cimg src=\"https://avatars3.githubusercontent.com/u/54397807?s=50\u0026v=4\" alt=\"logo\" width=\"50\"\u003e Tadam Framework\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglosa%2Fglosa-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fglosa%2Fglosa-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglosa%2Fglosa-server/lists"}