feat(web02): Deploy mattermost on chat.dgnum.eu
All checks were successful
Run pre-commit on all files / pre-commit (push) Successful in 27s
Run pre-commit on all files / pre-commit (pull_request) Successful in 27s
Check meta / check_dns (push) Successful in 15s
Check meta / check_meta (push) Successful in 16s
Check meta / check_dns (pull_request) Successful in 15s
Check meta / check_meta (pull_request) Successful in 15s
Check workflows / check_workflows (pull_request) Successful in 18s
Build all the nodes / ap01 (pull_request) Successful in 39s
Build all the nodes / bridge01 (pull_request) Successful in 45s
Build all the nodes / cof02 (pull_request) Successful in 51s
Build all the nodes / geo01 (pull_request) Successful in 51s
Build all the nodes / build01 (pull_request) Successful in 59s
Build all the nodes / geo02 (pull_request) Successful in 51s
Build all the nodes / netaccess01 (pull_request) Successful in 22s
Build all the nodes / hypervisor01 (pull_request) Successful in 49s
Build all the nodes / hypervisor02 (pull_request) Successful in 48s
Build all the nodes / hypervisor03 (pull_request) Successful in 45s
Build all the nodes / netcore00 (pull_request) Successful in 23s
Build all the nodes / netcore01 (pull_request) Successful in 22s
Build all the nodes / netcore02 (pull_request) Successful in 23s
Build all the nodes / compute01 (pull_request) Successful in 1m18s
Build all the nodes / lab-router01 (pull_request) Successful in 52s
Build all the nodes / iso (pull_request) Successful in 1m0s
Build the shell / build-shell (pull_request) Successful in 22s
Build all the nodes / tower01 (pull_request) Successful in 46s
Build all the nodes / vault01 (pull_request) Successful in 1m0s
Build all the nodes / krz01 (pull_request) Successful in 1m39s
Build all the nodes / rescue01 (pull_request) Successful in 1m11s
Build all the nodes / storage01 (pull_request) Successful in 1m15s
Build all the nodes / web03 (pull_request) Successful in 59s
Build all the nodes / web01 (pull_request) Successful in 1m11s
Build all the nodes / web02 (pull_request) Successful in 3m59s
All checks were successful
Run pre-commit on all files / pre-commit (push) Successful in 27s
Run pre-commit on all files / pre-commit (pull_request) Successful in 27s
Check meta / check_dns (push) Successful in 15s
Check meta / check_meta (push) Successful in 16s
Check meta / check_dns (pull_request) Successful in 15s
Check meta / check_meta (pull_request) Successful in 15s
Check workflows / check_workflows (pull_request) Successful in 18s
Build all the nodes / ap01 (pull_request) Successful in 39s
Build all the nodes / bridge01 (pull_request) Successful in 45s
Build all the nodes / cof02 (pull_request) Successful in 51s
Build all the nodes / geo01 (pull_request) Successful in 51s
Build all the nodes / build01 (pull_request) Successful in 59s
Build all the nodes / geo02 (pull_request) Successful in 51s
Build all the nodes / netaccess01 (pull_request) Successful in 22s
Build all the nodes / hypervisor01 (pull_request) Successful in 49s
Build all the nodes / hypervisor02 (pull_request) Successful in 48s
Build all the nodes / hypervisor03 (pull_request) Successful in 45s
Build all the nodes / netcore00 (pull_request) Successful in 23s
Build all the nodes / netcore01 (pull_request) Successful in 22s
Build all the nodes / netcore02 (pull_request) Successful in 23s
Build all the nodes / compute01 (pull_request) Successful in 1m18s
Build all the nodes / lab-router01 (pull_request) Successful in 52s
Build all the nodes / iso (pull_request) Successful in 1m0s
Build the shell / build-shell (pull_request) Successful in 22s
Build all the nodes / tower01 (pull_request) Successful in 46s
Build all the nodes / vault01 (pull_request) Successful in 1m0s
Build all the nodes / krz01 (pull_request) Successful in 1m39s
Build all the nodes / rescue01 (pull_request) Successful in 1m11s
Build all the nodes / storage01 (pull_request) Successful in 1m15s
Build all the nodes / web03 (pull_request) Successful in 59s
Build all the nodes / web01 (pull_request) Successful in 1m11s
Build all the nodes / web02 (pull_request) Successful in 3m59s
This commit is contained in:
parent
fb5a0ae7eb
commit
af1cf7606d
8 changed files with 1427 additions and 0 deletions
|
@ -15,6 +15,7 @@ lib.extra.mkConfig {
|
|||
"cas-eleves"
|
||||
# "kadenios"
|
||||
"django-apps"
|
||||
"mattermost"
|
||||
];
|
||||
|
||||
extraConfig = {
|
||||
|
|
348
machines/nixos/web02/mattermost/0001-Login-page-ENS-theme.patch
Normal file
348
machines/nixos/web02/mattermost/0001-Login-page-ENS-theme.patch
Normal file
|
@ -0,0 +1,348 @@
|
|||
From ec1ffa5fc38cdd6d0cc5e8dea07d9a4730fc5a32 Mon Sep 17 00:00:00 2001
|
||||
From: hbarral <hbarral@clipper.ens.fr>
|
||||
Date: Fri, 25 Oct 2024 06:50:47 +0200
|
||||
Subject: [PATCH 1/2] Login page: ENS theme This commit should be cherry-picked
|
||||
on top of of new Mattermost releases
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Co-authored-by: Théophile Bastian <contact@tobast.fr>
|
||||
---
|
||||
.../channels/src/components/login/login.scss | 87 +++++++++++++++++-
|
||||
.../channels/src/components/login/login.tsx | 78 +++++++++++++---
|
||||
webapp/channels/src/images/emailLogo.png | Bin 0 -> 605 bytes
|
||||
webapp/channels/src/images/gitlabLogo.png | Bin 0 -> 1655 bytes
|
||||
webapp/channels/src/images/noaccountLogo.png | Bin 0 -> 693 bytes
|
||||
5 files changed, 153 insertions(+), 12 deletions(-)
|
||||
create mode 100644 webapp/channels/src/images/emailLogo.png
|
||||
create mode 100644 webapp/channels/src/images/gitlabLogo.png
|
||||
create mode 100644 webapp/channels/src/images/noaccountLogo.png
|
||||
|
||||
diff --git a/webapp/channels/src/components/login/login.scss b/webapp/channels/src/components/login/login.scss
|
||||
index e64aebccb4..ec7dafdafb 100644
|
||||
--- a/webapp/channels/src/components/login/login.scss
|
||||
+++ b/webapp/channels/src/components/login/login.scss
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
@use 'utils/mixins';
|
||||
|
||||
+$clipper_color: #548;
|
||||
+$email_color: #4d8844;
|
||||
+$exte_color: #886344;
|
||||
+
|
||||
.login-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -130,6 +134,88 @@
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
|
||||
+ .collapsed {
|
||||
+ display: none;
|
||||
+ }
|
||||
+
|
||||
+ .login-btn {
|
||||
+ @include mixins.primary-button;
|
||||
+ @include mixins.button-large;
|
||||
+
|
||||
+ display: flex;
|
||||
+ height: 64px;
|
||||
+ flex-direction: row;
|
||||
+ align-items: center;
|
||||
+ justify-content: flex-start;
|
||||
+ background-color: red;
|
||||
+ text-decoration: none;
|
||||
+
|
||||
+ .text {
|
||||
+ display: flex;
|
||||
+ width: 80%;
|
||||
+ flex-direction: column;
|
||||
+ align-items: center;
|
||||
+ justify-content: space-evenly;
|
||||
+
|
||||
+ & > span {
|
||||
+ display: inline-block;
|
||||
+
|
||||
+ &:nth-child(2) {
|
||||
+ font-size: 0.8em;
|
||||
+ font-style: italic;
|
||||
+ font-weight: normal;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ .icon {
|
||||
+ position: relative;
|
||||
+ display: inline-block;
|
||||
+ width: 42px;
|
||||
+ height: 42px;
|
||||
+ margin-right: 12px;
|
||||
+ background-size: 100% 100%;
|
||||
+ text-align: center;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ .login-body-card-auth-clipper {
|
||||
+ background-color: $clipper_color;
|
||||
+
|
||||
+ &:hover {
|
||||
+ background-color: darken($clipper_color, 10%);
|
||||
+ }
|
||||
+
|
||||
+ .icon {
|
||||
+ background-image: url('../../images/gitlabLogo.png');
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ .login-body-card-auth-mail-toggle {
|
||||
+ background-color: $email_color;
|
||||
+
|
||||
+ &:hover {
|
||||
+ background-color: darken($email_color, 10%);
|
||||
+ }
|
||||
+
|
||||
+ .icon {
|
||||
+ background-image: url('../../images/emailLogo.png');
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ .login-body-card-auth-exte {
|
||||
+ background-color: $exte_color;
|
||||
+ margin-top: 10px;
|
||||
+
|
||||
+ &:hover {
|
||||
+ background-color: darken($exte_color, 10%);
|
||||
+ }
|
||||
+
|
||||
+ .icon {
|
||||
+ background-image: url('../../images/noaccountLogo.png');
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
.login-body-card-form {
|
||||
.login-body-card-form-input {
|
||||
margin-top: 22px;
|
||||
@@ -161,7 +246,7 @@
|
||||
display: flex;
|
||||
height: 1px;
|
||||
justify-content: center;
|
||||
- margin: 40px 0;
|
||||
+ margin: 20px 0;
|
||||
background: rgba(var(--center-channel-color-rgb), 0.08);
|
||||
text-align: center;
|
||||
|
||||
diff --git a/webapp/channels/src/components/login/login.tsx b/webapp/channels/src/components/login/login.tsx
|
||||
index 5668c029a7..d5e2794584 100644
|
||||
--- a/webapp/channels/src/components/login/login.tsx
|
||||
+++ b/webapp/channels/src/components/login/login.tsx
|
||||
@@ -121,6 +121,8 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
|
||||
const [alertBanner, setAlertBanner] = useState<AlertBannerProps | null>(null);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
const [isMobileView, setIsMobileView] = useState(false);
|
||||
+ const [showEmailForm, setShowEmailForm] = useState(false);
|
||||
+
|
||||
|
||||
const enableCustomBrand = EnableCustomBrand === 'true';
|
||||
const enableLdap = EnableLdap === 'true';
|
||||
@@ -460,6 +462,10 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
+ function toggleEmailForm() {
|
||||
+ setShowEmailForm(!showEmailForm);
|
||||
+ }
|
||||
+
|
||||
if (initializing) {
|
||||
return (<LoadingScreen/>);
|
||||
}
|
||||
@@ -780,6 +786,8 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
+ const doShowEmailForm = (showEmailForm) ? '' : ' collapsed';
|
||||
+
|
||||
if (!enableBaseLogin && !enableExternalSignup) {
|
||||
return (
|
||||
<ColumnLayout
|
||||
@@ -848,13 +856,50 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
|
||||
onDismiss={alertBanner.onDismiss ?? dismissAlert}
|
||||
/>
|
||||
)}
|
||||
+ {enableExternalSignup && (
|
||||
+ <a
|
||||
+ className='login-body-card-auth-clipper login-btn'
|
||||
+ id='gitlab'
|
||||
+ href={Client4.getOAuthRoute() + '/gitlab/login'}
|
||||
+ >
|
||||
+ <span className='icon'/>
|
||||
+ <span className='text'>
|
||||
+ <span>
|
||||
+ {formatMessage({id: 'login.clipper', defaultMessage: 'Clipper'})}
|
||||
+ </span>
|
||||
+ <span>
|
||||
+ {formatMessage({id: 'login.clipper_help', defaultMessage: '("Gitlab" sur mobile)'})}
|
||||
+ </span>
|
||||
+ </span>
|
||||
+ </a>
|
||||
+ )}
|
||||
+ {enableBaseLogin && enableExternalSignup && (
|
||||
+ <div className='login-body-card-form-divider'>
|
||||
+ <span className='login-body-card-form-divider-label'>
|
||||
+ {formatMessage({id: 'login.or', defaultMessage: 'or log in with'})}
|
||||
+ </span>
|
||||
+ </div>
|
||||
+ )}
|
||||
+ {enableBaseLogin && (
|
||||
+ <div
|
||||
+ className='login-body-card-auth-mail-toggle login-btn'
|
||||
+ onClick={toggleEmailForm}
|
||||
+ >
|
||||
+ <span className='icon'/>
|
||||
+ <span className='text'>
|
||||
+ <span>
|
||||
+ {formatMessage({id: 'login.email', defaultMessage: 'Adresse email'})}
|
||||
+ </span>
|
||||
+ </span>
|
||||
+ </div>
|
||||
+ )}
|
||||
{enableBaseLogin && (
|
||||
<form
|
||||
onSubmit={(event: FormEvent<HTMLFormElement>) => {
|
||||
preSubmit(event as unknown as React.MouseEvent);
|
||||
}}
|
||||
>
|
||||
- <div className='login-body-card-form'>
|
||||
+ <div className={'login-body-card-form' + doShowEmailForm}>
|
||||
<Input
|
||||
ref={loginIdInput}
|
||||
name='loginId'
|
||||
@@ -895,16 +940,27 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
- {enableExternalSignup && (
|
||||
- <div className={classNames('login-body-card-form-login-options', {column: !enableBaseLogin})}>
|
||||
- {getExternalLoginOptions().map((option) => (
|
||||
- <ExternalLoginButton
|
||||
- key={option.id}
|
||||
- direction={enableBaseLogin ? undefined : 'column'}
|
||||
- {...option}
|
||||
- />
|
||||
- ))}
|
||||
- </div>
|
||||
+ {enableBaseLogin && (
|
||||
+ <a
|
||||
+ className='login-body-card-auth-exte login-btn'
|
||||
+ href='@exte_login@'
|
||||
+ >
|
||||
+ <span className='icon'/>
|
||||
+ <span className='text'>
|
||||
+ <span>
|
||||
+ {formatMessage({
|
||||
+ id: 'login.noClipperAccount',
|
||||
+ defaultMessage: 'Pas de compte Clipper ?',
|
||||
+ })}
|
||||
+ </span>
|
||||
+ <span>
|
||||
+ {formatMessage({
|
||||
+ id: 'login.createExte',
|
||||
+ defaultMessage: 'Demander un compte extérieur',
|
||||
+ })}
|
||||
+ </span>
|
||||
+ </span>
|
||||
+ </a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
diff --git a/webapp/channels/src/images/emailLogo.png b/webapp/channels/src/images/emailLogo.png
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..098922ea6e827eca14dad9810cb953079a1a623d
|
||||
GIT binary patch
|
||||
literal 605
|
||||
zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4i*Lm28M*4p$rTROiAAEE)2Od`|PeWFfecy
|
||||
zctjR6Fz6|RFk{71`!WUw2KEw9Usv|WENsGR>R+M-zcDZ{zVmc(49U3nc80EpbD%`q
|
||||
z{)Ie(EuBqGY~4qV1X>SXnswG}_QkD|z0oGSN;Yar#caOmqc+)<O{}@8$x)z9da`ZX
|
||||
zYuW2>|Gk@6z5YSvZQ18<Z0+xt&nvbQ)CGaH@_`2yxVG=Oy0FzT@rK=TUC&p2mb?F2
|
||||
z&h{ysHRCVq<tLUK-|#+|94q+kXV=|5{&RV(w=f>QQ|;~Uv*Bp<ns4$slNY-Ef4)26
|
||||
z-2F?UmSH>l&;DyPP1~{MZxV;@e6?3kO!iLeQJJ^X<Lg1Cl|hFKo2?&7sF@l~$<#JB
|
||||
zci!_#<k6!`OHZ0q%1ymtU#YsYLPk{kOtI|Ee{HPO?)F=LeDTYz)00p6ru^ikCstQ8
|
||||
ze|&TAu|tdPuH>2DSN!@ut)aMrGdF)-{NeR8S#BM5o#u2%tANFG!TxGK&eh!yEL9d7
|
||||
zS#qp-vmwx;VZjEew%$vOKMrT{O!7E!<J%^Q?xhdeH#lAt4C7VP*dX_wVT~o<;Zse%
|
||||
zXQC7Movhcq+0d!W;ePpoRaRSK^0LIpTq!H&uf0N%?l(-X%DKFAcpJ3v5r=fE`$qkM
|
||||
z#Ru>3AHV8hVb{_2xWS>9?X$|dlz9fzUpVx#6@SnE=@)eU(-nEOmG)<Y>gO!`YvaGt
|
||||
zAy7_4!^OqIdxy*AKcR~R1ryD#DqWS=xSR<Bf0JvOmpne>k^WoC8<cE3UHx3vIVCg!
|
||||
E0QZ>*HUIzs
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/webapp/channels/src/images/gitlabLogo.png b/webapp/channels/src/images/gitlabLogo.png
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..bdc4422783b804cbaf45f13219354f38e080b654
|
||||
GIT binary patch
|
||||
literal 1655
|
||||
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
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
diff --git a/webapp/channels/src/images/noaccountLogo.png b/webapp/channels/src/images/noaccountLogo.png
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..b51eda513122fe8da10f2fe896b78f380811cc61
|
||||
GIT binary patch
|
||||
literal 693
|
||||
zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4i*Lm28M*4p$rTROiAAEE)2Od`|PeWFfecy
|
||||
zctjR6Fz6|RFk{71`!WUw2KEw9Usv|WENmijEG}<O{bFEXa`SX?49U3ncE*0c!v+G!
|
||||
zlvCHSBrWxJ7vK&ycbVU4+97^IXyc|5SJ9w*4Qp(i1!phU;W(z3w$|a*n^(t!LNDCf
|
||||
zDy#10xHIpn<@cX8-|x=Xc(r7*pVddPUn)<0W^PP4If>PH*%Os7v(0K<+89(=HI>=E
|
||||
zyf92~@oHpYk#zUHYwd2Be(1sq<CH@(u5r8dcQ`A0cCMXes3~+bw)WV0!2>t){;+o#
|
||||
zDp;&PT+_73WOwcH;wc)F0zOLy?6_Zhn4fh*>#X@Ku?a#9jVf3ENI3=Rei3oib&Oe{
|
||||
z)uP<=>G|!=zar1)z7z~r`ty0-{fY6i4kCsu`f&^TlXCuV&~DI3>iLx5Ui2jGRbjJB
|
||||
zQL^potIBSZc2Ada-Su@ni$j#Z^cRo7zSORspJrcKm^)@#8!<Ue|C{K)A&KRoSi=wF
|
||||
z{mG>V6a_rr<gMdzv?@@lwEdI*z@=Kv;O@DGTMSEl-g+6k^)gBrZr0Y7FkwqLaA@6@
|
||||
zCD$by<WAc&EcmKkz~OXm$J0*peE}N#Djs)6pL@mW<SkXydqAb>^#_wXjxKXP@Ep+o
|
||||
z9#eRV(a?~6PSH`@^$a$}LT)Z@TF;vN9~3^%_{LFFB<OUsE$N7&{GQ@W+xnB%@-kt1
|
||||
zZpVuL9O!<xIckNzO^Dv{V{J>G+_1dcr|B#uRO|gLbWzFkxzR?o!BQTMcD^h3>GHEY
|
||||
zxIXPQ+vEpnXUY>dTFzqKdB5J|cJsq6Uq9CHi-}ZkSah>l^{ST4?U>7JD;Mr{eL73_
|
||||
ucFfgvr$eewzlz_NksW*AQ+@6q@1JbVm+nZK2==9blB1`qpUXO@geCxL=_bDb
|
||||
|
||||
literal 0
|
||||
HcmV?d00001
|
||||
|
||||
--
|
||||
2.49.0
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2025 hbarral <hbarral@clipper.ens.fr>
|
||||
|
||||
SPDX-License-Identifier: MIT
|
|
@ -0,0 +1,25 @@
|
|||
From 4b0ad3a8398511843393ea92cc12f0666465a13f Mon Sep 17 00:00:00 2001
|
||||
From: hbarral <hbarral@clipper.ens.fr>
|
||||
Date: Sat, 7 Dec 2024 12:24:09 +0100
|
||||
Subject: [PATCH 2/2] Remove annoying "FREE EDITION" badge from webapp UI This
|
||||
commit should be cherry-picked on top of new Mattermost releases.
|
||||
|
||||
---
|
||||
.../product_branding_team_edition.tsx | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/webapp/channels/src/components/global_header/left_controls/product_menu/product_branding_team_edition/product_branding_team_edition.tsx b/webapp/channels/src/components/global_header/left_controls/product_menu/product_branding_team_edition/product_branding_team_edition.tsx
|
||||
index 2773ba5184..018454c880 100644
|
||||
--- a/webapp/channels/src/components/global_header/left_controls/product_menu/product_branding_team_edition/product_branding_team_edition.tsx
|
||||
+++ b/webapp/channels/src/components/global_header/left_controls/product_menu/product_branding_team_edition/product_branding_team_edition.tsx
|
||||
@@ -43,7 +43,6 @@ const ProductBrandingTeamEdition = (): JSX.Element => {
|
||||
width={116}
|
||||
height={20}
|
||||
/>
|
||||
- <Badge>{'FREE EDITION'}</Badge>
|
||||
</ProductBrandingTeamEditionContainer>
|
||||
);
|
||||
};
|
||||
--
|
||||
2.49.0
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SPDX-FileCopyrightText: 2025 hbarral <hbarral@clipper.ens.fr>
|
||||
|
||||
SPDX-License-Identifier: MIT
|
50
machines/nixos/web02/mattermost/default.nix
Normal file
50
machines/nixos/web02/mattermost/default.nix
Normal file
|
@ -0,0 +1,50 @@
|
|||
# SPDX-FileCopyrightText: 2024 Tom Hubrecht <tom.hubrecht@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
host = "chat.dgnum.eu";
|
||||
port = 8065;
|
||||
|
||||
exte_login = "https://demarches.dgnum.eu/commencer/demande-compte-merle";
|
||||
in
|
||||
|
||||
{
|
||||
imports = [ ./module.nix ];
|
||||
|
||||
services.mattermost = {
|
||||
enable = true;
|
||||
|
||||
inherit port;
|
||||
|
||||
package = pkgs.mattermostLatest.overrideAttrs (old: {
|
||||
webapp = old.webapp.overrideAttrs (wOld: {
|
||||
nativeBuildInputs = wOld.nativeBuildInputs ++ [
|
||||
pkgs.git
|
||||
pkgs.gnused
|
||||
];
|
||||
|
||||
postPatch =
|
||||
(wOld.postPatch or "")
|
||||
+ ''
|
||||
sed -i 's/GitLab/Clipper/g' channels/src/i18n/*.json
|
||||
git apply -p2 < ${pkgs.replaceVars ./0001-Login-page-ENS-theme.patch { inherit exte_login; }}
|
||||
git apply -p2 < ${./0002-Remove-annoying-FREE-EDITION-badge-from-webapp-UI.patch}
|
||||
'';
|
||||
});
|
||||
});
|
||||
|
||||
siteName = "Merle [Discussions ENS]";
|
||||
siteUrl = "https://${host}";
|
||||
|
||||
mutableConfig = true;
|
||||
|
||||
database.peerAuth = true;
|
||||
};
|
||||
|
||||
dgn-web.simpleProxies.mattermost = {
|
||||
inherit host port;
|
||||
};
|
||||
}
|
996
machines/nixos/web02/mattermost/module.nix
Normal file
996
machines/nixos/web02/mattermost/module.nix
Normal file
|
@ -0,0 +1,996 @@
|
|||
# SPDX-FileCopyrightText: The nixpkgs contributors
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib.strings)
|
||||
hasInfix
|
||||
hasSuffix
|
||||
escapeURL
|
||||
concatStringsSep
|
||||
escapeShellArg
|
||||
escapeShellArgs
|
||||
versionAtLeast
|
||||
optionalString
|
||||
;
|
||||
|
||||
inherit (lib.meta) getExe;
|
||||
|
||||
inherit (lib.lists) singleton;
|
||||
|
||||
inherit (lib.attrsets) mapAttrsToList recursiveUpdate optionalAttrs;
|
||||
|
||||
inherit (lib.options) mkOption mkPackageOption mkEnableOption;
|
||||
|
||||
inherit (lib.modules)
|
||||
mkRenamedOptionModule
|
||||
mkMerge
|
||||
mkIf
|
||||
mkDefault
|
||||
;
|
||||
|
||||
inherit (lib.trivial) warnIf throwIf;
|
||||
|
||||
inherit (lib) types;
|
||||
|
||||
cfg = config.services.mattermost;
|
||||
|
||||
# The directory to store mutable data within dataDir.
|
||||
mutableDataDir = "${cfg.dataDir}/data";
|
||||
|
||||
# The plugin directory. Note that this is the *pre-unpack* plugin directory,
|
||||
# since Mattermost looks in mutableDataDir for a directory called "plugins".
|
||||
# If Mattermost is installed with plugins defined in a Nix configuration, the plugins
|
||||
# are symlinked here. Otherwise, this is a real directory and the tarballs are uploaded here.
|
||||
pluginTarballDir = "${mutableDataDir}/plugins";
|
||||
|
||||
# We need a different unpack directory for Mattermost to sync things to at launch,
|
||||
# since the above may be a symlink to the store.
|
||||
pluginUnpackDir = "${mutableDataDir}/.plugins";
|
||||
|
||||
# Mattermost uses this as a staging directory to unpack plugins, among possibly other things.
|
||||
# Ensure that it's inside mutableDataDir since it can get rather large.
|
||||
tempDir = "${mutableDataDir}/tmp";
|
||||
|
||||
# Creates a database URI.
|
||||
mkDatabaseUri =
|
||||
{
|
||||
scheme,
|
||||
user ? null,
|
||||
password ? null,
|
||||
escapeUserAndPassword ? true,
|
||||
host ? null,
|
||||
escapeHost ? true,
|
||||
port ? null,
|
||||
path ? null,
|
||||
query ? { },
|
||||
}:
|
||||
let
|
||||
nullToEmpty = val: if val == null then "" else toString val;
|
||||
|
||||
# Converts a list of URI attrs to a query string.
|
||||
toQuery = mapAttrsToList (
|
||||
name: value: if value == null then null else (escapeURL name) + "=" + (escapeURL (toString value))
|
||||
);
|
||||
|
||||
schemePart = if scheme == null then "" else "${escapeURL scheme}://";
|
||||
userPart =
|
||||
let
|
||||
realUser = if escapeUserAndPassword then escapeURL user else user;
|
||||
realPassword = if escapeUserAndPassword then escapeURL password else password;
|
||||
in
|
||||
if user == null && password == null then
|
||||
""
|
||||
else if user != null && password != null then
|
||||
"${realUser}:${realPassword}"
|
||||
else if user != null then
|
||||
realUser
|
||||
else
|
||||
throw "Either user or username and password must be provided";
|
||||
hostPart =
|
||||
let
|
||||
realHost = if escapeHost then escapeURL (nullToEmpty host) else nullToEmpty host;
|
||||
in
|
||||
if userPart == "" then realHost else "@" + realHost;
|
||||
portPart = if port == null then "" else ":" + (toString port);
|
||||
pathPart = if path == null then "" else "/" + path;
|
||||
queryPart = if query == { } then "" else "?" + concatStringsSep "&" (toQuery query);
|
||||
in
|
||||
schemePart + userPart + hostPart + portPart + pathPart + queryPart;
|
||||
|
||||
database =
|
||||
let
|
||||
hostIsPath = hasInfix "/" cfg.database.host;
|
||||
in
|
||||
if cfg.database.driver == "postgres" then
|
||||
if cfg.database.peerAuth then
|
||||
mkDatabaseUri {
|
||||
scheme = cfg.database.driver;
|
||||
inherit (cfg.database) user;
|
||||
path = escapeURL cfg.database.name;
|
||||
query = {
|
||||
host = cfg.database.socketPath;
|
||||
} // cfg.database.extraConnectionOptions;
|
||||
}
|
||||
else
|
||||
mkDatabaseUri {
|
||||
scheme = cfg.database.driver;
|
||||
inherit (cfg.database) user password;
|
||||
host = if hostIsPath then null else cfg.database.host;
|
||||
port = if hostIsPath then null else cfg.database.port;
|
||||
path = escapeURL cfg.database.name;
|
||||
query =
|
||||
optionalAttrs hostIsPath { inherit (cfg.database) host; } // cfg.database.extraConnectionOptions;
|
||||
}
|
||||
else if cfg.database.driver == "mysql" then
|
||||
if cfg.database.peerAuth then
|
||||
mkDatabaseUri {
|
||||
scheme = null;
|
||||
inherit (cfg.database) user;
|
||||
escapeUserAndPassword = false;
|
||||
host = "unix(${cfg.database.socketPath})";
|
||||
escapeHost = false;
|
||||
path = escapeURL cfg.database.name;
|
||||
query = cfg.database.extraConnectionOptions;
|
||||
}
|
||||
else
|
||||
mkDatabaseUri {
|
||||
scheme = null;
|
||||
inherit (cfg.database) user password;
|
||||
escapeUserAndPassword = false;
|
||||
host =
|
||||
if hostIsPath then
|
||||
"unix(${cfg.database.host})"
|
||||
else
|
||||
"tcp(${cfg.database.host}:${toString cfg.database.port})";
|
||||
escapeHost = false;
|
||||
path = escapeURL cfg.database.name;
|
||||
query = cfg.database.extraConnectionOptions;
|
||||
}
|
||||
else
|
||||
throw "Invalid database driver: ${cfg.database.driver}";
|
||||
|
||||
mattermostPluginDerivations = map (
|
||||
plugin:
|
||||
pkgs.stdenvNoCC.mkDerivation {
|
||||
name = "${cfg.package.name}-plugin";
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/share
|
||||
ln -sf ${plugin} $out/share/plugin.tar.gz
|
||||
runHook postInstall
|
||||
'';
|
||||
dontUnpack = true;
|
||||
dontPatch = true;
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
preferLocalBuild = true;
|
||||
}
|
||||
) cfg.plugins;
|
||||
|
||||
mattermostPlugins =
|
||||
if mattermostPluginDerivations == [ ] then
|
||||
null
|
||||
else
|
||||
pkgs.stdenvNoCC.mkDerivation {
|
||||
name = "${cfg.package.name}-plugins";
|
||||
nativeBuildInputs = [ pkgs.autoPatchelfHook ] ++ mattermostPluginDerivations;
|
||||
buildInputs = [ cfg.package ];
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out
|
||||
plugins=(${
|
||||
escapeShellArgs (map (plugin: "${plugin}/share/plugin.tar.gz") mattermostPluginDerivations)
|
||||
})
|
||||
for plugin in "''${plugins[@]}"; do
|
||||
hash="$(sha256sum "$plugin" | awk '{print $1}')"
|
||||
mkdir -p "$hash"
|
||||
tar -C "$hash" -xzf "$plugin"
|
||||
autoPatchelf "$hash"
|
||||
GZIP_OPT=-9 tar -C "$hash" -cvzf "$out/$hash.tar.gz" .
|
||||
rm -rf "$hash"
|
||||
done
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
dontUnpack = true;
|
||||
dontPatch = true;
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
preferLocalBuild = true;
|
||||
};
|
||||
|
||||
mattermostConfWithoutPlugins = recursiveUpdate {
|
||||
ServiceSettings = {
|
||||
SiteURL = cfg.siteUrl;
|
||||
ListenAddress = "${cfg.host}:${toString cfg.port}";
|
||||
LocalModeSocketLocation = cfg.socket.path;
|
||||
EnableLocalMode = cfg.socket.enable;
|
||||
EnableSecurityFixAlert = cfg.telemetry.enableSecurityAlerts;
|
||||
};
|
||||
TeamSettings.SiteName = cfg.siteName;
|
||||
SqlSettings.DriverName = cfg.database.driver;
|
||||
SqlSettings.DataSource =
|
||||
if cfg.database.fromEnvironment then
|
||||
null
|
||||
else
|
||||
warnIf (!cfg.database.peerAuth && cfg.database.password != null) ''
|
||||
Database password is set in Mattermost config! This password will end up in the Nix store.
|
||||
|
||||
You may be able to simply set the following, if the database is on the same host
|
||||
and peer authentication is enabled:
|
||||
|
||||
services.mattermost.database.peerAuth = true;
|
||||
|
||||
Note that this is the default if you set system.stateVersion to 25.05 or later
|
||||
and the database host is localhost.
|
||||
|
||||
Alternatively, you can write the following to ${
|
||||
if cfg.environmentFile == null then "your environment file" else cfg.environmentFile
|
||||
}:
|
||||
|
||||
MM_SQLSETTINGS_DATASOURCE=${database}
|
||||
|
||||
Then set the following options:
|
||||
services.mattermost.environmentFile = "<your environment file>";
|
||||
services.mattermost.database.fromEnvironment = true;
|
||||
'' database;
|
||||
|
||||
# Note that the plugin tarball directory is not configurable, and is expected to be in FileSettings.Directory/plugins.
|
||||
FileSettings.Directory = mutableDataDir;
|
||||
PluginSettings.Directory = "${pluginUnpackDir}/server";
|
||||
PluginSettings.ClientDirectory = "${pluginUnpackDir}/client";
|
||||
|
||||
LogSettings = {
|
||||
FileLocation = cfg.logDir;
|
||||
|
||||
# Reaches out to Mattermost's servers for telemetry; disable it by default.
|
||||
# https://docs.mattermost.com/configure/environment-configuration-settings.html#enable-diagnostics-and-error-reporting
|
||||
EnableDiagnostics = cfg.telemetry.enableDiagnostics;
|
||||
};
|
||||
} cfg.settings;
|
||||
|
||||
mattermostConf = recursiveUpdate mattermostConfWithoutPlugins (
|
||||
if mattermostPlugins == null then
|
||||
{ }
|
||||
else
|
||||
{
|
||||
PluginSettings = {
|
||||
Enable = true;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
format = pkgs.formats.json { };
|
||||
finalConfig = format.generate "mattermost-config.json" mattermostConf;
|
||||
in
|
||||
{
|
||||
disabledModules = [ "services/web-apps/mattermost.nix" ];
|
||||
|
||||
imports = [
|
||||
(mkRenamedOptionModule
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"listenAddress"
|
||||
]
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"host"
|
||||
]
|
||||
)
|
||||
(mkRenamedOptionModule
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"localDatabaseCreate"
|
||||
]
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"database"
|
||||
"create"
|
||||
]
|
||||
)
|
||||
(mkRenamedOptionModule
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"localDatabasePassword"
|
||||
]
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"database"
|
||||
"password"
|
||||
]
|
||||
)
|
||||
(mkRenamedOptionModule
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"localDatabaseUser"
|
||||
]
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"database"
|
||||
"user"
|
||||
]
|
||||
)
|
||||
(mkRenamedOptionModule
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"localDatabaseName"
|
||||
]
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"database"
|
||||
"name"
|
||||
]
|
||||
)
|
||||
(mkRenamedOptionModule
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"extraConfig"
|
||||
]
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"settings"
|
||||
]
|
||||
)
|
||||
(mkRenamedOptionModule
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"statePath"
|
||||
]
|
||||
[
|
||||
"services"
|
||||
"mattermost"
|
||||
"dataDir"
|
||||
]
|
||||
)
|
||||
];
|
||||
|
||||
options = {
|
||||
services.mattermost = {
|
||||
enable = mkEnableOption "Mattermost chat server";
|
||||
|
||||
package = mkPackageOption pkgs "mattermost" { };
|
||||
|
||||
siteUrl = mkOption {
|
||||
type = types.str;
|
||||
example = "https://chat.example.com";
|
||||
description = ''
|
||||
URL this Mattermost instance is reachable under, without trailing slash.
|
||||
'';
|
||||
};
|
||||
|
||||
siteName = mkOption {
|
||||
type = types.str;
|
||||
default = "Mattermost";
|
||||
description = "Name of this Mattermost site.";
|
||||
};
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
example = "0.0.0.0";
|
||||
description = ''
|
||||
Host or address that this Mattermost instance listens on.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 8065;
|
||||
description = ''
|
||||
Port for Mattermost server to listen on.
|
||||
'';
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/lib/mattermost";
|
||||
description = ''
|
||||
Mattermost working directory.
|
||||
'';
|
||||
};
|
||||
|
||||
socket = {
|
||||
enable = mkEnableOption "Mattermost control socket";
|
||||
|
||||
path = mkOption {
|
||||
type = types.path;
|
||||
default = "${cfg.dataDir}/mattermost.sock";
|
||||
defaultText = ''''${config.mattermost.dataDir}/mattermost.sock'';
|
||||
description = ''
|
||||
Default location for the Mattermost control socket used by `mmctl`.
|
||||
'';
|
||||
};
|
||||
|
||||
export = mkEnableOption "Export socket control to system environment variables";
|
||||
};
|
||||
|
||||
logDir = mkOption {
|
||||
type = types.path;
|
||||
default =
|
||||
if versionAtLeast config.system.stateVersion "25.05" then
|
||||
"/var/log/mattermost"
|
||||
else
|
||||
"${cfg.dataDir}/logs";
|
||||
defaultText = ''
|
||||
if versionAtLeast config.system.stateVersion "25.05" then "/var/log/mattermost"
|
||||
else "''${config.services.mattermost.dataDir}/logs";
|
||||
'';
|
||||
description = ''
|
||||
Mattermost log directory.
|
||||
'';
|
||||
};
|
||||
|
||||
configDir = mkOption {
|
||||
type = types.path;
|
||||
default =
|
||||
if versionAtLeast config.system.stateVersion "25.05" then
|
||||
"/etc/mattermost"
|
||||
else
|
||||
"${cfg.dataDir}/config";
|
||||
defaultText = ''
|
||||
if versionAtLeast config.system.stateVersion "25.05" then
|
||||
"/etc/mattermost"
|
||||
else
|
||||
"''${config.services.mattermost.dataDir}/config";
|
||||
'';
|
||||
description = ''
|
||||
Mattermost config directory.
|
||||
'';
|
||||
};
|
||||
|
||||
mutableConfig = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether the Mattermost config.json is writeable by Mattermost.
|
||||
|
||||
Most of the settings can be edited in the system console of
|
||||
Mattermost if this option is enabled. A template config using
|
||||
the options specified in services.mattermost will be generated
|
||||
but won't be overwritten on changes or rebuilds.
|
||||
|
||||
If this option is disabled, persistent changes in the system
|
||||
console won't be possible (the default). If a config.json is
|
||||
present, it will be overwritten at service start!
|
||||
'';
|
||||
};
|
||||
|
||||
preferNixConfig = mkOption {
|
||||
type = types.bool;
|
||||
default = versionAtLeast config.system.stateVersion "25.05";
|
||||
defaultText = ''
|
||||
versionAtLeast config.system.stateVersion "25.05";
|
||||
'';
|
||||
description = ''
|
||||
If both mutableConfig and this option are set, the Nix configuration
|
||||
will take precedence over any settings configured in the server
|
||||
console.
|
||||
'';
|
||||
};
|
||||
|
||||
plugins = mkOption {
|
||||
type = with types; listOf (either path package);
|
||||
default = [ ];
|
||||
example = "[ ./com.github.moussetc.mattermost.plugin.giphy-2.0.0.tar.gz ]";
|
||||
description = ''
|
||||
Plugins to add to the configuration. Overrides any installed if non-null.
|
||||
This is a list of paths to .tar.gz files or derivations evaluating to
|
||||
.tar.gz files. You can use `mattermost.buildPlugin` to build plugins;
|
||||
see the NixOS documentation for more details.
|
||||
'';
|
||||
};
|
||||
|
||||
pluginsBundle = mkOption {
|
||||
type = with types; nullOr package;
|
||||
default = mattermostPlugins;
|
||||
defaultText = ''
|
||||
All entries in {config}`services.mattermost.plugins`, repacked
|
||||
'';
|
||||
description = ''
|
||||
Derivation building to a directory of plugin tarballs.
|
||||
This overrides {option}`services.mattermost.plugins` if provided.
|
||||
'';
|
||||
};
|
||||
|
||||
telemetry = {
|
||||
enableSecurityAlerts = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
True if we should enable security update checking. This reaches out to Mattermost's servers:
|
||||
https://docs.mattermost.com/manage/telemetry.html#security-update-check-feature
|
||||
'';
|
||||
};
|
||||
|
||||
enableDiagnostics = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
True if we should enable sending diagnostic data. This reaches out to Mattermost's servers:
|
||||
https://docs.mattermost.com/manage/telemetry.html#error-and-diagnostics-reporting-feature
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
environment = mkOption {
|
||||
type = with types; attrsOf (either int str);
|
||||
default = { };
|
||||
description = ''
|
||||
Extra environment variables to export to the Mattermost process
|
||||
from the systemd unit configuration.
|
||||
'';
|
||||
example = {
|
||||
MM_SERVICESETTINGS_SITEURL = "http://example.com";
|
||||
};
|
||||
};
|
||||
|
||||
environmentFile = mkOption {
|
||||
type = with types; nullOr path;
|
||||
default = null;
|
||||
description = ''
|
||||
Environment file (see {manpage}`systemd.exec(5)`
|
||||
"EnvironmentFile=" section for the syntax) which sets config options
|
||||
for mattermost (see [the Mattermost documentation](https://docs.mattermost.com/configure/configuration-settings.html#environment-variables)).
|
||||
|
||||
Settings defined in the environment file will overwrite settings
|
||||
set via Nix or via the {option}`services.mattermost.extraConfig`
|
||||
option.
|
||||
|
||||
Useful for setting config options without their value ending up in the
|
||||
(world-readable) Nix store, e.g. for a database password.
|
||||
'';
|
||||
};
|
||||
|
||||
database = {
|
||||
driver = mkOption {
|
||||
type = types.enum [
|
||||
"postgres"
|
||||
"mysql"
|
||||
];
|
||||
default = "postgres";
|
||||
description = ''
|
||||
The database driver to use (Postgres or MySQL).
|
||||
'';
|
||||
};
|
||||
|
||||
create = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Create a local PostgreSQL or MySQL database for Mattermost automatically.
|
||||
'';
|
||||
};
|
||||
|
||||
peerAuth = mkOption {
|
||||
type = types.bool;
|
||||
default = versionAtLeast config.system.stateVersion "25.05" && cfg.database.host == "localhost";
|
||||
defaultText = ''
|
||||
versionAtLeast config.system.stateVersion "25.05" && config.services.mattermost.database.host == "localhost"
|
||||
'';
|
||||
description = ''
|
||||
If set, will use peer auth instead of connecting to a Postgres server.
|
||||
Use services.mattermost.database.socketPath to configure the socket path.
|
||||
'';
|
||||
};
|
||||
|
||||
socketPath = mkOption {
|
||||
type = types.path;
|
||||
default =
|
||||
if cfg.database.driver == "postgres" then "/run/postgresql" else "/run/mysqld/mysqld.sock";
|
||||
defaultText = ''
|
||||
if config.services.mattermost.database.driver == "postgres" then "/run/postgresql" else "/run/mysqld/mysqld.sock";
|
||||
'';
|
||||
description = ''
|
||||
The database (Postgres or MySQL) socket path.
|
||||
'';
|
||||
};
|
||||
|
||||
fromEnvironment = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Use services.mattermost.environmentFile to configure the database instead of writing the database URI
|
||||
to the Nix store. Useful if you use password authentication with peerAuth set to false.
|
||||
'';
|
||||
};
|
||||
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
default = "mattermost";
|
||||
description = ''
|
||||
Local Mattermost database name.
|
||||
'';
|
||||
};
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "localhost";
|
||||
example = "127.0.0.1";
|
||||
description = ''
|
||||
Host to use for the database. Can also be set to a path if you'd like to connect
|
||||
to a socket using a username and password.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = if cfg.database.driver == "postgres" then 5432 else 3306;
|
||||
defaultText = ''
|
||||
if config.services.mattermost.database.type == "postgres" then 5432 else 3306
|
||||
'';
|
||||
example = 3306;
|
||||
description = ''
|
||||
Port to use for the database.
|
||||
'';
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "mattermost";
|
||||
description = ''
|
||||
Local Mattermost database username.
|
||||
'';
|
||||
};
|
||||
|
||||
password = mkOption {
|
||||
type = types.str;
|
||||
default = "mmpgsecret";
|
||||
description = ''
|
||||
Password for local Mattermost database user. If set and peerAuth is not true,
|
||||
will cause a warning nagging you to use environmentFile instead since it will
|
||||
end up in the Nix store.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConnectionOptions = mkOption {
|
||||
type = with types; attrsOf (either int str);
|
||||
default =
|
||||
if cfg.database.driver == "postgres" then
|
||||
{
|
||||
sslmode = "disable";
|
||||
connect_timeout = 60;
|
||||
}
|
||||
else if cfg.database.driver == "mysql" then
|
||||
{
|
||||
charset = "utf8mb4,utf8";
|
||||
writeTimeout = "60s";
|
||||
readTimeout = "60s";
|
||||
}
|
||||
else
|
||||
throw "Invalid database driver ${cfg.database.driver}";
|
||||
defaultText = ''
|
||||
if config.mattermost.database.driver == "postgres" then
|
||||
{
|
||||
sslmode = "disable";
|
||||
connect_timeout = 60;
|
||||
}
|
||||
else if config.mattermost.database.driver == "mysql" then
|
||||
{
|
||||
charset = "utf8mb4,utf8";
|
||||
writeTimeout = "60s";
|
||||
readTimeout = "60s";
|
||||
}
|
||||
else
|
||||
throw "Invalid database driver";
|
||||
'';
|
||||
description = ''
|
||||
Extra options that are placed in the connection URI's query parameters.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "mattermost";
|
||||
description = ''
|
||||
User which runs the Mattermost service.
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "mattermost";
|
||||
description = ''
|
||||
Group which runs the Mattermost service.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
inherit (format) type;
|
||||
default = { };
|
||||
description = ''
|
||||
Additional configuration options as Nix attribute set in config.json schema.
|
||||
'';
|
||||
};
|
||||
|
||||
matterircd = {
|
||||
enable = mkEnableOption "Mattermost IRC bridge";
|
||||
package = mkPackageOption pkgs "matterircd" { };
|
||||
parameters = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"-mmserver chat.example.com"
|
||||
"-bind [::]:6667"
|
||||
];
|
||||
description = ''
|
||||
Set commandline parameters to pass to matterircd. See
|
||||
<https://github.com/42wim/matterircd#usage> for more information.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
(mkIf cfg.enable {
|
||||
users.users = {
|
||||
${cfg.user} = {
|
||||
inherit (cfg) group;
|
||||
uid = mkIf (cfg.user == "mattermost") config.ids.uids.mattermost;
|
||||
home = cfg.dataDir;
|
||||
isSystemUser = true;
|
||||
packages = [ cfg.package ];
|
||||
};
|
||||
};
|
||||
|
||||
users.groups = {
|
||||
${cfg.group} = {
|
||||
gid = mkIf (cfg.group == "mattermost") config.ids.gids.mattermost;
|
||||
};
|
||||
};
|
||||
|
||||
services.postgresql = mkIf (cfg.database.driver == "postgres" && cfg.database.create) {
|
||||
enable = true;
|
||||
ensureDatabases = singleton cfg.database.name;
|
||||
ensureUsers = singleton {
|
||||
name =
|
||||
throwIf
|
||||
(cfg.database.peerAuth && (cfg.database.user != cfg.user || cfg.database.name != cfg.database.user))
|
||||
''
|
||||
Mattermost database peer auth is enabled and the user, database user, or database name mismatch.
|
||||
Peer authentication will not work.
|
||||
''
|
||||
cfg.database.user;
|
||||
ensureDBOwnership = true;
|
||||
};
|
||||
};
|
||||
|
||||
services.mysql = mkIf (cfg.database.driver == "mysql" && cfg.database.create) {
|
||||
enable = true;
|
||||
package = mkDefault pkgs.mariadb;
|
||||
ensureDatabases = singleton cfg.database.name;
|
||||
ensureUsers = singleton {
|
||||
name = cfg.database.user;
|
||||
ensurePermissions = {
|
||||
"${cfg.database.name}.*" = "ALL PRIVILEGES";
|
||||
};
|
||||
};
|
||||
settings = rec {
|
||||
mysqld = {
|
||||
collation-server = mkDefault "utf8mb4_general_ci";
|
||||
init-connect = mkDefault "SET NAMES utf8mb4";
|
||||
character-set-server = mkDefault "utf8mb4";
|
||||
};
|
||||
mysqld_safe = mysqld;
|
||||
};
|
||||
};
|
||||
|
||||
environment = {
|
||||
variables = mkIf cfg.socket.export {
|
||||
MMCTL_LOCAL = "true";
|
||||
MMCTL_LOCAL_SOCKET_PATH = cfg.socket.path;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules =
|
||||
[
|
||||
"d ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
"d ${cfg.logDir} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
"d ${cfg.configDir} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
"d ${mutableDataDir} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
|
||||
# Make sure tempDir exists and is not a symlink.
|
||||
"R- ${tempDir} - - - - -"
|
||||
"d= ${tempDir} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
|
||||
# Ensure that pluginUnpackDir is a directory.
|
||||
# Don't remove or clean it out since it should be persistent, as this is where plugins are unpacked.
|
||||
"d= ${pluginUnpackDir} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
|
||||
# Ensure that the plugin directories exist.
|
||||
"d= ${mattermostConf.PluginSettings.Directory} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
"d= ${mattermostConf.PluginSettings.ClientDirectory} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
|
||||
# Link in some of the immutable data directories.
|
||||
"L+ ${cfg.dataDir}/bin - - - - ${cfg.package}/bin"
|
||||
"L+ ${cfg.dataDir}/fonts - - - - ${cfg.package}/fonts"
|
||||
"L+ ${cfg.dataDir}/i18n - - - - ${cfg.package}/i18n"
|
||||
"L+ ${cfg.dataDir}/templates - - - - ${cfg.package}/templates"
|
||||
"L+ ${cfg.dataDir}/client - - - - ${cfg.package}/client"
|
||||
]
|
||||
++ (
|
||||
if cfg.pluginsBundle == null then
|
||||
# Create the plugin tarball directory to allow plugin uploads.
|
||||
[
|
||||
"d= ${pluginTarballDir} 0750 ${cfg.user} ${cfg.group} - -"
|
||||
]
|
||||
else
|
||||
# Symlink the plugin tarball directory, removing anything existing, since it's managed by Nix.
|
||||
[ "L+ ${pluginTarballDir} - - - - ${cfg.pluginsBundle}" ]
|
||||
);
|
||||
|
||||
systemd.services.mattermost = rec {
|
||||
description = "Mattermost chat service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = mkMerge [
|
||||
[ "network.target" ]
|
||||
(mkIf (cfg.database.driver == "postgres" && cfg.database.create) [ "postgresql.service" ])
|
||||
(mkIf (cfg.database.driver == "mysql" && cfg.database.create) [ "mysql.service" ])
|
||||
];
|
||||
requires = after;
|
||||
|
||||
environment = mkMerge [
|
||||
{
|
||||
# Use tempDir as this can get rather large, especially if Mattermost unpacks a large number of plugins.
|
||||
TMPDIR = tempDir;
|
||||
}
|
||||
cfg.environment
|
||||
];
|
||||
|
||||
preStart =
|
||||
''
|
||||
dataDir=${escapeShellArg cfg.dataDir}
|
||||
configDir=${escapeShellArg cfg.configDir}
|
||||
logDir=${escapeShellArg cfg.logDir}
|
||||
package=${escapeShellArg cfg.package}
|
||||
nixConfig=${escapeShellArg finalConfig}
|
||||
''
|
||||
+ optionalString (versionAtLeast config.system.stateVersion "25.05") ''
|
||||
# Migrate configs in the pre-25.05 directory structure.
|
||||
oldConfig="$dataDir/config/config.json"
|
||||
newConfig="$configDir/config.json"
|
||||
if [ "$oldConfig" != "$newConfig" ] && [ -f "$oldConfig" ] && [ ! -f "$newConfig" ]; then
|
||||
# Migrate the legacy config location to the new config location
|
||||
echo "Moving legacy config at $oldConfig to $newConfig" >&2
|
||||
mkdir -p "$configDir"
|
||||
mv "$oldConfig" "$newConfig"
|
||||
touch "$configDir/.initial-created"
|
||||
fi
|
||||
|
||||
# Logs too.
|
||||
oldLogs="$dataDir/logs"
|
||||
newLogs="$logDir"
|
||||
if [ "$oldLogs" != "$newLogs" ] && [ -d "$oldLogs" ] && [ ! -f "$newLogs/.initial-created" ]; then
|
||||
# Migrate the legacy log location to the new log location.
|
||||
# Allow this to fail if there aren't any logs to move.
|
||||
echo "Moving legacy logs at $oldLogs to $newLogs" >&2
|
||||
mkdir -p "$newLogs"
|
||||
mv "$oldLogs"/* "$newLogs" || true
|
||||
touch "$newLogs/.initial-created"
|
||||
fi
|
||||
''
|
||||
+ optionalString (!cfg.mutableConfig) ''
|
||||
${getExe pkgs.jq} -s '.[0] * .[1]' "$package/config/config.json" "$nixConfig" > "$configDir/config.json"
|
||||
''
|
||||
+ optionalString cfg.mutableConfig ''
|
||||
if [ ! -e "$configDir/.initial-created" ]; then
|
||||
${getExe pkgs.jq} -s '.[0] * .[1]' "$package/config/config.json" "$nixConfig" > "$configDir/config.json"
|
||||
touch "$configDir/.initial-created"
|
||||
fi
|
||||
''
|
||||
+ optionalString (cfg.mutableConfig && cfg.preferNixConfig) ''
|
||||
echo "$(${getExe pkgs.jq} -s '.[0] * .[1]' "$configDir/config.json" "$nixConfig")" > "$configDir/config.json"
|
||||
'';
|
||||
|
||||
serviceConfig = mkMerge [
|
||||
{
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
ExecStart = "${getExe cfg.package} --config ${cfg.configDir}/config.json";
|
||||
ReadWritePaths = [
|
||||
cfg.dataDir
|
||||
cfg.logDir
|
||||
cfg.configDir
|
||||
];
|
||||
UMask = "0027";
|
||||
Restart = "always";
|
||||
RestartSec = 10;
|
||||
LimitNOFILE = 49152;
|
||||
LockPersonality = true;
|
||||
NoNewPrivileges = true;
|
||||
PrivateDevices = true;
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProtectSystem = "strict";
|
||||
RestrictNamespaces = true;
|
||||
RestrictSUIDSGID = true;
|
||||
EnvironmentFile = cfg.environmentFile;
|
||||
WorkingDirectory = cfg.dataDir;
|
||||
}
|
||||
(mkIf (cfg.dataDir == "/var/lib/mattermost") {
|
||||
StateDirectory = baseNameOf cfg.dataDir;
|
||||
StateDirectoryMode = "0750";
|
||||
})
|
||||
(mkIf (cfg.logDir == "/var/log/mattermost") {
|
||||
LogsDirectory = baseNameOf cfg.logDir;
|
||||
LogsDirectoryMode = "0750";
|
||||
})
|
||||
(mkIf (cfg.configDir == "/etc/mattermost") {
|
||||
ConfigurationDirectory = baseNameOf cfg.configDir;
|
||||
ConfigurationDirectoryMode = "0750";
|
||||
})
|
||||
];
|
||||
|
||||
unitConfig.JoinsNamespaceOf = mkMerge [
|
||||
(mkIf (cfg.database.driver == "postgres" && cfg.database.create) [ "postgresql.service" ])
|
||||
(mkIf (cfg.database.driver == "mysql" && cfg.database.create) [ "mysql.service" ])
|
||||
];
|
||||
};
|
||||
|
||||
assertions = [
|
||||
{
|
||||
# Make sure the URL doesn't have a trailing slash
|
||||
assertion = !(hasSuffix "/" cfg.siteUrl);
|
||||
message = ''
|
||||
services.mattermost.siteUrl should not have a trailing "/".
|
||||
'';
|
||||
}
|
||||
{
|
||||
# Make sure this isn't a host/port pair
|
||||
assertion = !(hasInfix ":" cfg.host && !(hasInfix "[" cfg.host) && !(hasInfix "]" cfg.host));
|
||||
message = ''
|
||||
services.mattermost.host should not include a port. Use services.mattermost.host for the address
|
||||
or hostname, and services.mattermost.port to specify the port separately.
|
||||
'';
|
||||
}
|
||||
];
|
||||
})
|
||||
(mkIf cfg.matterircd.enable {
|
||||
systemd.services.matterircd = {
|
||||
description = "Mattermost IRC bridge service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
User = "nobody";
|
||||
Group = "nogroup";
|
||||
ExecStart = "${getExe cfg.matterircd.package} ${escapeShellArgs cfg.matterircd.parameters}";
|
||||
WorkingDirectory = "/tmp";
|
||||
PrivateTmp = true;
|
||||
Restart = "always";
|
||||
RestartSec = "5";
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ numinit ];
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
versions = [
|
||||
# Supported nixpkgs versions
|
||||
"unstable"
|
||||
"22.11"
|
||||
"23.11"
|
||||
"24.05"
|
||||
"24.11"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue