Add support for uploading avatars (#767)

* Add uploading configured avatar images

* Add avatar assets

* Update docs and sample config

* Add changelog

* Fix sample config

* Add removing avatars when none configured
This commit is contained in:
Justin Carlson 2023-05-24 09:16:37 -04:00 committed by GitHub
parent 9e5b569723
commit 0c4a493c56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 575 additions and 15 deletions

View File

@ -42,6 +42,7 @@ RUN yarn --network-timeout 600000 --production --pure-lockfile && yarn cache cle
COPY --from=builder /src/lib ./
COPY --from=builder /src/public ./public
COPY --from=builder /src/assets ./assets
VOLUME /data
EXPOSE 9993

BIN
assets/feeds_avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
assets/figma_avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
assets/github_avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/gitlab_avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/jira_avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 0.33333333 0.33333333"
version="1.1"
id="svg1630"
inkscape:version="1.2.2 (b0a84865, 2022-12-01)"
sodipodi:docname="feeds_avatar.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1632"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="in"
showgrid="false"
inkscape:zoom="4.28125"
inkscape:cx="94.715328"
inkscape:cy="-14.014599"
inkscape:window-width="2560"
inkscape:window-height="1302"
inkscape:window-x="2560"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1627" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#f8991d;stroke-width:0.000783981;fill-opacity:1"
id="rect16036"
width="0.33333334"
height="0.33333334"
x="0"
y="0" />
<ellipse
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.0113383;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path5270"
cx="0.10655722"
cy="0.22619501"
rx="0.023283437"
ry="0.022608556" />
<path
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.00108608px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 0.08347222,0.16973219 -7.942e-5,-0.032879 c 0.070275,0.00367 0.10927918,0.0539491 0.11023648,0.11071368 h -0.032928 c -5.4632e-4,-0.049895 -0.034473,-0.07602 -0.07722906,-0.0778347 z"
id="path5805"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.00108608px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 0.08434684,0.11703641 0.0833928,0.08363142 c 0.10798627,0.0050099 0.16581867,0.08337597 0.16654766,0.16607045 l -0.0338827,-4.7761e-4 c 0.001483,-0.052895 -0.0376492,-0.13061767 -0.13171092,-0.13218785 z"
id="path5807"
sodipodi:nodetypes="ccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 0.33333333 0.33333333"
version="1.1"
id="svg1630"
inkscape:version="1.2.2 (b0a84865, 2022-12-01)"
sodipodi:docname="figma_avatar.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1632"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="in"
showgrid="false"
inkscape:zoom="4.2812503"
inkscape:cx="62.715324"
inkscape:cy="56.525544"
inkscape:window-width="2560"
inkscape:window-height="1274"
inkscape:window-x="2560"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1627" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#ffffff;stroke-width:0.000783981;fill-opacity:1"
id="rect16036"
width="0.33333334"
height="0.33333334"
x="0"
y="0" />
<g
id="g482"
transform="translate(0.01500414)">
<rect
width="0.11111087"
height="0.16666642"
fill="#000000"
fill-opacity="0"
id="rect240"
x="0.096107043"
y="0.083333619"
style="stroke-width:0.00116931" />
<path
d="m 0.15166251,0.16666672 c 0,-0.0153406 0.0124364,-0.027778 0.0277778,-0.027778 v 0 c 0.015341,0 0.0277777,0.0124366 0.0277777,0.027778 v 0 c 0,0.0153413 -0.0124368,0.0277779 -0.0277777,0.0277779 v 0 c -0.0153414,0 -0.0277778,-0.0124366 -0.0277778,-0.0277779 z"
fill="#1abcfe"
id="path242"
style="stroke-width:0.000389771" />
<path
d="m 0.09610705,0.22222216 c 0,-0.0153406 0.0124365,-0.027778 0.0277777,-0.027778 h 0.0277778 v 0.027778 c 0,0.0153413 -0.0124364,0.027778 -0.0277778,0.027778 v 0 c -0.0153412,0 -0.0277777,-0.0124366 -0.0277777,-0.027778 z"
fill="#0acf83"
id="path244"
style="stroke-width:0.000389771" />
<path
d="m 0.15166251,0.08333365 v 0.05555524 h 0.0277778 c 0.0153414,0 0.0277777,-0.0124366 0.0277777,-0.0277773 v 0 c 0,-0.01534131 -0.0124364,-0.02777796 -0.0277777,-0.02777796 z"
fill="#ff7262"
id="path246"
style="stroke-width:0.000389771" />
<path
d="m 0.09610705,0.11111141 c 0,0.0153413 0.0124365,0.0277773 0.0277777,0.0277773 h 0.0277778 V 0.08333345 h -0.0277778 c -0.0153412,0 -0.0277777,0.01243665 -0.0277777,0.02777796 z"
fill="#f24e1e"
id="path248"
style="stroke-width:0.000389771" />
<path
d="m 0.09610705,0.16666672 c 0,0.0153413 0.0124365,0.0277779 0.0277777,0.0277779 h 0.0277778 v -0.0555552 h -0.0277778 c -0.0153412,0 -0.0277777,0.0124366 -0.0277777,0.0277773 z"
fill="#a259ff"
id="path250"
style="stroke-width:0.000389771" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 0.33333333 0.33333333"
version="1.1"
id="svg1630"
inkscape:version="1.2.2 (b0a84865, 2022-12-01)"
sodipodi:docname="github_avatar.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1632"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="in"
showgrid="false"
inkscape:zoom="12.109204"
inkscape:cx="39.350233"
inkscape:cy="8.0104357"
inkscape:window-width="2560"
inkscape:window-height="1302"
inkscape:window-x="2560"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1627" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#ffffff;stroke-width:0.000783981;fill-opacity:1"
id="rect16036"
width="0.33333334"
height="0.33333334"
x="0"
y="0" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="m 0.16677043,0.04375549 c -0.0691789,0 -0.1251031,0.0563338 -0.1251031,0.12602641 0,0.055709 0.03583264,0.10286558 0.085542,0.11955571 0.006214,0.001255 0.008491,-0.002712 0.008491,-0.006048 0,-0.002922 -2.0487e-4,-0.012936 -2.0487e-4,-0.0233708 -0.0348006,0.007513 -0.0420475,-0.0150232 -0.0420475,-0.0150232 -0.005592,-0.0146055 -0.0138795,-0.0183596 -0.0138795,-0.0183596 -0.0113895,-0.00772 8.2964e-4,-0.00772 8.2964e-4,-0.00772 0.0126345,8.3481e-4 0.0192646,0.0129359 0.0192646,0.0129359 0.0111825,0.0191945 0.0292028,0.0137715 0.0364524,0.0104325 0.001034,-0.008137 0.004351,-0.0137715 0.007872,-0.0169001 -0.0277559,-0.002922 -0.0569588,-0.0137715 -0.0569588,-0.0621797 0,-0.0137715 0.004968,-0.0250378 0.01284,-0.0338003 -0.001242,-0.003129 -0.005593,-0.0160681 0.001245,-0.0333854 0,0 0.010563,-0.003339 0.0343806,0.012936 a 0.12027864,0.12027267 0 0 1 0.031277,-0.004173 c 0.010563,0 0.0213311,0.001463 0.0312744,0.004173 0.0238202,-0.0162752 0.0343833,-0.012936 0.0343833,-0.012936 0.006837,0.0173176 0.002484,0.0302564 0.001241,0.0333854 0.008079,0.008763 0.012843,0.0200291 0.012843,0.0338003 0,0.0484087 -0.0292028,0.059048 -0.0571663,0.0621797 0.004558,0.003964 0.008491,0.0114735 0.008491,0.0233683 0,0.0169001 -2.0484e-4,0.0304638 -2.0484e-4,0.034635 0,0.003339 0.002279,0.007305 0.008491,0.006054 0.0497094,-0.0166952 0.085542,-0.0638492 0.085542,-0.11955826 2.0433e-4,-0.0696935 -0.0559249,-0.12602732 -0.12489634,-0.12602731 z"
fill="#24292f"
id="path361"
style="stroke-width:0.00256072" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 0.33333333 0.33333333"
version="1.1"
id="svg1630"
inkscape:version="1.2.2 (b0a84865, 2022-12-01)"
sodipodi:docname="gitlab_avatar.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1632"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="in"
showgrid="false"
inkscape:zoom="17.125001"
inkscape:cx="28.992699"
inkscape:cy="10.218978"
inkscape:window-width="2560"
inkscape:window-height="1302"
inkscape:window-x="2560"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1627" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#ffffff;stroke-width:0.000783981;fill-opacity:1"
id="rect16036"
width="0.33333334"
height="0.33333334"
x="0"
y="0" />
<g
id="LOGO"
transform="matrix(0.00130172,0,0,0.00130172,-0.08066014,-0.08067311)">
<path
class="cls-1"
d="m 282.83,170.73 -0.27,-0.69 -26.14,-68.22 a 6.81,6.81 0 0 0 -2.69,-3.24 7,7 0 0 0 -8,0.43 7,7 0 0 0 -2.32,3.52 l -17.65,54 h -71.47 l -17.65,-54 a 6.86,6.86 0 0 0 -2.32,-3.53 7,7 0 0 0 -8,-0.43 6.87,6.87 0 0 0 -2.69,3.24 L 97.44,170 l -0.26,0.69 a 48.54,48.54 0 0 0 16.1,56.1 l 0.09,0.07 0.24,0.17 39.82,29.82 19.7,14.91 12,9.06 a 8.07,8.07 0 0 0 9.76,0 l 12,-9.06 19.7,-14.91 40.06,-30 0.1,-0.08 a 48.56,48.56 0 0 0 16.08,-56.04 z"
id="path695"
style="fill:#e24329" />
<path
class="cls-2"
d="m 282.83,170.73 -0.27,-0.69 a 88.3,88.3 0 0 0 -35.15,15.8 L 190,229.25 c 19.55,14.79 36.57,27.64 36.57,27.64 l 40.06,-30 0.1,-0.08 a 48.56,48.56 0 0 0 16.1,-56.08 z"
id="path697"
style="fill:#fc6d26" />
<path
class="cls-3"
d="m 153.43,256.89 19.7,14.91 12,9.06 a 8.07,8.07 0 0 0 9.76,0 l 12,-9.06 19.7,-14.91 c 0,0 -17.04,-12.89 -36.59,-27.64 -19.55,14.75 -36.57,27.64 -36.57,27.64 z"
id="path699"
style="fill:#fca326" />
<path
class="cls-2"
d="M 132.58,185.84 A 88.19,88.19 0 0 0 97.44,170 l -0.26,0.69 a 48.54,48.54 0 0 0 16.1,56.1 l 0.09,0.07 0.24,0.17 39.82,29.82 c 0,0 17,-12.85 36.57,-27.64 z"
id="path701"
style="fill:#fc6d26" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
version="1.1"
id="svg22"
sodipodi:docname="jira_avatar.svg"
inkscape:version="1.2.2 (b0a84865, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview24"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="11.346854"
inkscape:cx="12.999198"
inkscape:cy="14.453345"
inkscape:window-width="2560"
inkscape:window-height="1302"
inkscape:window-x="2560"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="svg22" />
<rect
style="opacity:1;fill:#0052cc;fill-opacity:1;stroke-width:0.941893"
id="rect332"
width="32"
height="32"
x="0"
y="-1.3125472e-07" />
<path
d="M23.7199 7.64001H15.6399C15.6399 9.64001 17.2799 11.28 19.2799 11.28H20.7599V12.72C20.7599 14.72 22.3999 16.36 24.3999 16.36V8.32001C24.4399 7.96001 24.1199 7.64001 23.7199 7.64001Z"
fill="white"
id="path4" />
<path
d="M19.7199 11.64H11.6399C11.6399 13.64 13.2799 15.28 15.2799 15.28H16.7599V16.72C16.7599 18.72 18.3999 20.36 20.3999 20.36V12.36C20.4399 11.96 20.1199 11.64 19.7199 11.64Z"
fill="url(#paint0_linear)"
id="path6" />
<path
d="M15.7199 15.6801H7.63989C7.63989 17.6801 9.27988 19.3201 11.2799 19.3201H12.7599V20.7601C12.7599 22.7601 14.3999 24.4001 16.3999 24.4001V16.4001C16.4399 16.0001 16.1199 15.6801 15.7199 15.6801Z"
fill="url(#paint1_linear)"
id="path8" />
<defs
id="defs20">
<linearGradient
id="paint0_linear"
x1="20.2597"
y1="11.6708"
x2="16.8183"
y2="15.2196"
gradientUnits="userSpaceOnUse">
<stop
offset="0.176"
stop-color="white"
stop-opacity="0.4"
id="stop10" />
<stop
offset="1"
stop-color="white"
id="stop12" />
</linearGradient>
<linearGradient
id="paint1_linear"
x1="16.4844"
y1="15.7246"
x2="12.5054"
y2="19.596"
gradientUnits="userSpaceOnUse">
<stop
offset="0.176"
stop-color="white"
stop-opacity="0.4"
id="stop15" />
<stop
offset="1"
stop-color="white"
id="stop17" />
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 0.33333333 0.33333333"
version="1.1"
id="svg1630"
inkscape:version="1.2.2 (b0a84865, 2022-12-01)"
sodipodi:docname="webhooks_avatar.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1632"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="in"
showgrid="false"
inkscape:zoom="6.0546022"
inkscape:cx="90.096753"
inkscape:cy="-17.011853"
inkscape:window-width="2560"
inkscape:window-height="1302"
inkscape:window-x="2560"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1627" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#ffffff;stroke-width:0.000783981;fill-opacity:1"
id="rect16036"
width="0.33333334"
height="0.33333334"
x="0"
y="0" />
<g
id="g346"
transform="matrix(0.015625,0,0,0.015625,-2.4512961,-2.5012285)">
<g
id="OvHZFw.tif"
transform="matrix(0.12401029,0,0,0.12401029,159.54955,163.29764)">
<g
id="g325">
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="#231f20"
d="m 60.467,50.345 c -5.367,9.022 -10.509,17.759 -15.758,26.43 -1.348,2.226 -2.015,4.039 -0.938,6.869 2.973,7.817 -1.221,15.424 -9.104,17.489 C 27.233,103.081 19.99,98.195 18.515,90.236 17.208,83.191 22.675,76.285 30.442,75.184 31.093,75.091 31.757,75.08 32.851,74.998 36.657,68.616 40.556,62.079 44.666,55.186 37.235,47.797 32.812,39.159 33.791,28.456 34.483,20.89 37.458,14.352 42.896,8.993 53.311,-1.269 69.2,-2.931 81.463,4.946 93.241,12.512 98.635,27.25 94.037,39.864 90.57,38.924 87.079,37.976 83.241,36.935 84.685,29.922 83.617,23.624 78.887,18.229 75.762,14.667 71.752,12.8 67.192,12.112 58.051,10.731 49.076,16.604 46.413,25.576 43.39,35.759 47.965,44.077 60.467,50.345 Z"
id="path319" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="#231f20"
d="m 75.794,39.676 c 3.781,6.67 7.62,13.441 11.425,20.15 19.232,-5.95 33.732,4.696 38.934,16.094 6.283,13.768 1.988,30.075 -10.352,38.569 -12.666,8.72 -28.684,7.23 -39.906,-3.971 2.86,-2.394 5.734,-4.799 8.805,-7.368 11.084,7.179 20.778,6.841 27.975,-1.66 6.137,-7.252 6.004,-18.065 -0.311,-25.165 -7.288,-8.193 -17.05,-8.443 -28.85,-0.578 -4.895,-8.684 -9.875,-17.299 -14.615,-26.046 -1.598,-2.948 -3.363,-4.658 -6.965,-5.282 -6.016,-1.043 -9.9,-6.209 -10.133,-11.997 -0.229,-5.724 3.143,-10.898 8.414,-12.914 5.221,-1.997 11.348,-0.385 14.86,4.054 2.87,3.627 3.782,7.709 2.272,12.182 -0.42,1.247 -0.964,2.454 -1.553,3.932 z"
id="path321" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
fill="#231f20"
d="m 84.831,94.204 c -7.605,0 -15.238,0 -23.152,0 -2.219,9.127 -7.012,16.496 -15.271,21.182 -6.42,3.642 -13.34,4.877 -20.705,3.688 C 12.143,116.887 1.055,104.68 0.079,90.934 -1.026,75.363 9.677,61.522 23.943,58.413 c 0.985,3.577 1.98,7.188 2.965,10.756 -13.089,6.678 -17.619,15.092 -13.956,25.613 3.225,9.259 12.385,14.334 22.331,12.371 10.157,-2.004 15.278,-10.445 14.653,-23.992 9.629,0 19.266,-0.1 28.896,0.049 3.76,0.059 6.663,-0.331 9.496,-3.646 4.664,-5.455 13.248,-4.963 18.271,0.189 5.133,5.265 4.887,13.737 -0.545,18.78 -5.241,4.866 -13.521,4.606 -18.424,-0.637 -1.008,-1.081 -1.802,-2.364 -2.799,-3.692 z"
id="path323" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
assets/webhooks_avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

1
changelog.d/767.feature Normal file
View File

@ -0,0 +1 @@
Add support for uploading bot avatar images.

View File

@ -107,7 +107,7 @@ serviceBots:
- localpart: feeds
displayname: Feeds
avatar: mxc://half-shot.uk/2876e89ccade4cb615e210c458e2a7a6883fe17d
avatar: ./assets/feeds_avatar.png
prefix: "!feeds"
service: feeds
metrics:

View File

@ -20,7 +20,7 @@ For example with this configuration:
serviceBots:
- localpart: feeds
displayname: Feeds
avatar: mxc://half-shot.uk/2876e89ccade4cb615e210c458e2a7a6883fe17d
avatar: "./assets/feeds_avatar.png"
prefix: "!feeds"
service: feeds
```

View File

@ -1,3 +1,6 @@
import { promises as fs } from "fs";
import axios from "axios";
import mime from "mime";
import { Appservice, Intent } from "matrix-bot-sdk";
import { Logger } from "matrix-appservice-bridge";
@ -84,22 +87,122 @@ export default class BotUsersManager {
log.debug(`Ensuring bot user ${botUser.userId} is registered`);
await botUser.intent.ensureRegistered();
// Set up the bot profile
let profile;
await this.ensureProfile(botUser);
}
}
/**
* Ensures the bot user profile display name and avatar image are updated.
*
* @returns Promise resolving when the user profile has been ensured.
*/
private async ensureProfile(botUser: BotUser): Promise<void> {
log.debug(`Ensuring profile for ${botUser.userId} is updated`);
let profile: {
avatar_url?: string,
displayname?: string,
};
try {
profile = await botUser.intent.underlyingClient.getUserProfile(botUser.userId);
} catch {
profile = {}
}
if (botUser.avatar && profile.avatar_url !== botUser.avatar) {
log.info(`Setting avatar for "${botUser.userId}" to ${botUser.avatar}`);
await botUser.intent.underlyingClient.setAvatarUrl(botUser.avatar);
} catch (e) {
log.error(`Failed to get user profile for ${botUser.userId}:`, e);
profile = {};
}
// Update display name if necessary
if (botUser.displayname && profile.displayname !== botUser.displayname) {
log.info(`Setting displayname for "${botUser.userId}" to ${botUser.displayname}`);
try {
await botUser.intent.underlyingClient.setDisplayName(botUser.displayname);
log.info(`Updated displayname for "${botUser.userId}" to ${botUser.displayname}`);
} catch (e) {
log.error(`Failed to set displayname for ${botUser.userId}:`, e);
}
}
if (!botUser.avatar) {
// Unset any avatar
if (profile.avatar_url) {
await botUser.intent.underlyingClient.setAvatarUrl('');
log.info(`Removed avatar for "${botUser.userId}"`);
}
return;
}
if (botUser.avatar.startsWith("mxc://")) {
// Configured avatar is a Matrix content URL
if (profile.avatar_url === botUser.avatar) {
// Avatar is current, no need to update
log.debug(`Avatar for ${botUser.userId} is already updated`);
return;
}
try {
await botUser.intent.underlyingClient.setAvatarUrl(botUser.avatar);
log.info(`Updated avatar for ${botUser.userId} to ${botUser.avatar}`);
} catch (e) {
log.error(`Failed to set avatar for ${botUser.userId}:`, e);
}
return;
}
// Otherwise assume configured avatar is a file path
let avatarImage: {
image: Buffer,
contentType: string,
};
try {
const contentType = mime.getType(botUser.avatar);
if (!contentType) {
throw new Error("Could not determine content type");
}
// File path
avatarImage = {
image: await fs.readFile(botUser.avatar),
contentType,
};
} catch (e) {
log.error(`Failed to load avatar at ${botUser.avatar}:`, e);
return;
}
// Determine if an avatar update is needed
if (profile.avatar_url) {
try {
const res = await axios.get(
botUser.intent.underlyingClient.mxcToHttp(profile.avatar_url),
{ responseType: "arraybuffer" },
);
const currentAvatarImage = {
image: Buffer.from(res.data),
contentType: res.headers["content-type"],
};
if (
currentAvatarImage.image.equals(avatarImage.image)
&& currentAvatarImage.contentType === avatarImage.contentType
) {
// Avatar is current, no need to update
log.debug(`Avatar for ${botUser.userId} is already updated`);
return;
}
} catch (e) {
log.error(`Failed to get current avatar image for ${botUser.userId}:`, e);
}
}
// Update the avatar
try {
const uploadedAvatarMxcUrl = await botUser.intent.underlyingClient.uploadContent(
avatarImage.image,
avatarImage.contentType,
);
await botUser.intent.underlyingClient.setAvatarUrl(uploadedAvatarMxcUrl);
log.info(`Updated avatar for ${botUser.userId} to ${uploadedAvatarMxcUrl}`);
} catch (e) {
log.error(`Failed to set avatar for ${botUser.userId}:`, e);
}
}
private async getJoinedRooms(): Promise<void> {

View File

@ -53,7 +53,7 @@ export const DefaultConfigRoot: BridgeConfigRoot = {
{
localpart: "feeds",
displayname: "Feeds",
avatar: "mxc://half-shot.uk/2876e89ccade4cb615e210c458e2a7a6883fe17d",
avatar: "./assets/feeds_avatar.png",
prefix: "!feeds",
service: "feeds",
},