Compare commits

...

181 commits

Author SHA1 Message Date
bca1d919b2 add alertmanager formatter 2025-01-21 10:26:07 -05:00
8e1a0894f3 docs: updates to config-dist.yaml 2023-01-17 14:11:28 -05:00
86f49edf3d docs: basic readme change from the upstream version 2023-01-17 13:36:50 -05:00
fc1552304f add whitelist check to AbuseIPDB check 2022-12-08 20:29:01 -05:00
66df6e56e2 Add abuseipdb lookup to link, fix differences in version running in prod 2022-12-02 18:03:25 -05:00
05eeab7c9c add abuseipdb and crowdsec cti links for IP 2022-12-02 11:20:30 -05:00
33a650efda remove github stuff that I didn't set up for my fork 2022-11-29 22:25:51 -05:00
eb0231f4ba add pyyaml dep 2022-11-29 22:22:30 -05:00
7ff165a6f7 add crowdsec formatter 2022-11-29 22:12:42 -05:00
3c2b2d346c add package*.json 2022-11-29 22:11:08 -05:00
6e05a2a3f9 merge upstream formatter for grafana_9x 2022-11-29 22:09:11 -05:00
6781f994f9 merge upstream changes 2022-11-29 22:08:43 -05:00
Guilhem Saurel
7ba365d6e8
Merge pull request #54 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-11-29 09:03:21 +01:00
pre-commit-ci[bot]
347f639422
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.4.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.4.0)
- [github.com/PyCQA/flake8: 5.0.4 → 6.0.0](https://github.com/PyCQA/flake8/compare/5.0.4...6.0.0)
2022-11-28 20:10:31 +00:00
Guilhem Saurel
e8fcb07205
Merge pull request #52 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-11-14 21:20:49 +01:00
pre-commit-ci[bot]
6cc4a7cfd9
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.2.0 → v3.2.2](https://github.com/asottile/pyupgrade/compare/v3.2.0...v3.2.2)
2022-11-14 19:25:31 +00:00
Guilhem Saurel
e963478986
Merge pull request #51 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-10-31 22:25:26 +01:00
pre-commit-ci[bot]
2ac1f123fd
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.1.0 → v3.2.0](https://github.com/asottile/pyupgrade/compare/v3.1.0...v3.2.0)
2022-10-31 19:21:12 +00:00
Guilhem Saurel
37def41cc8
Merge pull request #50 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-10-17 21:34:28 +02:00
pre-commit-ci[bot]
1dc9d79a3b
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.0.0 → v3.1.0](https://github.com/asottile/pyupgrade/compare/v3.0.0...v3.1.0)
2022-10-17 19:11:40 +00:00
Guilhem Saurel
07f3bd4714 fix ci cache 2022-10-17 10:40:09 +02:00
Guilhem Saurel
3017fb255a ci: cache poetry 2022-10-17 10:20:23 +02:00
Guilhem Saurel
97b842a20e
Merge pull request #49 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-10-10 22:10:05 +02:00
pre-commit-ci[bot]
962812758b
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.8.0 → 22.10.0](https://github.com/psf/black/compare/22.8.0...22.10.0)
- [github.com/asottile/pyupgrade: v2.38.2 → v3.0.0](https://github.com/asottile/pyupgrade/compare/v2.38.2...v3.0.0)
2022-10-10 19:35:08 +00:00
Guilhem Saurel
67ffd334e3 poetry update 2022-10-01 09:56:47 +02:00
Guilhem Saurel
5140df64c6
Merge pull request #48 from nim65s/dependabot/pip/matrix-nio-0.20.0
build(deps): bump matrix-nio from 0.18.7 to 0.20.0
2022-10-01 09:44:51 +02:00
dependabot[bot]
eb28e99aa9
build(deps): bump matrix-nio from 0.18.7 to 0.20.0
Bumps [matrix-nio](https://github.com/poljar/matrix-nio) from 0.18.7 to 0.20.0.
- [Release notes](https://github.com/poljar/matrix-nio/releases)
- [Changelog](https://github.com/poljar/matrix-nio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/poljar/matrix-nio/compare/0.18.7...0.20.0)

---
updated-dependencies:
- dependency-name: matrix-nio
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-30 22:59:18 +00:00
Guilhem Saurel
c251d1c9cb
Merge pull request #47 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-09-27 11:14:27 +02:00
pre-commit-ci[bot]
8fac0e1a5d
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.38.0 → v2.38.2](https://github.com/asottile/pyupgrade/compare/v2.38.0...v2.38.2)
2022-09-26 19:09:45 +00:00
Guilhem Saurel
272a427034
Merge pull request #46 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-09-21 14:58:15 +02:00
pre-commit-ci[bot]
7915e78d87
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.37.3 → v2.38.0](https://github.com/asottile/pyupgrade/compare/v2.37.3...v2.38.0)
2022-09-19 19:10:39 +00:00
Guilhem Saurel
efdfd3a2db Release v3.5.0 2022-09-07 18:45:41 +02:00
Guilhem Saurel
5b7067f382 bump some tools 2022-09-07 18:20:59 +02:00
Guilhem Saurel
228f38f101 poetry update 2022-09-07 18:18:34 +02:00
Guilhem Saurel
1fb1a0b8f3 add #45 to CHANGELOG 2022-09-07 18:16:37 +02:00
Guilhem Saurel
880832275b
Merge pull request #45 from svenseeberg/bugfix/grafana-9x-formatting
Support Grafana v9.x messages, fixes #29
2022-09-07 18:14:41 +02:00
Sven Seeberg
e139c3a61b
Support Grafana v9.x messages, fixes #29 2022-09-07 17:45:32 +02:00
Guilhem Saurel
3288c3ff5a
Merge pull request #44 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-09-05 21:49:37 +02:00
pre-commit-ci[bot]
48b988efc0
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.6.0 → 22.8.0](https://github.com/psf/black/compare/22.6.0...22.8.0)
2022-09-05 19:11:44 +00:00
Guilhem Saurel
8f3a6a77ff
Merge pull request #43 from nim65s/dependabot/github_actions/codecov/codecov-action-3
build(deps): bump codecov/codecov-action from 1 to 3
2022-08-15 12:33:03 +02:00
dependabot[bot]
d25cfd3ba6
build(deps): bump codecov/codecov-action from 1 to 3
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 3.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1...v3)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-15 10:28:23 +00:00
Guilhem Saurel
bc858f8bac Release v3.4.0 2022-08-12 11:50:09 +02:00
Guilhem Saurel
13c7d0a431 add changelog to urls 2022-08-12 11:47:48 +02:00
Guilhem Saurel
c82ab8c5e0 docker: setup qemu & buildx 2022-08-12 11:46:01 +02:00
Guilhem Saurel
53dd300414 update changelog 2022-08-12 11:45:42 +02:00
Guilhem Saurel
1750a1fbed
Merge pull request #42 from nim65s/dependabot/github_actions/actions/checkout-3
build(deps): bump actions/checkout from 2 to 3
2022-08-12 11:41:56 +02:00
dependabot[bot]
807a1e7b99
build(deps): bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:39:52 +00:00
Guilhem Saurel
8632c87d4f
Merge pull request #39 from nim65s/dependabot/github_actions/actions/setup-python-4
build(deps): bump actions/setup-python from 2 to 4
2022-08-12 11:39:43 +02:00
Guilhem Saurel
5905136919
Merge pull request #41 from nim65s/dependabot/github_actions/docker/login-action-2
build(deps): bump docker/login-action from 1 to 2
2022-08-12 11:39:30 +02:00
Guilhem Saurel
776ebb67c2
Merge pull request #40 from nim65s/dependabot/github_actions/docker/metadata-action-4
build(deps): bump docker/metadata-action from 3 to 4
2022-08-12 11:39:26 +02:00
Guilhem Saurel
0ef10cc620
Merge pull request #38 from nim65s/dependabot/github_actions/docker/build-push-action-3
build(deps): bump docker/build-push-action from 2 to 3
2022-08-12 11:39:19 +02:00
dependabot[bot]
93211f33c7
build(deps): bump docker/login-action from 1 to 2
Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 2.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:35:26 +00:00
dependabot[bot]
7e3983626d
build(deps): bump docker/metadata-action from 3 to 4
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 3 to 4.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md)
- [Commits](https://github.com/docker/metadata-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:35:23 +00:00
dependabot[bot]
8127e52fc7
build(deps): bump actions/setup-python from 2 to 4
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2 to 4.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:35:20 +00:00
dependabot[bot]
d49bd60403
build(deps): bump docker/build-push-action from 2 to 3
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 3.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-12 09:35:17 +00:00
Guilhem Saurel
940cfd9bd3 add dependabot to update actions 2022-08-12 11:34:57 +02:00
Guilhem Saurel
2d17e00ec5
Merge pull request #37 from kusold/patch-1
Add linux/arm64 platform to docker builds
2022-08-12 11:32:45 +02:00
Mike Kusold
9ca48a083e
Add linux/arm64 platform to docker builds
Publishes linux/arm64 docker images.

Relevant documentation: https://github.com/docker/build-push-action/blob/master/docs/advanced/multi-platform.md
2022-08-11 23:05:47 -06:00
Guilhem Saurel
8c59d2412e
Merge pull request #36 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-08-08 21:03:23 +02:00
pre-commit-ci[bot]
d7bcc786b0
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/flake8: 5.0.2 → 5.0.4](https://github.com/PyCQA/flake8/compare/5.0.2...5.0.4)
2022-08-08 19:00:42 +00:00
Guilhem Saurel
a7104ac2a0 details 2022-08-05 20:27:41 +02:00
Guilhem Saurel
152c80b3ff typo 2022-08-05 20:25:00 +02:00
Guilhem Saurel
ac4e00b54a badges 2022-08-05 20:19:46 +02:00
Guilhem Saurel
760e5cbb15
Merge pull request #35 from nim65s/script
Script
2022-08-02 09:06:06 +02:00
Guilhem Saurel
2ca7201346 poetry update 2022-08-02 00:08:30 +02:00
Guilhem Saurel
6c7d015b8d add missing docstring 2022-08-01 23:59:20 +02:00
Guilhem Saurel
50e93180ee test scripts 2022-08-01 23:51:29 +02:00
Guilhem Saurel
7b9605a363 document scripts 2022-08-01 23:51:29 +02:00
Albrecht Muehlenschulte
29653fc04b adds script 2022-08-01 23:51:29 +02:00
Guilhem Saurel
0ab2507009
Merge pull request #34 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-08-01 23:39:37 +02:00
Guilhem Saurel
dd20888af4 Merge branch 'master' into pre-commit-ci-update-config 2022-08-01 23:38:08 +02:00
Guilhem Saurel
0819503d8b fix tests 2022-08-01 23:34:34 +02:00
pre-commit-ci[bot]
2fa2557076
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/flake8: 4.0.1 → 5.0.2](https://github.com/PyCQA/flake8/compare/4.0.1...5.0.2)
- [github.com/asottile/pyupgrade: v2.37.2 → v2.37.3](https://github.com/asottile/pyupgrade/compare/v2.37.2...v2.37.3)
2022-08-01 19:11:04 +00:00
Guilhem Saurel
52b5ff87ea
Merge pull request #33 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-07-26 00:28:18 +02:00
pre-commit-ci[bot]
36b5e85f7e
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.37.1 → v2.37.2](https://github.com/asottile/pyupgrade/compare/v2.37.1...v2.37.2)
2022-07-25 18:37:12 +00:00
Guilhem Saurel
7f2ba3d83b
Merge pull request #31 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-07-12 00:16:55 +02:00
pre-commit-ci[bot]
363f8a497d
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.34.0 → v2.37.1](https://github.com/asottile/pyupgrade/compare/v2.34.0...v2.37.1)
2022-07-11 18:33:45 +00:00
Guilhem Saurel
d53ab56661
Merge pull request #30 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-07-04 22:39:28 +02:00
pre-commit-ci[bot]
8469e679b3
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.3.0 → 22.6.0](https://github.com/psf/black/compare/22.3.0...22.6.0)
2022-07-04 18:49:48 +00:00
Guilhem Saurel
90cc262a73
Merge pull request #28 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-06-13 20:51:58 +02:00
pre-commit-ci[bot]
8e3f4e5771
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.2.0 → v4.3.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.2.0...v4.3.0)
- [github.com/asottile/pyupgrade: v2.32.1 → v2.34.0](https://github.com/asottile/pyupgrade/compare/v2.32.1...v2.34.0)
2022-06-13 18:44:41 +00:00
Guilhem Saurel
8c63736879
Merge pull request #27 from nim65s/dependabot/pip/httpx-0.23.0
Bump httpx from 0.18.2 to 0.23.0
2022-06-02 10:09:41 +02:00
dependabot[bot]
baa20e51eb
Bump httpx from 0.18.2 to 0.23.0
Bumps [httpx](https://github.com/encode/httpx) from 0.18.2 to 0.23.0.
- [Release notes](https://github.com/encode/httpx/releases)
- [Changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/httpx/compare/0.18.2...0.23.0)

---
updated-dependencies:
- dependency-name: httpx
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 23:59:44 +00:00
Guilhem Saurel
f1d2d2bd68
Merge pull request #26 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-05-10 20:03:31 +02:00
pre-commit-ci[bot]
70d85af682
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.32.0 → v2.32.1](https://github.com/asottile/pyupgrade/compare/v2.32.0...v2.32.1)
2022-05-09 18:10:56 +00:00
Guilhem Saurel
395daf4630 poetry update 2022-05-06 16:28:10 +02:00
Guilhem Saurel
8d81b7ba44
Merge pull request #24 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-04-11 20:34:44 +02:00
pre-commit-ci[bot]
36b3f6f877
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.1.0 → v4.2.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.1.0...v4.2.0)
- [github.com/asottile/pyupgrade: v2.31.1 → v2.32.0](https://github.com/asottile/pyupgrade/compare/v2.31.1...v2.32.0)
2022-04-11 18:30:34 +00:00
Guilhem Saurel
e9b3f83cd1
Merge pull request #23 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-04-04 21:50:04 +02:00
pre-commit-ci[bot]
916ddb7d18
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.1.0 → 22.3.0](https://github.com/psf/black/compare/22.1.0...22.3.0)
2022-04-04 18:04:37 +00:00
Guilhem Saurel
bdd3940066
Merge pull request #22 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-03-14 21:18:18 +01:00
pre-commit-ci[bot]
5bc8f81d8e
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.31.0 → v2.31.1](https://github.com/asottile/pyupgrade/compare/v2.31.0...v2.31.1)
2022-03-14 19:46:21 +00:00
Guilhem Saurel
11ee2ec2f4 Release v3.3.0 2022-03-04 00:36:46 +01:00
Guilhem Saurel
b66b9717e4 pyupgrade 2022-03-04 00:13:57 +01:00
Guilhem Saurel
c4e0bb76e9 poetry update 2022-03-04 00:11:35 +01:00
Guilhem Saurel
14398e4b7d changelog 2022-03-04 00:06:32 +01:00
Guilhem Saurel
42317f74d9
Merge pull request #21 from GhislainC/master
Add gitlab formatter
2022-03-04 00:05:11 +01:00
Ghislain Chatras
f6bf150c7f
Add gitlab formatter
Only for Google Chat and Microsoft Teams notification integrations
2022-03-03 19:17:40 +01:00
Guilhem Saurel
e91865f175
Merge pull request #19 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-02-10 17:25:15 +01:00
pre-commit-ci[bot]
a3607c5ee2
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.0.1 → v4.1.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.0.1...v4.1.0)
- [github.com/psf/black: 21.12b0 → 22.1.0](https://github.com/psf/black/compare/21.12b0...22.1.0)
2022-01-31 18:21:12 +00:00
f4808719b0 refactor(formatter/pingdom): build message content line-by-line
feat(formatter/pingdom): add tags to output (if set)
2022-01-12 12:08:53 -05:00
8c18c2054e refactor(formatter/buildbot): cleanup redundancy in logic 2022-01-11 22:22:20 -05:00
97e10df1a2 docs: format cleanup 2021-12-14 23:19:51 -05:00
630dc98974
docs: cleanup formatters as a table 2021-12-14 23:17:15 -05:00
7b94c80bbd docs: add buildbot and generic formatter details 2021-12-14 22:58:30 -05:00
5048ef8c4c
Merge branch 'nim65s:master' into master 2021-12-11 23:28:15 -05:00
Guilhem Saurel
ff10e58cba
Merge pull request #18 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-12-06 19:13:49 +01:00
pre-commit-ci[bot]
6032dfe836
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.11b1 → 21.12b0](https://github.com/psf/black/compare/21.11b1...21.12b0)
2021-12-06 17:55:15 +00:00
affe16c605 fix(buildbot): add else to handle non start/success statuses 2021-12-01 23:44:59 -05:00
92b6c3618b
Merge branch 'nim65s:master' into master 2021-12-01 23:37:48 -05:00
0c8c5faad0 feat(buildbot): add buildbot formatter 2021-12-01 23:36:57 -05:00
Guilhem Saurel
d799fc18a0
Merge pull request #17 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-11-25 16:05:21 +01:00
pre-commit-ci[bot]
0ac65ba895
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.10b0 → 21.11b1](https://github.com/psf/black/compare/21.10b0...21.11b1)
2021-11-22 17:47:55 +00:00
e42aa941e5 feat: add room to api config 2021-11-09 08:57:46 -05:00
778ebcdad9 feat: add slack formatter 2021-11-09 01:41:44 -05:00
e0a407acd9 feat: add generic formatter that will just return json sent 2021-11-09 01:41:26 -05:00
93f84859b4 feat: add config file handling 2021-11-05 10:01:32 -04:00
b5912a8b6c tests: add pingdom test and supporting json examples 2021-11-05 10:00:17 -04:00
d964f75c84 fix: correct missed envar for api_keys 2021-11-04 13:58:12 -04:00
a3638fdc75 update changelog 2021-11-04 13:51:42 -04:00
ab5927bfa4 feat(conf)!: allow multiple keys to be used for different endpoints 2021-11-04 13:26:54 -04:00
8e5a90ec1f refactor: clean-up 'weird' formatting 2021-11-04 00:17:24 -04:00
87ac023631 fix: correct except clauses missing exceptions 2021-11-03 23:42:44 -04:00
1ea47991e4 fix: correct exception case for invalid formatter module 2021-11-03 17:05:45 -04:00
0d92c378c4 feat: breakout formatters into their own plugin-like module to ease additonal formatters 2021-11-03 17:02:22 -04:00
d82a0ba9bd first attempt at this disaster 2021-11-03 16:12:52 -04:00
793a5e8c8c fix: correct missing colon on try 2021-11-03 15:51:05 -04:00
09fe26633f add basic functionality for pingdom formatter 2021-11-03 00:19:52 -04:00
Guilhem Saurel
afd68b791c
Merge pull request #16 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-11-02 08:38:07 +01:00
pre-commit-ci[bot]
b3004a5c8a
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.9b0 → 21.10b0](https://github.com/psf/black/compare/21.9b0...21.10b0)
2021-11-01 17:37:21 +00:00
Guilhem Saurel
2a78594861 handle M_CONSENT_NOT_GIVEN, fix #15 2021-10-12 16:23:24 +02:00
Guilhem Saurel
5a5e9655be
Merge pull request #14 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-10-11 20:41:05 +02:00
pre-commit-ci[bot]
ea91eea7ee
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/flake8: 3.9.2 → 4.0.1](https://github.com/PyCQA/flake8/compare/3.9.2...4.0.1)
2021-10-11 17:23:48 +00:00
Guilhem Saurel
e148dfbad9 update README after #12 2021-09-28 11:05:32 +02:00
Guilhem Saurel
b3a2e00f43 comments 2021-09-28 10:58:32 +02:00
Guilhem Saurel
d0481d741a update changelog after #12 2021-09-28 10:54:10 +02:00
Guilhem Saurel
85dd602f5c
Merge pull request #12 from bboehmke/join-room
join room before sending message
2021-09-28 10:50:27 +02:00
Guilhem Saurel
d2a3e618f4 join room: fix error code & unit tests 2021-09-28 10:39:41 +02:00
Guilhem Saurel
d9fe01c1db
Merge pull request #13 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-09-27 20:35:33 +02:00
pre-commit-ci[bot]
5d39019ef7
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.8b0 → 21.9b0](https://github.com/psf/black/compare/21.8b0...21.9b0)
2021-09-20 17:21:38 +00:00
Benjamin Böhmke
7ffa47c267 join room before sending message 2021-09-18 12:20:57 +02:00
Guilhem Saurel
624a1b2c08 grafana formatter: smaller titles 2021-09-13 17:03:57 +02:00
Guilhem Saurel
6c5b3e1358 pre-commit: drop useless checks 2021-09-12 16:00:38 +02:00
Guilhem Saurel
df2059b012 docker: use image from docker hub 2021-09-12 15:55:10 +02:00
Guilhem Saurel
d0c4cd4227 formatters: fix github format 2021-09-12 15:55:10 +02:00
Guilhem Saurel
7aa5df3871 readme: detail 2021-09-12 15:55:10 +02:00
Guilhem Saurel
e5f3d7bfbd
Merge pull request #11 from nim65s/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-09-12 15:54:03 +02:00
pre-commit-ci[bot]
ef79d39a9f
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.7b0 → 21.8b0](https://github.com/psf/black/compare/21.7b0...21.8b0)
2021-08-30 17:11:56 +00:00
Guilhem Saurel
179ef11ae7 readme: typo 2021-08-28 00:18:42 +02:00
Guilhem Saurel
8592be257f badges: new line 2021-08-28 00:15:41 +02:00
Guilhem Saurel
0aea63903d badges: add PyPI 2021-08-28 00:11:30 +02:00
Guilhem Saurel
df8ce523cb fix changelog 2021-08-28 00:08:56 +02:00
Guilhem Saurel
58d0e83f8f Release v3.2.1 2021-08-28 00:07:36 +02:00
Guilhem Saurel
d726db6ed2 release: push 2021-08-28 00:07:30 +02:00
Guilhem Saurel
1c00ff22f3 fix changelog 2021-08-28 00:06:38 +02:00
Guilhem Saurel
7e1be831df ci: detail 2021-08-28 00:05:20 +02:00
Guilhem Saurel
7f5c8583a1 Release v3.2.0 2021-08-27 23:59:56 +02:00
Guilhem Saurel
4928ceb91a release: details 2021-08-27 23:59:49 +02:00
Guilhem Saurel
cda8898019 tests: improve coverage 2021-08-27 23:56:56 +02:00
Guilhem Saurel
6b5d6e6e87 formatters: add github 2021-08-27 23:47:07 +02:00
Guilhem Saurel
4bcdb25c80 formatters: also get headers 2021-08-27 20:05:08 +02:00
Guilhem Saurel
ac7d1d9647 typo 2021-08-27 18:39:28 +02:00
Guilhem Saurel
9a544b8f2b detail 2021-08-27 18:33:18 +02:00
Guilhem Saurel
8f215c04fd docs: release 2021-08-27 18:33:18 +02:00
Guilhem Saurel
7f20fb7ff9 split code in utils / handler / app 2021-08-27 18:33:18 +02:00
Guilhem Saurel
2b7b79971d lint: fix pydocstyle 2021-08-27 18:15:58 +02:00
Guilhem Saurel
6aaac9149d lint: pre-commit autoupdate 2021-08-27 18:15:58 +02:00
Guilhem Saurel
eb3c795368 lint: fix line length 2021-08-27 18:15:58 +02:00
Guilhem Saurel
c03ae0a571 lint: add flake8 configuration
Black allows up to 88 characters per line.

Put this configuration into a separated file, as pyproject.toml won't do
ref. https://github.com/PyCQA/flake8/issues/234
2021-08-27 18:15:58 +02:00
Guilhem Saurel
eabb446d05 ci: release also on github 2021-08-27 18:15:55 +02:00
Guilhem Saurel
6f7d38dbd7 update test for latest synapse docker image 2021-08-27 18:14:54 +02:00
Guilhem Saurel
530f40a129 setup action to publish releases on github 2021-08-07 17:54:39 +02:00
Guilhem Saurel
528940abcc fix changelog 2021-08-07 17:54:36 +02:00
Guilhem Saurel
0ccec84eef room_id can come from url, content, or parameters 2021-08-01 13:20:03 +02:00
Guilhem Saurel
c8f6c9ec28 README: document grafana usage 2021-08-01 13:20:03 +02:00
Guilhem Saurel
c07d4bfa8d add tests for grafana formatter 2021-08-01 13:20:03 +02:00
Guilhem Saurel
2d232fe1f7 add grafana formatter
This was initially designed and implemented in #4

Co-authored-by: Sven Seeberg <mail@sven-seeberg.de>
2021-08-01 13:19:58 +02:00
Guilhem Saurel
3bebc88ee2 allow direct formatted_body
This was initially designed and implemented in #6

Co-authored-by: Gerhard Bräunlich <gerhard.braeunlich@id.ethz.ch>
2021-08-01 13:19:53 +02:00
Guilhem Saurel
fa8f9b4a51 allow "key" to be passed as a parameter
This was initially designed and implemented in #4

Co-authored-by: Sven Seeberg <mail@sven-seeberg.de>
2021-08-01 13:19:39 +02:00
Guilhem Saurel
292d77274d update "text" key to "body" 2021-07-31 11:21:29 +02:00
Guilhem Saurel
8b32c972b8 typo 2021-07-18 23:08:40 +02:00
50 changed files with 4596 additions and 736 deletions

2
.flake8 Normal file
View file

@ -0,0 +1,2 @@
[flake8]
max-line-length = 88

View file

@ -1,28 +0,0 @@
name: Publish
on:
push:
branches:
- 'master'
tags:
- 'v*'
jobs:
docker-hub:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: docker/metadata-action@v3
id: meta
with:
images: nim65s/matrix-webhook
- uses: docker/login-action@v1
with:
username: nim65s
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

View file

@ -1,8 +0,0 @@
name: Lints
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: psf/black@stable

View file

@ -1,15 +0,0 @@
name: PyPI
on:
push:
tags:
- 'v*'
jobs:
pypi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: pip install -U poetry twine wheel
- run: poetry build
- run: twine upload --non-interactive -u __token__ -p ${{ secrets.PYPI_TOKEN }} dist/*

View file

@ -1,9 +0,0 @@
name: Tests
on: [push, pull_request]
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: docker-compose -f test.yml up --exit-code-from tests
- uses: codecov/codecov-action@v1

2
.gitignore vendored
View file

@ -3,3 +3,5 @@
.mypy_cache
coverage.xml
htmlcov
**__pycache__
config.yaml

View file

@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-ast
@ -14,7 +14,7 @@ repos:
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 21.6b0
rev: 22.10.0
hooks:
- id: black
language_version: python3
@ -22,12 +22,15 @@ repos:
rev: 6.1.1
hooks:
- id: pydocstyle
args:
- --ignore=D200,D203,D212
- repo: https://github.com/PyCQA/flake8
rev: 3.9.2
rev: 6.0.0
hooks:
- id: flake8
- repo: https://gitlab.com/smop/pre-commit-hooks
rev: v1.0.0
- repo: https://github.com/asottile/pyupgrade
rev: v3.2.2
hooks:
- id: check-poetry
- id: check-gitlab-ci
- id: pyupgrade
args:
- --py38-plus

View file

@ -6,13 +6,67 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [3.1.0] - 2021-07-18
## [v3.5.0] - 2022-09-07
- Add formatter for grafana 9
in [#45](https://github.com/nim65s/matrix-webhook/pull/45)
by [@svenseeberg](https://github.com/svenseeberg)
## [v3.4.0] - 2022-08-12
- fix tests
- add `matrix-webhook` script
in [#25](https://github.com/nim65s/matrix-webhook/pull/25)
and [#35](https://github.com/nim65s/matrix-webhook/pull/35)
by [@a7p](https://github.com/a7p)
- publish linux/arm64 image
in [#37](https://github.com/nim65s/matrix-webhook/pull/35)
by [@kusold](https://github.com/kusold)
- update badges
- setup dependabot
- misc upgrades from poetry update, pre-commit.ci, and dependabot
## [v3.3.0] - 2022-03-04
- add pyupgrade
- add gitlab formatter for google chat & microsoft teams
in [#21](https://github.com/nim65s/matrix-webhook/pull/21)
by [@GhislainC](https://github.com/GhislainC)
- join room before sending message
in [#12](https://github.com/nim65s/matrix-webhook/pull/12)
by [@bboehmke](https://github.com/bboehmke)
- Changed --api-key and envvar API_KEY to --api-keys and API_KEYS respectively
- Changed handling of api key to use a list instead of single value
can be used
- Changed the formatters to a more plugin-based approach where each formatter is
its own <formattername>.py file in formatters directory
- Added pingdom formatter (currently handling http, dns, and tcp probe types)
## [v3.2.1] - 2021-08-28
- fix changelog
## [v3.2.0] - 2021-08-27
- add github & grafana formatters
- add formatted_body to bypass markdown with direct
[matrix-custom-HTML](https://matrix.org/docs/spec/client_server/r0.6.1#m-room-message-msgtypes)
- allow "key" to be passed as a parameter
- allow to use a sha256 HMAC hex digest with the key instead of the raw key
- allow "room_id" to be passed as a parameter or with the data
- rename "text" to "body".
- Publish releases also on github from github actions
- fix tests for recent synapse docker image
## [v3.1.1] - 2021-07-18
## [v3.1.0] - 2021-07-18
- Publish on PyPI & Docker Hub with Github Actions
in [#10](https://github.com/nim65s/matrix-webhook/pull/10)
by [@nim65s](https://github.com/)
by [@nim65s](https://github.com/nim65s)
## [3.0.0] - 2021-07-18
## [v3.0.0] - 2021-07-18
- Simplify code
in [#1](https://github.com/nim65s/matrix-webhook/pull/1)
@ -30,12 +84,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
in [#9](https://github.com/nim65s/matrix-webhook/pull/9)
by [@nim65s](https://github.com/nim65s)
## [2.0.0] - 2020-03-14
## [v2.0.0] - 2020-03-14
- Update to matrix-nio & aiohttp & markdown
## [1.0.0] - 2020-02-14
## [v1.0.0] - 2020-02-14
- First release with matrix-client & http.server
[Unreleased]: https://github.com/nim65s/matrix-webhook/compare/v2.0.0...devel
[2.0.0]: https://github.com/nim65s/matrix-webhook/compare/v1.0.0...v2.0.0
[1.0.0]: https://github.com/nim65s/matrix-webhook/releases/tag/v1.0.0
[Unreleased]: https://github.com/nim65s/matrix-webhook/compare/v3.5.0...master
[v3.5.0]: https://github.com/nim65s/matrix-webhook/compare/v3.4.0...v3.5.0
[v3.4.0]: https://github.com/nim65s/matrix-webhook/compare/v3.3.0...v3.4.0
[v3.3.0]: https://github.com/nim65s/matrix-webhook/compare/v3.2.1...v3.3.0
[v3.2.1]: https://github.com/nim65s/matrix-webhook/compare/v3.2.0...v3.2.1
[v3.2.0]: https://github.com/nim65s/matrix-webhook/compare/v3.1.1...v3.2.0
[v3.1.1]: https://github.com/nim65s/matrix-webhook/compare/v3.1.0...v3.1.1
[v3.1.0]: https://github.com/nim65s/matrix-webhook/compare/v3.0.0...v3.1.0
[v3.0.0]: https://github.com/nim65s/matrix-webhook/compare/v2.0.0...v3.0.0
[v2.0.0]: https://github.com/nim65s/matrix-webhook/compare/v1.0.0...v2.0.0
[v1.0.0]: https://github.com/nim65s/matrix-webhook/releases/tag/v1.0.0

View file

@ -1,51 +1,55 @@
# Matrix Webhook
[![Tests](https://github.com/nim65s/matrix-webhook/actions/workflows/test.yml/badge.svg)](https://github.com/nim65s/matrix-webhook/actions/workflows/test.yml)
[![Lints](https://github.com/nim65s/matrix-webhook/actions/workflows/lint.yml/badge.svg)](https://github.com/nim65s/matrix-webhook/actions/workflows/lint.yml)
[![Docker-Hub](https://github.com/nim65s/matrix-webhook/actions/workflows/docker-hub.yml/badge.svg)](https://hub.docker.com/r/nim65s/matrix-webhook)
[![PyPI](https://github.com/nim65s/matrix-webhook/actions/workflows/pypi.yml/badge.svg)](https://pypi.org/project/matrix-webhook/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![codecov](https://codecov.io/gh/nim65s/matrix-webhook/branch/master/graph/badge.svg?token=BLGISGCYKG)](https://codecov.io/gh/nim65s/matrix-webhook)
Post a message to a matrix room with a simple HTTP POST
This is my own fork of https://github.com/nim65s/matrix-webhook
It adds a yaml configuration with multi-api key endpoints and moves the filtes
to more of a plugin-based system
## Install
```
python3 -m pip install matrix-webhook
# OR
docker pull nim65s/matrix-webhook
```
For now, clone this repo and run `pip install .`
## Start
Create a matrix user for the bot, make it join the rooms you want it to talk into, and launch it with the following
arguments or environment variables:
Create a matrix user for the bot, and launch this app with the following arguments and/or environment variables
(environment variables update defaults, arguments take precedence):
```
matrix-webhook -h
# OR
python -m matrix_webhook -h
# OR
docker run --rm -it nim65s/matrix-webhook -h
```
```
usage: python -m matrix_webhook [-h] [-H HOST] [-P PORT] [-u MATRIX_URL] -i MATRIX_ID -p MATRIX_PW -k API_KEY [-v]
usage: python -m matrix_webhook [-h] [-H HOST] [-P PORT] [-u MATRIX_URL]
[-i MATRIX_ID] [-p MATRIX_PW] [-k API_KEYS]
[-c CONFIG] [-v]
Configuration for Matrix Webhook.
optional arguments:
options:
-h, --help show this help message and exit
-H HOST, --host HOST host to listen to. Default: `''`. Environment variable: `HOST`
-P PORT, --port PORT port to listed to. Default: 4785. Environment variable: `PORT`
-H HOST, --host HOST host to listen to. Default: `''`. Environment
variable: `HOST`
-P PORT, --port PORT port to listed to. Default: 4785. Environment
variable: `PORT`
-u MATRIX_URL, --matrix-url MATRIX_URL
matrix homeserver url. Default: `https://matrix.org`. Environment variable: `MATRIX_URL`
matrix homeserver url. Default: `https://matrix.org`.
Environment variable: `MATRIX_URL`
-i MATRIX_ID, --matrix-id MATRIX_ID
matrix user-id. Required. Environment variable: `MATRIX_ID`
matrix user-id. Required. Environment variable:
`MATRIX_ID`
-p MATRIX_PW, --matrix-pw MATRIX_PW
matrix password. Required. Environment variable: `MATRIX_PW`
-k API_KEY, --api-key API_KEY
shared secret to use this service. Required. Environment variable: `API_KEY`
matrix password. Required. Environment variable:
`MATRIX_PW`
-k API_KEYS, --api-keys API_KEYS
comma separated list of shared secrets to use this
service. Required. Environment variable: `API_KEYS`
-c CONFIG, --config CONFIG
configuration file. Default: `config.yaml`
-v, --verbose increment verbosity level
```
@ -74,14 +78,42 @@ docker-compose up -d
## Test / Usage
```
curl -d '{"text":"new contrib from toto: [44](http://radio.localhost/map/#44)", "key": "secret"}' \
curl -d '{"body":"new contrib from toto: [44](http://radio.localhost/map/#44)", "key": "secret"}' \
'http://matrixwebhook.localhost/!DPrUlnwOhBEfYwsDLh:matrix.org'
```
(or localhost:4785 without docker)
### Formatters
These formatters will output custom messages depending on the specific formatter. Generally to set these up, on the remote provider you would create a webhook with `https://your.webhook.domain/?formatter=<formatter columun below>&api_key=<your apikey>`
| formatter | description | key location |
| -- | - | - |
| github | for github.com | in github JSON webhook settings as `secret` |
| grafana | for grafana | in webhook URL with `api_key=<yourkey>` |
| pingdom | for pingdom.com | in webhook URL with `api_key=<yourkey>` |
| buildbot | buildbot reporter | in webhook URL with `api_key=<yourkey>` or in master.cfg credentials header as `api_key` |
| generic | returns raw JSON that was recieved. For developing additional formatter plugins | in URL with api_key=<yourkey> |
For example, if your matrix-webhook was hosted at https://webhooks.example.com, and you were setting up pingdom and you have an api_key of "123", you would use the following URL for your webhook call from pingdom:
`https://webhooks.example.com/?formatter=pingdom&api_key=123`
### For Gitlab
At a group level, Gitlab does not permit to setup webhooks. A workaround consists to use Google
Chat or Microsoft Teams notification integration with a custom URL (Gitlab does not check if the url begins with the normal url of the service).
#### Google Chat
Add a Google Chat integration with an URL ending with `?formatter=gitlab_gchat&key=API_KEY`
#### Microsoft Teams
Add a Microsoft Teams integration with an URL ending with `?formatter=gitlab_teams&key=API_KEY`
## Test room
#matrix-webhook:tetaneutral.net](https://matrix.to/#/!DPrUlnwOhBEfYwsDLh:matrix.org?via=laas.fr&via=tetaneutral.net&via=aen.im)
[#matrix-webhook:tetaneutral.net](https://matrix.to/#/!DPrUlnwOhBEfYwsDLh:matrix.org)
## Unit tests

19
config-dist.yaml Normal file
View file

@ -0,0 +1,19 @@
hostname: localhost
port: 4785
# matrix-specific settings
matrix:
# URL of homeserver to connect
url: https://matrix.org
# user to connect to homserver as
id: username
# password for the user
pw: password
# keys to allow These should be random strings
# these could be generated with something like `openssl rand -hex 24`
# change these, you only need
api_keys:
RandomTextForKey: "!room_id:server.domain" # Can add a comment for what the key is used
secondRandomkey: "!a_different_room_id:server.domain"
thirdKey: #This one has no room specified, so it must be specified in the payload data or url
log:
level: debug

View file

@ -6,6 +6,7 @@ networks:
services:
bot:
image: nim65s/matrix-webhook
build: .
restart: unless-stopped
env_file:

18
docs/release.md Normal file
View file

@ -0,0 +1,18 @@
# Publish a new release
A github actions handle the build of the release archives, and push them to PyPI and Github Releases.
To trigger it, we just need to:
1. use poetry to update the version number
2. update the changelog
3. git commit
4. git tag
5. git push
6. git push --tags
For this, an helper script is provided:
```bash
./docs/release.sh [patch|minor|major|x.y.z]
```

22
docs/release.sh Executable file
View file

@ -0,0 +1,22 @@
#!/bin/bash -eux
# ./docs/release.sh [patch|minor|major|x.y.z]
[[ $(basename "$PWD") == docs ]] && cd ..
OLD=$(poetry version -s)
poetry version "$1"
NEW=$(poetry version -s)
DATE=$(date +%Y-%m-%d)
sed -i "/^## \[Unreleased\]/a \\\n## [v$NEW] - $DATE" CHANGELOG.md
sed -i "/^\[Unreleased\]/s/$OLD/$NEW/" CHANGELOG.md
sed -i "/^\[Unreleased\]/a [v$NEW]: https://github.com/nim65s/matrix-webhook/compare/v$OLD...v$NEW" CHANGELOG.md
git add pyproject.toml CHANGELOG.md
git commit -m "Release v$NEW"
git tag -s "v$NEW" -m "Release v$NEW"
git push
git push --tags

View file

@ -1,143 +1,15 @@
"""
Matrix Webhook.
Post a message to a matrix room with a simple HTTP POST
"""
import asyncio
import json
"""Matrix Webhook module entrypoint."""
import logging
from http import HTTPStatus
from signal import SIGINT, SIGTERM
from aiohttp import web
from markdown import markdown
from nio import AsyncClient
from nio.exceptions import LocalProtocolError
from nio.responses import RoomSendError
from . import conf
ERROR_MAP = {"M_FORBIDDEN": HTTPStatus.FORBIDDEN}
CLIENT = AsyncClient(conf.MATRIX_URL, conf.MATRIX_ID)
LOGGER = logging.getLogger("matrix-webhook")
from . import app, conf
async def handler(request):
"""
Coroutine given to the server, st. it knows what to do with an HTTP request.
This one handles a POST, checks its content, and forwards it to the matrix room.
"""
LOGGER.debug(f"Handling {request=}")
data = await request.read()
try:
data = json.loads(data.decode())
except json.decoder.JSONDecodeError:
return create_json_response(HTTPStatus.BAD_REQUEST, "Invalid JSON")
if not all(key in data for key in ["text", "key"]):
return create_json_response(
HTTPStatus.BAD_REQUEST, "Missing text and/or API key property"
)
if data["key"] != conf.API_KEY:
return create_json_response(HTTPStatus.UNAUTHORIZED, "Invalid API key")
room_id = request.path[1:]
content = {
"msgtype": "m.text",
"body": data["text"],
"format": "org.matrix.custom.html",
"formatted_body": markdown(str(data["text"]), extensions=["extra"]),
}
for _ in range(10):
try:
resp = await send_room_message(room_id, content)
if isinstance(resp, RoomSendError):
if resp.status_code == "M_UNKNOWN_TOKEN":
LOGGER.warning("Reconnecting")
await CLIENT.login(conf.MATRIX_PW)
else:
return create_json_response(
ERROR_MAP[resp.status_code], resp.message
)
else:
break
except LocalProtocolError as e:
LOGGER.error(f"Send error: {e}")
LOGGER.warning("Trying again")
else:
return create_json_response(
HTTPStatus.GATEWAY_TIMEOUT, "Homeserver not responding"
)
return create_json_response(HTTPStatus.OK, "OK")
def create_json_response(status, ret):
"""Create a JSON response."""
LOGGER.debug(f"Creating json response: {status=}, {ret=}")
response_data = {"status": status, "ret": ret}
return web.json_response(response_data, status=status)
async def send_room_message(room_id, content):
"""Send a message to a room."""
LOGGER.debug(f"Sending room message in {room_id=}: {content=}")
return await CLIENT.room_send(
room_id=room_id, message_type="m.room.message", content=content
)
async def main(event):
"""
Launch main coroutine.
matrix client login & start web server
"""
LOGGER.info(f"Log in {conf.MATRIX_ID=} on {conf.MATRIX_URL=}")
await CLIENT.login(conf.MATRIX_PW)
server = web.Server(handler)
runner = web.ServerRunner(server)
await runner.setup()
LOGGER.info(f"Binding on {conf.SERVER_ADDRESS=}")
site = web.TCPSite(runner, *conf.SERVER_ADDRESS)
await site.start()
# Run until we get a shutdown request
await event.wait()
# Cleanup
await runner.cleanup()
await CLIENT.close()
def terminate(event, signal):
"""Close handling stuff."""
event.set()
asyncio.get_event_loop().remove_signal_handler(signal)
def run():
"""Launch everything."""
LOGGER.info("Starting...")
loop = asyncio.get_event_loop()
event = asyncio.Event()
for sig in (SIGINT, SIGTERM):
loop.add_signal_handler(sig, terminate, event, sig)
loop.run_until_complete(main(event))
LOGGER.info("Closing...")
loop.close()
def main():
"""Start everything."""
log_format = "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s"
logging.basicConfig(level=50 - 10 * conf.VERBOSE, format=log_format)
app.run()
if __name__ == "__main__":
log_format = "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(message)s"
logging.basicConfig(level=50 - 10 * conf.VERBOSE, format=log_format)
run()
main()

56
matrix_webhook/app.py Normal file
View file

@ -0,0 +1,56 @@
"""Matrix Webhook app."""
import asyncio
import logging
from signal import SIGINT, SIGTERM
from aiohttp import web
from . import conf, handler, utils
LOGGER = logging.getLogger("matrix_webhook.app")
async def main(event):
"""
Launch main coroutine.
matrix client login & start web server
"""
LOGGER.info(f"Log in {conf.MATRIX_ID=} on {conf.MATRIX_URL=}")
await utils.CLIENT.login(conf.MATRIX_PW)
server = web.Server(handler.matrix_webhook)
runner = web.ServerRunner(server)
await runner.setup()
LOGGER.info(f"Binding on {conf.SERVER_ADDRESS=}")
site = web.TCPSite(runner, *conf.SERVER_ADDRESS)
await site.start()
# Run until we get a shutdown request
await event.wait()
# Cleanup
await runner.cleanup()
await utils.CLIENT.close()
def terminate(event, signal):
"""Close handling stuff."""
event.set()
asyncio.get_event_loop().remove_signal_handler(signal)
def run():
"""Launch everything."""
LOGGER.info("Starting...")
loop = asyncio.get_event_loop()
event = asyncio.Event()
for sig in (SIGINT, SIGTERM):
loop.add_signal_handler(sig, terminate, event, sig)
loop.run_until_complete(main(event))
LOGGER.info("Closing...")
loop.close()

View file

@ -1,6 +1,25 @@
"""Configuration for Matrix Webhook."""
import argparse
import os
import sys
import yaml
def get_numeric_log_level(log_level):
"""Return a number that will calculate to the verbosity level"""
if log_level.lower() == "debug":
return 4
elif log_level.lower() == "info":
return 3
elif log_level.lower() == "warning":
return 2
elif log_level.lower() == "error":
return 1
elif log_level.lower() == "critical":
return 0
else:
return 2
parser = argparse.ArgumentParser(description=__doc__, prog="python -m matrix_webhook")
parser.add_argument(
@ -20,47 +39,67 @@ parser.add_argument(
"-u",
"--matrix-url",
default=os.environ.get("MATRIX_URL", "https://matrix.org"),
help="matrix homeserver url. Default: `https://matrix.org`. Environment variable: `MATRIX_URL`",
help="matrix homeserver url. Default: `https://matrix.org`. "
"Environment variable: `MATRIX_URL`",
)
parser.add_argument(
"-i",
"--matrix-id",
help="matrix user-id. Required. Environment variable: `MATRIX_ID`",
**(
{"default": os.environ["MATRIX_ID"]}
if "MATRIX_ID" in os.environ
else {"required": True}
),
)
parser.add_argument(
"-p",
"--matrix-pw",
help="matrix password. Required. Environment variable: `MATRIX_PW`",
**(
{"default": os.environ["MATRIX_PW"]}
if "MATRIX_PW" in os.environ
else {"required": True}
),
)
parser.add_argument(
"-k",
"--api-key",
help="shared secret to use this service. Required. Environment variable: `API_KEY`",
**(
{"default": os.environ["API_KEY"]}
if "API_KEY" in os.environ
else {"required": True}
),
"--api-keys",
help="comma separated list of shared secrets to use this service. Required. Environment variable: `API_KEYS`",
)
parser.add_argument(
"-c",
"--config",
help="configuration file. Default: `config.yaml`",
)
parser.add_argument(
"-v", "--verbose", action="count", default=0, help="increment verbosity level"
)
args = parser.parse_args()
SERVER_ADDRESS = (args.host, args.port)
MATRIX_URL = args.matrix_url
MATRIX_ID = args.matrix_id
MATRIX_PW = args.matrix_pw
API_KEY = args.api_key
VERBOSE = args.verbose
if args.config:
with open(args.config) as f:
config = yaml.safe_load(f)
SERVER_ADDRESS = (config["hostname"], config["port"])
MATRIX_URL = config["matrix"]["url"]
MATRIX_ID = config["matrix"]["id"]
MATRIX_PW = config["matrix"]["pw"]
API_KEYS = config["api_keys"]
LOG_FILE = config["log"]
VERBOSE = get_numeric_log_level(config["log"]["level"])
else:
SERVER_ADDRESS = (args.host, args.port)
MATRIX_URL = args.matrix_url
LOG_FILE = args.log
if not args.matrix_id:
print("Missing matrix user-id. Use -i or --matrix-id or specify in config.yaml")
sys.exit(1)
else:
MATRIX_ID = args.matrix_id
if not args.matrix_pw:
print(
"Missing matrix password. Use -p or --matrix-pw or specify in config.yaml"
)
sys.exit(1)
else:
MATRIX_PW = args.matrix_pw
if not args.api_keys:
print("Missing api keys. Use -k or --api-keys or specify in config.yaml")
sys.exit(1)
else:
API_KEYS = args.api_keys.split(",")
VERBOSE = args.verbose

View file

@ -0,0 +1,8 @@
def formatter(data, headers):
"""Pretty-print an alertmanager notification."""
text = ""
for alert in data['alerts']:
text += f"[{alert['status']}] - {alert['labels']['summary']}\n\n"
data["body"] = text
return data

View file

@ -0,0 +1,34 @@
from datetime import datetime
def formatter(data, headers):
"""Pretty-print a buildbot notification."""
buildid = data["buildid"]
buildstate = data["state_string"]
buildlink = data["url"]
reason = data["buildset"]["reason"]
project = data["properties"]["project"][0]
submittime = datetime.fromtimestamp(data["buildset"]["submitted_at"])
try:
if buildstate == "starting":
data["body"] = (
f"###Buildbot job #{buildid} for {project} - {buildstate}\n\n"
f"{reason}\n\n"
f"**started at** {submittime}\n\n"
f"[view details]({buildlink})"
)
elif buildstate == "build successful":
data["body"] = (
f"###Buildbot job #{buildid} for {project} - {buildstate}\n\n"
f"**completed at** {datetime.fromtimestamp(data['complete_at'])}\n\n"
f"[view details]({buildlink})"
)
else:
data["body"] = (
f"###Buildbot job #{buildid} for {project} - {buildstate}\n\n"
f"[view details]({buildlink})"
)
except Exception as error:
print(error)
return data

View file

@ -0,0 +1,36 @@
import requests
def get_abuse_confidence(ip):
"""get abuseipdb's confidence level on an ip passed in, and return that value"""
base_url = "https://api.abuseipdb.com/api/v2/check"
api_key = "YOUR API KEY"
headers = {"Key": api_key, "Accept": "application/json"}
data = {"ipAddress": ip, "maxAgeInDays": 90}
r = requests.get(base_url, headers=headers, json=data)
confidence = r.json()["data"]["abuseConfidenceScore"]
whitelist = r.json()["data"]["isWhitelisted"]
return [confidence, whitelist]
def formatter(data, headers):
"""format a message sent with crowdsec http endpoints"""
data_out = ""
for row in data["body"]:
ip = row["host"]
duration = row["duration"]
confidence, whitelisted = get_abuse_confidence(ip)
if "crowdsecurity" in row["scenario"]:
source, scenario, *_ = row["scenario"].split("/")
row[
"scenario"
] = f"[{scenario}](https://hub.crowdsec.net/author/crowdsecurity/configurations/{scenario})"
data_out += f"{ip} has been banned {duration} due to {row['scenario']}\n\n"
if whitelisted:
data_out += "**Note: AbuseIPDB has whitelisted this address\n\n"
data_out += (
f"[AbuseIPDB](https://www.abuseipdb.com/check/{row['host']})({confidence}%) | "
f"[Crowdsec](https://app.crowdsec.net/cti/{row['host']})\n\n"
)
data["body"] = data_out
return data

View file

@ -0,0 +1,4 @@
def formatter(data, headers):
"""Just dump the json data"""
data["body"] = f"{data}"
return data

View file

@ -0,0 +1,15 @@
def formatter(data, headers):
"""Pretty-print a github notification."""
# TODO: Write nice useful formatters. This is only an example.
if headers["X-GitHub-Event"] == "push":
pusher, ref, a, b, c = [
data[k] for k in ["pusher", "ref", "after", "before", "compare"]
]
pusher = f"[@{pusher['name']}](https://github.com/{pusher['name']})"
data["body"] = f"{pusher} pushed on {ref}: [{b}{a}]({c}):\n\n"
for commit in data["commits"]:
data["body"] += f"- [{commit['message']}]({commit['url']})\n"
else:
data["body"] = "notification from github"
data["digest"] = headers["X-Hub-Signature-256"].replace("sha256=", "")
return data

View file

@ -0,0 +1,12 @@
def formatter(data, headers):
"""Pretty-print a grafana notification."""
text = ""
if "title" in data:
text = "#### " + data["title"] + "\n"
if "message" in data:
text = text + data["message"] + "\n\n"
if "evalMatches" in data:
for match in data["evalMatches"]:
text = text + "* " + match["metric"] + ": " + str(match["value"]) + "\n"
data["body"] = text
return data

View file

@ -0,0 +1,9 @@
def grafana_9x(data, headers):
"""Pretty-print a Grafana newer than v9.x notification."""
text = ""
if "title" in data:
text = "#### " + data["title"] + "\n"
if "message" in data:
text = text + data["message"].replace("\n", "\n\n") + "\n\n"
data["body"] = text
return data

View file

@ -0,0 +1,64 @@
from datetime import datetime
def formatter(data, headers):
"""Pretty-print a pingdom notification."""
# JSON data formatting was obtained from https://www.pingdom.com/resources/webhooks/
# these are common to all check types
check_id = data["check_id"]
check_name = data["check_name"]
current_state = data["current_state"]
tags = data["tags"]
local_time = datetime.fromtimestamp(data["state_changed_timestamp"])
if data["check_type"].lower() == "http":
# http https or http_custom check types
try:
check_url = data["check_params"]["full_url"]
message = ""
message += f"###{check_name} is {current_state}\n\n{check_url}"
message += f" marked {current_state} at {local_time}"
message += f"[view details](https://my.pingdom.com/reports/responsetime#check={check_id})"
if tags:
message += f"\n\nTags: {tags}"
data["body"] = message
except Exception as error:
data["body"] = (
f"Error: An attempt to post from pingdom was malformed "
"(or I don't know how to handle what was sent).\n\n"
f"{repr(error)}"
)
elif data["check_type"].lower() == "dns":
# There are a bunch of values that are blanke when you do a test
# so ignore them if value is unset
try:
first_ip = data["first_probe"]["ip"]
except KeyError:
first_ip = "unknown"
try:
second_ip = data["second_probe"]["ip"]
except KeyError:
second_ip = "unknown"
try:
first_location = data["first_probe"]["location"]
except KeyError:
first_location = "unknown"
try:
second_location = data["second_probe"]["location"]
except KeyError:
second_location = "unknown"
try:
expected_ip = data["check_params"]["expected_ip"]
data["body"] = (
f"###{check_name} is {current_state}\n\n"
f"expected {expected_ip} but got:\n\n"
f" {first_ip} ({first_location})\n\n"
f" {second_ip} ({second_location})\n\n"
f" marked {current_state} at {local_time}"
f"[view details](https://my.pingdom.com/reports/responsetime#check={check_id})"
)
except Exception as error:
print(error)
return data

View file

@ -0,0 +1,5 @@
def formatter(data, headers):
""" format a message sent with slack api endpoints"""
text = data["attachments"][0]["text"]
data["body"] = f"{text}"
return data

91
matrix_webhook/handler.py Normal file
View file

@ -0,0 +1,91 @@
"""Matrix Webhook main request handler."""
import json
import logging
from http import HTTPStatus
from hmac import HMAC
import importlib
from markdown import markdown
from . import conf, utils
LOGGER = logging.getLogger("matrix_webhook.handler")
async def matrix_webhook(request):
"""
Coroutine given to the server, st. it knows what to do with an HTTP request.
This one handles a POST, checks its content, and forwards it to the matrix room.
"""
LOGGER.debug(f"Handling {request=}")
data_b = await request.read()
try:
data = json.loads(data_b.decode())
except json.decoder.JSONDecodeError:
return utils.create_json_response(HTTPStatus.BAD_REQUEST, "Invalid JSON")
# legacy naming
if "text" in data and "body" not in data:
data["body"] = data["text"]
# allow key to be passed as a parameter
if "key" in request.rel_url.query and "key" not in data:
data["key"] = request.rel_url.query["key"]
if "formatter" in request.rel_url.query:
try:
format = request.rel_url.query["formatter"]
plugin = importlib.import_module(f"matrix_webhook.formatters.{format}", "formatter")
data = plugin.formatter(data, request.headers)
except ModuleNotFoundError:
return utils.create_json_response(
HTTPStatus.BAD_REQUEST, "Unknown formatter"
)
if "room_id" in request.rel_url.query and "room_id" not in data:
data["room_id"] = request.rel_url.query["room_id"]
if "room_id" not in data:
data["room_id"] = request.path.lstrip("/")
# If we get a good SHA-256 HMAC digest,
# we can consider that the sender has the right API key
if "digest" in data:
if data["digest"] == HMAC(conf.API_KEY.encode(), data_b, "sha256").hexdigest():
data["key"] = conf.API_KEY
else: # but if there is a wrong digest, an informative error should be provided
return utils.create_json_response(
HTTPStatus.UNAUTHORIZED, "Invalid SHA-256 HMAC digest"
)
missing = []
for key in ["body", "key", "room_id"]:
if key not in data or not data[key]:
missing.append(key)
if missing:
return utils.create_json_response(
HTTPStatus.BAD_REQUEST, f"Missing {', '.join(missing)}"
)
if data["key"] not in conf.API_KEYS:
return utils.create_json_response(HTTPStatus.UNAUTHORIZED, "Invalid API key")
if "formatted_body" in data:
formatted_body = data["formatted_body"]
else:
formatted_body = markdown(str(data["body"]), extensions=["extra"])
# try to join room first -> non none response means error
resp = await utils.join_room(data["room_id"])
if resp is not None:
return resp
content = {
"msgtype": "m.text",
"body": data["body"],
"format": "org.matrix.custom.html",
"formatted_body": formatted_body,
}
return await utils.send_room_message(data["room_id"], content)

78
matrix_webhook/utils.py Normal file
View file

@ -0,0 +1,78 @@
"""Matrix Webhook utils."""
import logging
from http import HTTPStatus
from aiohttp import web
from nio import AsyncClient
from nio.exceptions import LocalProtocolError
from nio.responses import RoomSendError, JoinError
from . import conf
ERROR_MAP = {
"M_FORBIDDEN": HTTPStatus.FORBIDDEN,
"M_CONSENT_NOT_GIVEN": HTTPStatus.FORBIDDEN,
}
LOGGER = logging.getLogger("matrix_webhook.utils")
CLIENT = AsyncClient(conf.MATRIX_URL, conf.MATRIX_ID)
def error_map(resp):
"""Map response errors to HTTP status."""
if resp.status_code == "M_UNKNOWN":
# in this case, we should directly consider the HTTP status from the response
# ref. https://matrix.org/docs/spec/client_server/r0.6.1#api-standards
return resp.transport_response.status
return ERROR_MAP[resp.status_code]
def create_json_response(status, ret):
"""Create a JSON response."""
LOGGER.debug(f"Creating json response: {status=}, {ret=}")
response_data = {"status": status, "ret": ret}
return web.json_response(response_data, status=status)
async def join_room(room_id):
"""Try to join the room."""
LOGGER.debug(f"Join room {room_id=}")
for _ in range(10):
try:
resp = await CLIENT.join(room_id)
if isinstance(resp, JoinError):
if resp.status_code == "M_UNKNOWN_TOKEN":
LOGGER.warning("Reconnecting")
await CLIENT.login(conf.MATRIX_PW)
else:
return create_json_response(error_map(resp), resp.message)
else:
return None
except LocalProtocolError as e:
LOGGER.error(f"Send error: {e}")
LOGGER.warning("Trying again")
return create_json_response(HTTPStatus.GATEWAY_TIMEOUT, "Homeserver not responding")
async def send_room_message(room_id, content):
"""Send a message to a room."""
LOGGER.debug(f"Sending room message in {room_id=}: {content=}")
for _ in range(10):
try:
resp = await CLIENT.room_send(
room_id=room_id, message_type="m.room.message", content=content
)
if isinstance(resp, RoomSendError):
if resp.status_code == "M_UNKNOWN_TOKEN":
LOGGER.warning("Reconnecting")
await CLIENT.login(conf.MATRIX_PW)
else:
return create_json_response(error_map(resp), resp.message)
else:
return create_json_response(HTTPStatus.OK, "OK")
except LocalProtocolError as e:
LOGGER.error(f"Send error: {e}")
LOGGER.warning("Trying again")
return create_json_response(HTTPStatus.GATEWAY_TIMEOUT, "Homeserver not responding")

2577
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

5
package.json Normal file
View file

@ -0,0 +1,5 @@
{
"dependencies": {
"@mermaid-js/mermaid-cli": "^8.13.3"
}
}

1014
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "matrix-webhook"
version = "3.1.1"
version = "3.5.0"
description = "Post a message to a matrix room with a simple HTTP POST"
authors = ["Guilhem Saurel <guilhem.saurel@laas.fr>"]
license = "BSD-2-Clause"
@ -8,21 +8,29 @@ readme = "README.md"
homepage = "https://github.com/nim65s/matrix-webhook"
repository = "https://github.com/nim65s/matrix-webhook.git"
[tool.poetry.urls]
"changelog" = "https://github.com/nim65s/matrix-webhook/blob/master/CHANGELOG.md"
[tool.poetry.dependencies]
python = "^3.8"
Markdown = "^3.3.4"
matrix-nio = "^0.18.3"
matrix-nio = ">=0.18.3,<0.21.0"
PyYAML = "^6.0"
[tool.poetry.dev-dependencies]
httpx = "^0.18.2"
coverage = "^5.5"
black = "^21.6b0"
httpx = "^0.23.0"
black = "^22.8.0"
coverage = "^6.4.4"
pydocstyle = "^6.1.1"
flake8 = "^3.9.2"
flake8 = "^5.0.4"
pyupgrade = "^2.31.0"
[tool.pydocstyle]
ignore = ["D203", "D204", "D212"]
ignore = ["D200", "D203", "D204", "D212"]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
matrix-webhook = "matrix_webhook.__main__:main"

View file

@ -4,13 +4,29 @@ FROM matrixdotorg/synapse
# The config dir defaults to /data which is a volume made to keep data.
# Here, we want to trash those (and avoid the permission issues) by using something else
ENV SYNAPSE_CONFIG_DIR=/srv SYNAPSE_SERVER_NAME=tests SYNAPSE_REPORT_STATS=no
ENV SYNAPSE_CONFIG_DIR=/srv SYNAPSE_DATA_DIR=/srv SYNAPSE_SERVER_NAME=tests SYNAPSE_REPORT_STATS=no
# Generate configuration and keys for synapse
WORKDIR $SYNAPSE_CONFIG_DIR
RUN chown -R 991:991 . \
&& /start.py generate \
&& sed -i 's=/data=/srv=;s=8008=80=;s=#sup=sup=;' homeserver.yaml \
&& echo "" >> homeserver.yaml \
&& echo "rc_message:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo "rc_registration:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo "rc_registration_token_validity:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo "rc_login:" >> homeserver.yaml \
&& echo " address:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo " account:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo " failed_attempts:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& echo "rc_joins:" >> homeserver.yaml \
&& echo " burst_count: 1000" >> homeserver.yaml \
&& python -m synapse.app.homeserver --config-path homeserver.yaml --generate-keys
RUN pip install --no-cache-dir markdown matrix-nio httpx coverage

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
{"text":"John Doe pushed to branch \u003chttps://gitlab.com/jdoe/test/commits/master|master\u003e of \u003chttps://gitlab.com/jdoe/test|John Doe / test\u003e (\u003chttps://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e|Compare changes\u003e)\n\u003chttps://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213650d6c009db0471361e|3517b06c\u003e: Merge branch 'prod' into 'master' - John Doe\n\n\u003chttps://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f391eb8de3ac4fcc6fc1d|1f661795\u003e: Merge branch 'revert-a827b196' into 'prod' - John Doe\n\n\u003chttps://gitlab.com/jdoe/test/-/commit/b76004b20503d4d506e51a670de095cc063e4707|b76004b2\u003e: Merge branch 'revert-a827b196' into 'master' - John Doe"}

View file

@ -0,0 +1 @@
{"sections":[{"activityTitle":"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits/master)","activitySubtitle":"in [John Doe / test](https://gitlab.com/jdoe/test)","activityText":"[Compare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e)","activityImage":"https://secure.gravatar.com/avatar/80\u0026d=identicon"},{"text":"[3517b06c](https://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213650d6c009db0471361e): Merge branch 'prod' into 'master' - John Doe\n\n[1f661795](https://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f391eb8de3ac4fcc6fc1d): Merge branch 'revert-a827b196' into 'prod' - John Doe\n\n[b76004b2](https://gitlab.com/jdoe/test/-/commit/b76004b20503d4d506e51a670de095cc063e4707): Merge branch 'revert-a827b196' into 'master' - John Doe"}],"title":"John Doe / test","summary":"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits/master) of [John Doe / test](https://gitlab.com/jdoe/test) ([Compare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e))"}

View file

@ -0,0 +1,22 @@
{
"dashboardId":1,
"evalMatches":[
{
"value":1,
"metric":"Count",
"tags":{}
}
],
"imageUrl":"https://grafana.com/assets/img/blog/mixed_styles.png",
"message":"Notification Message",
"orgId":1,
"panelId":2,
"ruleId":1,
"ruleName":"Panel Title alert",
"ruleUrl":"http://localhost:3000/d/hZ7BuVbWz/test-dashboard?fullscreen\u0026edit\u0026tab=alert\u0026panelId=2\u0026orgId=1",
"state":"alerting",
"tags":{
"tag name":"tag value"
},
"title":"[Alerting] Panel Title alert"
}

View file

@ -0,0 +1,41 @@
{
"receiver": "",
"status": "firing",
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "TestAlert",
"instance": "Grafana"
},
"annotations": {
"summary": "Notification test"
},
"startsAt": "2022-09-07T15:00:26.722304913+02:00",
"endsAt": "0001-01-01T00:00:00Z",
"generatorURL": "",
"fingerprint": "57c6d9296de2ad39",
"silenceURL": "https://grafana.example.com/alerting/silence/new?alertmanager=grafana&matcher=alertname%3DTestAlert&matcher=instance%3DGrafana",
"dashboardURL": "",
"panelURL": "",
"valueString": "[ metric='foo' labels={instance=bar} value=10 ]"
}
],
"groupLabels": {},
"commonLabels": {
"alertname": "TestAlert",
"instance": "Grafana"
},
"commonAnnotations": {
"summary": "Notification test"
},
"externalURL": "https://grafana.example.com/",
"version": "1",
"groupKey": "{alertname=\"TestAlert\", instance=\"Grafana\"}2022-09-07 15:00:26.722304913 +0200 CEST m=+246580.963796811",
"truncatedAlerts": 0,
"orgId": 1,
"title": "[FIRING:1] (TestAlert Grafana)",
"state": "alerting",
"message": "**Firing**\n\nValue: [ metric='foo' labels={instance=bar} value=10 ]\nLabels:\n - alertname = TestAlert\n - instance = Grafana\nAnnotations:\n - summary = Notification test\nSilence: https://grafana.example.com/alerting/silence/new?alertmanager=grafana&matcher=alertname%3DTestAlert&matcher=instance%3DGrafana\n",
"key": "ak"
}

View file

@ -0,0 +1,33 @@
{
"check_id": 12345,
"check_name": "Pingdom-dns build test",
"check_type": "DNS",
"check_params": {
"hostname": "www.example.com",
"basic_auth": false,
"expected_ip": "123.4.5.6",
"ipv6": false,
"nameserver": "example.com"
},
"tags": [
"example_tag"
],
"previous_state": "UP",
"current_state": "DOWN",
"importance_level": "HIGH",
"state_changed_timestamp": 1451610061,
"state_changed_utc_time": "2016-01-01T01:01:01",
"long_description": "Long error message",
"description": "Short error message",
"first_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Stockholm, Sweden"
},
"second_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Austin, US",
"version": 1
}
}

View file

@ -0,0 +1,36 @@
{
"check_id": 12345,
"check_name": "Pingdom-http build test",
"check_type": "HTTP",
"check_params": {
"basic_auth": false,
"encryption": true,
"full_url": "https://www.example.com/path",
"header": "User-Agent:Pingdom.com_bot",
"hostname": "www.example.com",
"ipv6": false,
"port": 443,
"url": "/path"
},
"tags": [
"example_tag"
],
"previous_state": "UP",
"current_state": "DOWN",
"importance_level": "HIGH",
"state_changed_timestamp": 1451610061,
"state_changed_utc_time": "2016-01-01T01:01:01",
"long_description": "Long error message",
"description": "Short error message",
"first_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Stockholm, Sweden"
},
"second_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Austin, US",
"version": 1
}
}

View file

@ -0,0 +1,34 @@
{
"body":{
"check_id": 12345,
"check_name": "Pingdom-tcp build test",
"check_type": "PORT_TCP",
"check_params": {
"hostname": "www.example.com",
"basic_auth": false,
"ipv6": false,
"port": 80
},
"tags": [
"example_tag"
],
"previous_state": "UP",
"current_state": "DOWN",
"importance_level": "HIGH",
"state_changed_timestamp": 1451610061,
"state_changed_utc_time": "2016-01-01T01:01:01",
"long_description": "Long error message",
"description": "Short error message",
"first_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Stockholm, Sweden"
},
"second_probe": {
"ip": "123.4.5.6",
"ipv6": "2001:4800:1020:209::5",
"location": "Austin, US",
"version": 1
}
}
}

View file

@ -25,19 +25,35 @@ parser.add_argument(
)
def bot_req(req=None, key=None, room_id=None):
def bot_req(
req=None,
key=None,
room_id=None,
params=None,
key_as_param=False,
room_as_parameter=False,
):
"""Bot requests boilerplate."""
if params is None:
params = {}
if key is not None:
req["key"] = key
url = BOT_URL if room_id is None else f"{BOT_URL}/{room_id}"
return httpx.post(url, json=req).json()
if key_as_param:
params["key"] = key
else:
req["key"] = key
if room_as_parameter:
params["room_id"] = room_id
url = BOT_URL if room_id is None or room_as_parameter else f"{BOT_URL}/{room_id}"
return httpx.post(url, params=params, json=req).json()
def wait_available(url: str, key: str, timeout: int = 10) -> bool:
"""Wait until a service answer correctly or timeout."""
def check_json(url: str, key: str) -> bool:
"""Ensure a service at a given url answers with valid json containing a certain key."""
"""
Ensure a service at a given url answers with valid json including a certain key.
"""
try:
data = httpx.get(url).json()
return key in data
@ -88,7 +104,7 @@ def run_and_test():
srv.terminate()
# TODO Check what the bot says when the server is offline
# print(bot_req({'text': 'bye'}, KEY), {'status': 200, 'ret': 'OK'})
# print(bot_req({'data': 'bye'}, KEY), {'status': 200, 'ret': 'OK'})
LOGGER.info("Stopping the bot")
bot.terminate()

130
tests/test_github.py Normal file
View file

@ -0,0 +1,130 @@
"""Test module for grafana formatter."""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, MATRIX_ID, MATRIX_PW, MATRIX_URL
SHA256 = "fd7522672889385736be8ffc86d1f8de2e15668864f49af729b5c63e5e0698c4"
def headers(sha256=SHA256, event="push"):
"""Mock headers from github webhooks."""
return {
# 'Request URL': 'https://bot.saurel.me/room?formatter=github',
# 'Request method': 'POST',
"Accept": "*/*",
"content-type": "application/json",
"User-Agent": "GitHub-Hookshot/8d33975",
"X-GitHub-Delivery": "636b9b1c-0761-11ec-8a8a-5e435c5ac4f4",
"X-GitHub-Event": event,
"X-GitHub-Hook-ID": "311845633",
"X-GitHub-Hook-Installation-Target-ID": "171114171",
"X-GitHub-Hook-Installation-Target-Type": "repository",
"X-Hub-Signature": "sha1=ea68fdfcb2f328aaa8f50d176f355e5d4fc95d94",
"X-Hub-Signature-256": f"sha256={sha256}",
}
class GithubFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Github formatter test class."""
async def test_github_notification(self):
"""Send a mock github webhook, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_github_push.json", "rb") as f:
example_github_push = f.read().strip()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={
"formatter": "github",
},
content=example_github_push,
headers=headers(event="something else"),
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.formatted_body,
"<p>notification from github</p>",
)
async def test_github_push(self):
"""Send a mock github push webhook, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_github_push.json", "rb") as f:
example_github_push = f.read().strip()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={
"formatter": "github",
},
content=example_github_push,
headers=headers(),
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
before = "ac7d1d9647008145e9d0cf65d24744d0db4862b8"
after = "4bcdb25c809391baaabc264d9309059f9f48ead2"
GH = "https://github.com"
expected = f'<p><a href="{GH}/nim65s">@nim65s</a> pushed on refs/heads/devel: '
expected += f'<a href="{GH}/nim65s/matrix-webhook/compare/ac7d1d964700...'
expected += f'4bcdb25c8093">{before}{after}</a>:</p>\n<ul>\n<li>'
expected += f'<a href="{GH}/nim65s/matrix-webhook/commit/{after}">'
expected += "formatters: also get headers</a></li>\n</ul>"
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.formatted_body,
expected,
)
async def test_github_wrong_digest(self):
"""Send a mock github push webhook with a wrong digest."""
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_github_push.json", "rb") as f:
example_github_push = f.read().strip()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={
"formatter": "github",
},
content=example_github_push,
headers=headers("wrong digest"),
).json(),
{"status": 401, "ret": "Invalid SHA-256 HMAC digest"},
)
await client.close()

View file

@ -0,0 +1,54 @@
"""
Test module for gitlab "google chat" formatter.
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL
class GitlabGchatFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Gitlab "google chat" formatter test class."""
async def test_gitlab_gchat_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_gitlab_gchat.json") as f:
example_gitlab_gchat_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "gitlab_gchat", "key": KEY},
content=example_gitlab_gchat_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.body,
"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits/m"
+ "aster) of [John Doe / test](https://gitlab.com/jdoe/test) ([Compare chan"
+ "ges](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e51a670de095"
+ "cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e))\n[3517b06c](http"
+ "s://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213650d6c009db047136"
+ "1e): Merge branch 'prod' into 'master' - John Doe\n\n[1f661795](https://"
+ "gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f391eb8de3ac4fcc6fc1d):"
+ " Merge branch 'revert-a827b196' into 'prod' - John Doe\n\n[b76004b2](htt"
+ "ps://gitlab.com/jdoe/test/-/commit/b76004b20503d4d506e51a670de095cc063e4"
+ "707): Merge branch 'revert-a827b196' into 'master' - John Doe",
)

View file

@ -0,0 +1,55 @@
"""
Test module for gitlab "teams" formatter.
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL
class GitlabTeamsFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Gitlab "teams" formatter test class."""
async def test_gitlab_teams_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_gitlab_teams.json") as f:
example_gitlab_teams_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "gitlab_teams", "key": KEY},
content=example_gitlab_teams_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.body,
"John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits"
+ "/master) in [John Doe / test](https://gitlab.com/jdoe/test) \u2192 [Com"
+ "pare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e5"
+ "1a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e) \n\n*"
+ " [3517b06c](https://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213"
+ "650d6c009db0471361e): Merge branch 'prod' into 'master' - John Doe \n*"
+ " [1f661795](https://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f3"
+ "91eb8de3ac4fcc6fc1d): Merge branch 'revert-a827b196' into 'prod' - John"
+ " Doe \n* [b76004b2](https://gitlab.com/jdoe/test/-/commit/b76004b20503"
+ "d4d506e51a670de095cc063e4707): Merge branch 'revert-a827b196' into 'mas"
+ "ter' - John Doe",
)

46
tests/test_grafana.py Normal file
View file

@ -0,0 +1,46 @@
"""
Test module for grafana formatter.
ref https://grafana.com/docs/grafana/latest/alerting/old-alerting/notifications/#webhook
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL
class GrafanaFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Grafana formatter test class."""
async def test_grafana_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_grafana.json") as f:
example_grafana_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "grafana", "key": KEY},
content=example_grafana_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.body,
"#### [Alerting] Panel Title alert\nNotification Message\n\n* Count: 1\n",
)

51
tests/test_grafana_9x.py Normal file
View file

@ -0,0 +1,51 @@
"""
Test module for grafana v9 formatter.
ref https://grafana.com/docs/grafana/latest/alerting/old-alerting/notifications/#webhook
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, MATRIX_ID, MATRIX_PW, MATRIX_URL
class Grafana9xFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Grafana formatter test class."""
async def test_grafana_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_grafana_9x.json") as f:
example_grafana_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "grafana_9x"},
content=example_grafana_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
expected_body = (
"#### [FIRING:1] (TestAlert Grafana)\n**Firing**\n\n\n\nValue: [ metr"
"ic='foo' labels={instance=bar} value=10 ]\n\nLabels:\n\n - alertname "
"= TestAlert\n\n - instance = Grafana\n\nAnnotations:\n\n - summary = "
"Notification test\n\nSilence: https://grafana.example.com/alerting/si"
"lence/new?alertmanager=grafana&matcher=alertname%3DTestAlert&matcher="
"instance%3DGrafana\n\n\n\n"
)
self.assertEqual(message.body, expected_body)

View file

@ -0,0 +1,51 @@
"""
Test version 9 compatibility of grafana formatter.
ref https://grafana.com/docs/grafana/latest/alerting/old-alerting/notifications/#webhook
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, MATRIX_ID, MATRIX_PW, MATRIX_URL
class GrafanaForwardFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Grafana formatter test class."""
async def test_grafana_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_grafana_9x.json") as f:
example_grafana_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "grafana"},
content=example_grafana_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
expected_body = (
"#### [FIRING:1] (TestAlert Grafana)\n**Firing**\n\n\n\nValue: [ metr"
"ic='foo' labels={instance=bar} value=10 ]\n\nLabels:\n\n - alertname "
"= TestAlert\n\n - instance = Grafana\n\nAnnotations:\n\n - summary = "
"Notification test\n\nSilence: https://grafana.example.com/alerting/si"
"lence/new?alertmanager=grafana&matcher=alertname%3DTestAlert&matcher="
"instance%3DGrafana\n\n\n\n"
)
self.assertEqual(message.body, expected_body)

44
tests/test_pingdom.py Normal file
View file

@ -0,0 +1,44 @@
"""
Test module for pingdom formatter.
"""
import unittest
import httpx
import nio
from .start import BOT_URL, FULL_ID, KEY, MATRIX_ID, MATRIX_PW, MATRIX_URL
class PingdomFormatterTest(unittest.IsolatedAsyncioTestCase):
"""Grafana formatter test class."""
async def test_pingdom_http_body(self):
"""Send a markdown message, and check the result."""
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
with open("tests/example_pingdom_http.json") as f:
example_pingdom_request = f.read()
self.assertEqual(
httpx.post(
f"{BOT_URL}/{room.room_id}",
params={"formatter": "pingdom", "key": KEY},
content=example_pingdom_request,
).json(),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(
message.body,
"#### [Alerting] Panel Title alert\nNotification Message\n\n* Count: 1\n",
)

View file

@ -15,19 +15,33 @@ class BotTest(unittest.IsolatedAsyncioTestCase):
self.assertEqual(bot_req(), {"status": 400, "ret": "Invalid JSON"})
self.assertEqual(
bot_req({"toto": 3}),
{"status": 400, "ret": "Missing text and/or API key property"},
{"status": 400, "ret": "Missing body, key, room_id"},
)
self.assertEqual(
bot_req({"text": 3, "key": None}), {"status": 401, "ret": "Invalid API key"}
bot_req({"body": 3}, "wrong_key", "wrong_room"),
{"status": 401, "ret": "Invalid API key"},
)
# TODO: if the client from matrix_webhook has olm support, this won't be a 403 from synapse,
# but a LocalProtocolError from matrix_webhook
self.assertEqual(
bot_req({"text": 3}, KEY), {"status": 403, "ret": "Unknown room"}
bot_req({"body": 3}, "wrong_key", "wrong_room", key_as_param=True),
{"status": 401, "ret": "Invalid API key"},
)
self.assertEqual(
bot_req({"body": 3}, KEY, params={"formatter": "wrong_formatter"}),
{"status": 400, "ret": "Unknown formatter"},
)
# TODO: if the client from matrix_webhook has olm support,
# this won't be a 403 from synapse, but a LocalProtocolError from matrix_webhook
self.assertEqual(
bot_req({"body": 3}, KEY, "wrong_room"),
{"status": 400, "ret": "wrong_room was not legal room ID or room alias"},
)
self.assertEqual(
bot_req({"body": 3}, KEY, "wrong_room", key_as_param=True),
{"status": 400, "ret": "wrong_room was not legal room ID or room alias"},
)
async def test_message(self):
"""Send a markdown message, and check the result."""
"""Send a markdown message with the old format, and check the result."""
text = "# Hello"
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
@ -48,6 +62,100 @@ class BotTest(unittest.IsolatedAsyncioTestCase):
self.assertEqual(message.body, text)
self.assertEqual(message.formatted_body, "<h1>Hello</h1>")
async def test_room_id_req(self):
"""Send a markdown message in a room given as data, and check the result."""
body = "# Hello"
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
self.assertEqual(
bot_req({"body": body, "room_id": room.room_id}, KEY, room.room_id),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(message.body, body)
self.assertEqual(message.formatted_body, "<h1>Hello</h1>")
async def test_room_id_parameter(self):
"""Send a markdown message in a room given as parameter."""
body = "# Hello"
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
self.assertEqual(
bot_req({"body": body}, KEY, room.room_id, room_as_parameter=True),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(message.body, body)
self.assertEqual(message.formatted_body, "<h1>Hello</h1>")
async def test_markdown_body(self):
"""Send a markdown message, and check the result."""
body = "# Hello"
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
self.assertEqual(
bot_req({"body": body}, KEY, room.room_id), {"status": 200, "ret": "OK"}
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(message.body, body)
self.assertEqual(message.formatted_body, "<h1>Hello</h1>")
async def test_formatted_body(self):
"""Send a formatted message, and check the result."""
body = "Formatted message"
formatted_body = "<del>markdown</del><strong>Formatted</strong> message"
messages = []
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
await client.login(MATRIX_PW)
room = await client.room_create()
self.assertEqual(
bot_req(
{"body": body, "formatted_body": formatted_body}, KEY, room.room_id
),
{"status": 200, "ret": "OK"},
)
sync = await client.sync()
messages = await client.room_messages(room.room_id, sync.next_batch)
await client.close()
message = messages.chunk[0]
self.assertEqual(message.sender, FULL_ID)
self.assertEqual(message.body, body)
self.assertEqual(message.formatted_body, formatted_body)
async def test_reconnect(self):
"""Check the reconnecting path."""
client = nio.AsyncClient(MATRIX_URL, MATRIX_ID)
@ -56,6 +164,6 @@ class BotTest(unittest.IsolatedAsyncioTestCase):
await client.logout(all_devices=True)
await client.close()
self.assertEqual(
bot_req({"text": "Re"}, KEY, room.room_id),
bot_req({"body": "Re"}, KEY, room.room_id),
{"status": 200, "ret": "OK"},
)