|
@ -40,4 +40,12 @@ Developer wanted! If you have time it would be awesome if you could help to enha
|
||||||
<admin>OCA\BigBlueButton\Settings\Admin</admin>
|
<admin>OCA\BigBlueButton\Settings\Admin</admin>
|
||||||
<personal-section>OCA\BigBlueButton\Settings\Section</personal-section>
|
<personal-section>OCA\BigBlueButton\Settings\Section</personal-section>
|
||||||
</settings>
|
</settings>
|
||||||
|
<activity>
|
||||||
|
<settings>
|
||||||
|
<setting>OCA\BigBlueButton\Activity\Setting</setting>
|
||||||
|
</settings>
|
||||||
|
<providers>
|
||||||
|
<provider>OCA\BigBlueButton\Activity\Provider</provider>
|
||||||
|
</providers>
|
||||||
|
</activity>
|
||||||
</info>
|
</info>
|
||||||
|
|
|
@ -14,5 +14,7 @@ return [
|
||||||
['name' => 'server#delete_record', 'url' => '/server/record/{recordId}', 'verb' => 'DELETE'],
|
['name' => 'server#delete_record', 'url' => '/server/record/{recordId}', 'verb' => 'DELETE'],
|
||||||
['name' => 'join#index', 'url' => '/b/{token}', 'verb' => 'GET'],
|
['name' => 'join#index', 'url' => '/b/{token}', 'verb' => 'GET'],
|
||||||
['name' => 'restriction#user', 'url' => '/restrictions/user', 'verb' => 'GET'],
|
['name' => 'restriction#user', 'url' => '/restrictions/user', 'verb' => 'GET'],
|
||||||
|
['name' => 'hook#meetingEnded', 'url' => '/hook/ended/{token}/{mac}', 'verb' => 'GET'],
|
||||||
|
['name' => 'hook#recordingReady', 'url' => '/hook/recording/{token}/{mac}', 'verb' => 'GET'],
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
After Width: | Height: | Size: 397 B |
|
@ -0,0 +1,68 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="32"
|
||||||
|
width="32"
|
||||||
|
version="1.0"
|
||||||
|
viewBox="0 0 32 32"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="meeting-ended.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||||
|
inkscape:export-filename="/home/klaus/Repos/cloud_bbb/img/actions/meeting-started.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1479"
|
||||||
|
inkscape:window-height="997"
|
||||||
|
id="namedview6"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="10.429825"
|
||||||
|
inkscape:cx="-15.100081"
|
||||||
|
inkscape:cy="6.1114182"
|
||||||
|
inkscape:window-x="1889"
|
||||||
|
inkscape:window-y="504"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.48244119;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 6.140625,2 C 3.8448872,2 2,3.9362265 2,6.2421875 V 25.757812 C 2,28.063773 3.8448872,30 6.140625,30 h 19.71875 C 28.155113,30 30,28.063773 30,25.757812 V 6.2421875 C 30,3.9362265 28.155113,2 25.859375,2 Z m 0,2.4824219 h 19.71875 c 0.917462,0 1.658203,0.7417266 1.658203,1.7597656 V 25.757812 c 0,1.01804 -0.740741,1.759766 -1.658203,1.759766 H 6.140625 c -0.9174623,0 -1.6582031,-0.741726 -1.6582031,-1.759766 V 6.2421875 c 0,-1.018039 0.7407408,-1.7597656 1.6582031,-1.7597656 z"
|
||||||
|
id="rect817"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<rect
|
||||||
|
style="opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.70519036;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
id="rect820"
|
||||||
|
width="13.231286"
|
||||||
|
height="13.231286"
|
||||||
|
x="9.3843575"
|
||||||
|
y="9.3843575"
|
||||||
|
rx="0"
|
||||||
|
ry="0" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 505 B |
|
@ -0,0 +1,69 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="32"
|
||||||
|
width="32"
|
||||||
|
version="1.0"
|
||||||
|
viewBox="0 0 32 32"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="meeting-started.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||||
|
inkscape:export-filename="/home/klaus/Repos/cloud_bbb/img/actions/room-created.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1479"
|
||||||
|
inkscape:window-height="997"
|
||||||
|
id="namedview6"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="10.429825"
|
||||||
|
inkscape:cx="-15.100081"
|
||||||
|
inkscape:cy="6.1114182"
|
||||||
|
inkscape:window-x="1889"
|
||||||
|
inkscape:window-y="504"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.48244119;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 6.140625,2 C 3.8448872,2 2,3.9362265 2,6.2421875 V 25.757812 C 2,28.063773 3.8448872,30 6.140625,30 h 19.71875 C 28.155113,30 30,28.063773 30,25.757812 V 6.2421875 C 30,3.9362265 28.155113,2 25.859375,2 Z m 0,2.4824219 h 19.71875 c 0.917462,0 1.658203,0.7417266 1.658203,1.7597656 V 25.757812 c 0,1.01804 -0.740741,1.759766 -1.658203,1.759766 H 6.140625 c -0.9174623,0 -1.6582031,-0.741726 -1.6582031,-1.759766 V 6.2421875 c 0,-1.018039 0.7407408,-1.7597656 1.6582031,-1.7597656 z"
|
||||||
|
id="rect817"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:18.66666603px;line-height:125%;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue';letter-spacing:0px;word-spacing:0px;fill:#44aa00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
x="4.2549443"
|
||||||
|
y="20.848959"
|
||||||
|
id="text816"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan814"
|
||||||
|
x="4.2549443"
|
||||||
|
y="20.848959"> ▶</tspan></text>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 611 B |
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="32"
|
||||||
|
width="32"
|
||||||
|
version="1.0"
|
||||||
|
viewBox="0 0 32 32"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="recording-ready.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||||
|
inkscape:export-filename="/home/klaus/Repos/cloud_bbb/img/actions/meeting-ended.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1479"
|
||||||
|
inkscape:window-height="997"
|
||||||
|
id="namedview6"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="10.429825"
|
||||||
|
inkscape:cx="-15.100081"
|
||||||
|
inkscape:cy="5.6320238"
|
||||||
|
inkscape:window-x="1889"
|
||||||
|
inkscape:window-y="504"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.48244119;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 6.140625,2 C 3.8448872,2 2,3.9362265 2,6.2421875 V 25.757812 C 2,28.063773 3.8448872,30 6.140625,30 h 19.71875 C 28.155113,30 30,28.063773 30,25.757812 V 6.2421875 C 30,3.9362265 28.155113,2 25.859375,2 Z m 0,2.4824219 h 19.71875 c 0.917462,0 1.658203,0.7417266 1.658203,1.7597656 V 25.757812 c 0,1.01804 -0.740741,1.759766 -1.658203,1.759766 H 6.140625 c -0.9174623,0 -1.6582031,-0.741726 -1.6582031,-1.759766 V 6.2421875 c 0,-1.018039 0.7407408,-1.7597656 1.6582031,-1.7597656 z"
|
||||||
|
id="rect817"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<circle
|
||||||
|
style="opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.81180269;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
|
||||||
|
id="path841"
|
||||||
|
cx="16"
|
||||||
|
cy="16"
|
||||||
|
r="7.3826737" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 695 B |
|
@ -0,0 +1,70 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="32"
|
||||||
|
width="32"
|
||||||
|
version="1.0"
|
||||||
|
viewBox="0 0 32 32"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="room-created.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||||
|
inkscape:export-filename="/home/klaus/Repos/cloud_bbb/img/actions/room-created.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1479"
|
||||||
|
inkscape:window-height="997"
|
||||||
|
id="namedview6"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="10.429825"
|
||||||
|
inkscape:cx="-15.100081"
|
||||||
|
inkscape:cy="6.5908126"
|
||||||
|
inkscape:window-x="1889"
|
||||||
|
inkscape:window-y="504"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg4" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.48244119;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 6.140625,2 C 3.8448872,2 2,3.9362265 2,6.2421875 V 25.757812 C 2,28.063773 3.8448872,30 6.140625,30 h 19.71875 C 28.155113,30 30,28.063773 30,25.757812 V 6.2421875 C 30,3.9362265 28.155113,2 25.859375,2 Z m 0,2.4824219 h 19.71875 c 0.917462,0 1.658203,0.7417266 1.658203,1.7597656 V 25.757812 c 0,1.01804 -0.740741,1.759766 -1.658203,1.759766 H 6.140625 c -0.9174623,0 -1.6582031,-0.741726 -1.6582031,-1.759766 V 6.2421875 c 0,-1.018039 0.7407408,-1.7597656 1.6582031,-1.7597656 z"
|
||||||
|
id="rect817"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<g
|
||||||
|
aria-label="+"
|
||||||
|
transform="matrix(1.5934936,0,0,1.2502401,-6.542738,-6.5950957)"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:23.68428612px;line-height:125%;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue';letter-spacing:0px;word-spacing:0px;fill:#44aa00;fill-opacity:1;stroke:none;stroke-width:1.26880109px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
id="text817">
|
||||||
|
<path
|
||||||
|
d="m 13.196362,25.27142 0.307896,0.189474 0.213158,-0.16579 v 0.09474 l 0.236843,-0.09474 0.09474,0.09474 0.142106,-0.09474 h 0.568423 l 0.142106,-0.07105 h 0.33158 l 0.378948,-1.018424 0.118422,-0.82895 -0.118422,-0.402633 0.07105,-0.09474 V 21.95562 l 0.09474,-0.947372 0.07105,-1.894743 h 1.634216 l 1.278951,-0.07105 0.757898,-0.236842 0.16579,-0.16579 v -0.307896 l 0.09474,-0.378949 v -0.260527 l 0.07105,-0.307896 v -0.521054 l -0.402633,-0.49737 h -0.213159 l -0.09474,-0.07105 h -3.292116 v -2.581587 l -0.16579,-1.6579 -0.473686,-1.184214 -0.142105,-0.142106 h -0.781582 l -0.33158,0.07105 -0.07105,0.189474 -0.236842,-0.118421 h -0.378949 l -0.16579,0.16579 v 5.257911 h -2.98422 l -1.16053,0.236843 -0.3552643,0.16579 -0.1894743,0.615792 0.071053,0.07105 -0.071053,0.473686 0.094737,0.189474 -0.094737,0.189475 -0.094737,0.473685 0.1421058,0.16579 2.2736908,0.16579 h 1.752638 l 0.450001,0.07105 -0.09474,3.955276 0.09474,0.99474 z"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Bocadillo;-inkscape-font-specification:Bocadillo;fill:#44aa00;stroke-width:1.26880109px"
|
||||||
|
id="path819"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 704 B |
After Width: | Height: | Size: 9.4 KiB |
After Width: | Height: | Size: 611 B |
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="32"
|
||||||
|
width="32"
|
||||||
|
version="1.0"
|
||||||
|
viewBox="0 0 32 32"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="share-created.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||||
|
inkscape:export-filename="/home/klaus/Repos/cloud_bbb/img/actions/share-created.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1907"
|
||||||
|
inkscape:window-height="997"
|
||||||
|
id="namedview6"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="7.375"
|
||||||
|
inkscape:cx="-50.305084"
|
||||||
|
inkscape:cy="5.7142748"
|
||||||
|
inkscape:window-x="1511"
|
||||||
|
inkscape:window-y="343"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg4"
|
||||||
|
showguides="false" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.48244119;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 6.140625,2 C 3.8448872,2 2,3.9362265 2,6.2421875 V 25.757812 C 2,28.063773 3.8448872,30 6.140625,30 h 19.71875 C 28.155113,30 30,28.063773 30,25.757812 V 6.2421875 C 30,3.9362265 28.155113,2 25.859375,2 Z m 0,2.4824219 h 19.71875 c 0.917462,0 1.658203,0.7417266 1.658203,1.7597656 V 25.757812 c 0,1.01804 -0.740741,1.759766 -1.658203,1.759766 H 6.140625 c -0.9174623,0 -1.6582031,-0.741726 -1.6582031,-1.759766 V 6.2421875 c 0,-1.018039 0.7407408,-1.7597656 1.6582031,-1.7597656 z"
|
||||||
|
id="rect817"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#008000"
|
||||||
|
d="m 20.363645,9.0002321 a 2.5,2.5 0 0 0 -2.5,2.4999999 2.5,2.5 0 0 0 0.0059,0.128906 l -4.904297,2.451172 a 2.5,2.5 0 0 0 -1.601563,-0.580078 2.5,2.5 0 0 0 -2.5,2.5 2.5,2.5 0 0 0 2.5,2.5 2.5,2.5 0 0 0 1.601563,-0.582032 l 4.90625,2.453125 a 2.5,2.5 0 0 0 -0.0078,0.128907 2.5,2.5 0 0 0 2.5,2.5 2.5,2.5 0 0 0 2.5,-2.5 2.5,2.5 0 0 0 -2.5,-2.5 2.5,2.5 0 0 0 -1.599609,0.582031 l -4.90625,-2.453125 a 2.5,2.5 0 0 0 0.0059,-0.128906 2.5,2.5 0 0 0 -0.0039,-0.128907 L 18.762083,13.4182 a 2.5,2.5 0 0 0 1.601562,0.582032 2.5,2.5 0 0 0 2.5,-2.5 2.5,2.5 0 0 0 -2.5,-2.4999999 z"
|
||||||
|
id="circle814"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 596 B |
|
@ -0,0 +1,65 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
height="32"
|
||||||
|
width="32"
|
||||||
|
version="1.0"
|
||||||
|
viewBox="0 0 32 32"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="share-deleted.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
|
||||||
|
inkscape:export-filename="/home/klaus/Repos/cloud_bbb/img/actions/share-deleted.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs8" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1907"
|
||||||
|
inkscape:window-height="997"
|
||||||
|
id="namedview6"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="7.375"
|
||||||
|
inkscape:cx="-50.576271"
|
||||||
|
inkscape:cy="6.3922409"
|
||||||
|
inkscape:window-x="1511"
|
||||||
|
inkscape:window-y="343"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg4"
|
||||||
|
showguides="false" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.48244119;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 6.140625,2 C 3.8448872,2 2,3.9362265 2,6.2421875 V 25.757812 C 2,28.063773 3.8448872,30 6.140625,30 h 19.71875 C 28.155113,30 30,28.063773 30,25.757812 V 6.2421875 C 30,3.9362265 28.155113,2 25.859375,2 Z m 0,2.4824219 h 19.71875 c 0.917462,0 1.658203,0.7417266 1.658203,1.7597656 V 25.757812 c 0,1.01804 -0.740741,1.759766 -1.658203,1.759766 H 6.140625 c -0.9174623,0 -1.6582031,-0.741726 -1.6582031,-1.759766 V 6.2421875 c 0,-1.018039 0.7407408,-1.7597656 1.6582031,-1.7597656 z"
|
||||||
|
id="rect817"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
<path
|
||||||
|
style="fill:#ff0000"
|
||||||
|
d="m 20.363645,9.0002321 a 2.5,2.5 0 0 0 -2.5,2.4999999 2.5,2.5 0 0 0 0.0059,0.128906 l -4.904297,2.451172 a 2.5,2.5 0 0 0 -1.601563,-0.580078 2.5,2.5 0 0 0 -2.5,2.5 2.5,2.5 0 0 0 2.5,2.5 2.5,2.5 0 0 0 1.601563,-0.582032 l 4.90625,2.453125 a 2.5,2.5 0 0 0 -0.0078,0.128907 2.5,2.5 0 0 0 2.5,2.5 2.5,2.5 0 0 0 2.5,-2.5 2.5,2.5 0 0 0 -2.5,-2.5 2.5,2.5 0 0 0 -1.599609,0.582031 l -4.90625,-2.453125 a 2.5,2.5 0 0 0 0.0059,-0.128906 2.5,2.5 0 0 0 -0.0039,-0.128907 L 18.762083,13.4182 a 2.5,2.5 0 0 0 1.601562,0.582032 2.5,2.5 0 0 0 2.5,-2.5 2.5,2.5 0 0 0 -2.5,-2.4999999 z"
|
||||||
|
id="circle814"
|
||||||
|
inkscape:connector-curvature="0" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 4.1 KiB |
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Activity;
|
||||||
|
|
||||||
|
use OCP\EventDispatcher\Event;
|
||||||
|
use OCP\EventDispatcher\IEventListener;
|
||||||
|
use OCP\Activity\IManager as IActivityManager;
|
||||||
|
use OCA\BigBlueButton\Event\MeetingStartedEvent;
|
||||||
|
use OCA\BigBlueButton\Event\MeetingEndedEvent;
|
||||||
|
use OCA\BigBlueButton\Event\RecordingReadyEvent;
|
||||||
|
use OCA\BigBlueButton\AppInfo\Application;
|
||||||
|
use OCP\IUserSession;
|
||||||
|
|
||||||
|
class MeetingListener implements IEventListener {
|
||||||
|
|
||||||
|
/** @var IActivityManager */
|
||||||
|
private $activityManager;
|
||||||
|
|
||||||
|
/** @var IUserSession */
|
||||||
|
private $userSession;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
IActivityManager $activityManager,
|
||||||
|
IUserSession $userSession) {
|
||||||
|
$this->activityManager = $activityManager;
|
||||||
|
$this->userSession = $userSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Event $event): void {
|
||||||
|
if ($event instanceof MeetingStartedEvent) {
|
||||||
|
$subject = Provider::MEETING_STARTED;
|
||||||
|
} elseif ($event instanceof MeetingEndedEvent) {
|
||||||
|
$subject = Provider::MEETING_ENDED;
|
||||||
|
} elseif ($event instanceof RecordingReadyEvent) {
|
||||||
|
$subject = Provider::RECORDING_READY;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$room = $event->getRoom();
|
||||||
|
$activityEvent = $this->activityManager->generateEvent();
|
||||||
|
|
||||||
|
if (!$this->userSession->isLoggedIn()) {
|
||||||
|
$activityEvent->setAuthor($room->getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
$subjectData = [
|
||||||
|
'id' => $room->getId(),
|
||||||
|
'name' => $room->getName(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($event instanceof MeetingEndedEvent) {
|
||||||
|
$subjectData['recordingMarks'] = $event->hasRecordingMarks();
|
||||||
|
}
|
||||||
|
|
||||||
|
$activityEvent->setApp(Application::ID);
|
||||||
|
$activityEvent->setType(Setting::Identifier);
|
||||||
|
$activityEvent->setAffectedUser($room->getUserId());
|
||||||
|
$activityEvent->setSubject($subject, $subjectData);
|
||||||
|
|
||||||
|
$this->activityManager->publish($activityEvent);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,251 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Activity;
|
||||||
|
|
||||||
|
use OCA\BigBlueButton\AppInfo\Application;
|
||||||
|
use OCA\BigBlueButton\Db\RoomShare;
|
||||||
|
use OCP\Activity\IProvider;
|
||||||
|
use OCP\Activity\IEvent;
|
||||||
|
use OCP\Activity\IManager;
|
||||||
|
use OCP\IL10N;
|
||||||
|
use OCP\IUserManager;
|
||||||
|
use OCP\IGroupManager;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
|
use OCP\L10N\IFactory;
|
||||||
|
use OCP\IUser;
|
||||||
|
|
||||||
|
class Provider implements IProvider {
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public const ROOM_CREATED = 'room_created';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public const ROOM_DELETED = 'room_deleted';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public const SHARE_CREATED = 'share_created';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public const SHARE_DELETED = 'share_deleted';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public const MEETING_STARTED = 'meeting_started';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public const MEETING_ENDED = 'meeting_ended';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public const RECORDING_READY = 'recording_ready';
|
||||||
|
|
||||||
|
/** @var IL10N */
|
||||||
|
protected $l;
|
||||||
|
|
||||||
|
/** @var IManager */
|
||||||
|
protected $activityManager;
|
||||||
|
|
||||||
|
/** @var IUserManager */
|
||||||
|
protected $userManager;
|
||||||
|
|
||||||
|
/** @var IGroupManager */
|
||||||
|
protected $groupManager;
|
||||||
|
|
||||||
|
/** @var IURLGenerator */
|
||||||
|
protected $url;
|
||||||
|
|
||||||
|
/** @var IFactory */
|
||||||
|
protected $languageFactory;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
IManager $manager,
|
||||||
|
IUserManager $userManager,
|
||||||
|
IGroupManager $groupManager,
|
||||||
|
IURLGenerator $url,
|
||||||
|
IFactory $languageFactory
|
||||||
|
) {
|
||||||
|
$this->activityManager = $manager;
|
||||||
|
$this->userManager = $userManager;
|
||||||
|
$this->groupManager = $groupManager;
|
||||||
|
$this->url = $url;
|
||||||
|
$this->languageFactory = $languageFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse($language, IEvent $event, IEvent $previousEvent = null) {
|
||||||
|
if ($event->getApp() !== Application::ID) {
|
||||||
|
throw new \InvalidArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->l = $this->languageFactory->get(Application::ID, $language);
|
||||||
|
|
||||||
|
$subject = $event->getSubject();
|
||||||
|
|
||||||
|
if ($subject === self::ROOM_CREATED) {
|
||||||
|
$this->parseRoomCreated($event);
|
||||||
|
} elseif ($subject === self::ROOM_DELETED) {
|
||||||
|
$this->parseRoomDeleted($event);
|
||||||
|
} elseif ($subject === self::SHARE_CREATED) {
|
||||||
|
$this->parseShareCreated($event);
|
||||||
|
} elseif ($subject === self::SHARE_DELETED) {
|
||||||
|
$this->parseShareDeleted($event);
|
||||||
|
} elseif ($subject === self::MEETING_STARTED) {
|
||||||
|
$this->parseMeetingStarted($event);
|
||||||
|
} elseif ($subject === self::MEETING_ENDED) {
|
||||||
|
$this->parseMeetingEnded($event);
|
||||||
|
} elseif ($subject === self::RECORDING_READY) {
|
||||||
|
$this->parseRecordingReady($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $event;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseRoomCreated(IEvent $event) {
|
||||||
|
$params = $event->getSubjectParameters();
|
||||||
|
|
||||||
|
$event->setParsedSubject($this->l->t('You created the room %s.', [$params['name']]));
|
||||||
|
|
||||||
|
$this->setIcon($event, 'room-created');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseRoomDeleted(IEvent $event) {
|
||||||
|
$params = $event->getSubjectParameters();
|
||||||
|
|
||||||
|
if ($this->activityManager->getCurrentUserId() === $event->getAuthor()) {
|
||||||
|
$event->setParsedSubject($this->l->t('You deleted the room %s.', [$params['name']]));
|
||||||
|
} else {
|
||||||
|
$subject = $this->l->t('{user} deleted the room %s', [$params['name']]);
|
||||||
|
|
||||||
|
$this->setSubjects($event, $subject, [
|
||||||
|
'user' => $this->getUser($event->getAuthor()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setIcon($event, 'room-deleted');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseShareCreated(IEvent $event) {
|
||||||
|
$params = $event->getSubjectParameters();
|
||||||
|
|
||||||
|
if ($this->activityManager->getCurrentUserId() === $event->getAuthor()) {
|
||||||
|
$subject = $this->l->t('You shared the room %s with {shareWith}.', [$params['name']]);
|
||||||
|
} else {
|
||||||
|
$subject = $this->l->t('{user} shared the room %s with you.', [$params['name']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setSubjects($event, $subject, [
|
||||||
|
'user' => $this->getUser($event->getAuthor()),
|
||||||
|
'shareWith' => $params['shareType'] === RoomShare::SHARE_TYPE_USER ? $this->getUser($params['shareWith']) : $this->getGroup($params['shareWith']),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->setIcon($event, 'share-created');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseShareDeleted(IEvent $event) {
|
||||||
|
$params = $event->getSubjectParameters();
|
||||||
|
|
||||||
|
if ($this->activityManager->getCurrentUserId() === $event->getAuthor()) {
|
||||||
|
$subject = $this->l->t('You unshared the room %s with {shareWith}.', [$params['name']]);
|
||||||
|
} else {
|
||||||
|
$subject = $this->l->t('{user} unshared the room %s with you.', [$params['name']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setSubjects($event, $subject, [
|
||||||
|
'user' => $this->getUser($event->getAuthor()),
|
||||||
|
'shareWith' => $params['shareType'] === RoomShare::SHARE_TYPE_USER ? $this->getUser($params['shareWith']) : $this->getGroup($params['shareWith']),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->setIcon($event, 'share-deleted');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseMeetingStarted(IEvent $event) {
|
||||||
|
$params = $event->getSubjectParameters();
|
||||||
|
|
||||||
|
if ($this->activityManager->getCurrentUserId() === $event->getAuthor()) {
|
||||||
|
$subject = $this->l->t('You started a meeting in the "%s" room.', [$params['name']]);
|
||||||
|
} else {
|
||||||
|
$subject = $this->l->t('{user} started a meeting in the "%s" room.', [$params['name']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setSubjects($event, $subject, [
|
||||||
|
'user' => $this->getUser($event->getAuthor()),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->setIcon($event, 'meeting-started');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseMeetingEnded(IEvent $event) {
|
||||||
|
$params = $event->getSubjectParameters();
|
||||||
|
|
||||||
|
$event->setParsedSubject($this->l->t('The meeting in room "%s" has ended.', [$params['name']]));
|
||||||
|
|
||||||
|
$this->setIcon($event, 'meeting-ended');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseRecordingReady(IEvent $event) {
|
||||||
|
$params = $event->getSubjectParameters();
|
||||||
|
|
||||||
|
$event->setParsedSubject($this->l->t('Recording for room "%s" is ready.', [$params['name']]));
|
||||||
|
|
||||||
|
$this->setIcon($event, 'recording-ready');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setIcon(IEvent $event, string $baseName) {
|
||||||
|
if ($this->activityManager->getRequirePNG()) {
|
||||||
|
$imagePath = $this->url->imagePath(Application::ID, 'actions/'.$baseName.'.png');
|
||||||
|
} else {
|
||||||
|
$imagePath = $this->url->imagePath(Application::ID, 'actions/'.$baseName.'.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
$event->setIcon($this->url->getAbsoluteURL($imagePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setSubjects(IEvent $event, $subject, array $parameters) {
|
||||||
|
$placeholders = $replacements = [];
|
||||||
|
|
||||||
|
foreach ($parameters as $placeholder => $parameter) {
|
||||||
|
$placeholders[] = '{' . $placeholder . '}';
|
||||||
|
if ($parameter['type'] === 'file') {
|
||||||
|
$replacements[] = $parameter['path'];
|
||||||
|
} else {
|
||||||
|
$replacements[] = $parameter['name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$event->setParsedSubject(str_replace($placeholders, $replacements, $subject))
|
||||||
|
->setRichSubject($subject, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getUser($uid) {
|
||||||
|
$user = $this->userManager->get($uid);
|
||||||
|
|
||||||
|
if ($user instanceof IUser) {
|
||||||
|
return [
|
||||||
|
'type' => 'user',
|
||||||
|
'id' => $user->getUID(),
|
||||||
|
'name' => $user->getDisplayName(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'type' => 'user',
|
||||||
|
'id' => $uid,
|
||||||
|
'name' => $uid,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getGroup($uid) {
|
||||||
|
$group = $this->groupManager->get($uid);
|
||||||
|
|
||||||
|
if ($group !== null) {
|
||||||
|
return [
|
||||||
|
'type' => 'user-group',
|
||||||
|
'id' => $group->getGID(),
|
||||||
|
'name' => $group->getDisplayName(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'type' => 'user-group',
|
||||||
|
'id' => $uid,
|
||||||
|
'name' => $uid,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Activity;
|
||||||
|
|
||||||
|
use OCP\EventDispatcher\Event;
|
||||||
|
use OCP\EventDispatcher\IEventListener;
|
||||||
|
use OCP\Activity\IManager as IActivityManager;
|
||||||
|
use OCA\BigBlueButton\Event\RoomCreatedEvent;
|
||||||
|
use OCA\BigBlueButton\Event\RoomDeletedEvent;
|
||||||
|
use OCA\BigBlueButton\AppInfo\Application;
|
||||||
|
|
||||||
|
class RoomListener implements IEventListener {
|
||||||
|
|
||||||
|
/** @var IActivityManager */
|
||||||
|
private $activityManager;
|
||||||
|
|
||||||
|
public function __construct(IActivityManager $activityManager) {
|
||||||
|
$this->activityManager = $activityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Event $event): void {
|
||||||
|
if ($event instanceof RoomCreatedEvent) {
|
||||||
|
$subject = Provider::SHARE_CREATED;
|
||||||
|
} elseif ($event instanceof RoomDeletedEvent) {
|
||||||
|
$subject = Provider::SHARE_DELETED;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$room = $event->getRoom();
|
||||||
|
$activityEvent = $this->activityManager->generateEvent();
|
||||||
|
|
||||||
|
$activityEvent->setApp(Application::ID);
|
||||||
|
$activityEvent->setType(Setting::Identifier);
|
||||||
|
$activityEvent->setAffectedUser($room->getUserId());
|
||||||
|
$activityEvent->setSubject($subject, [
|
||||||
|
'id' => $room->getId(),
|
||||||
|
'name' => $room->getName(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->activityManager->publish($activityEvent);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Activity;
|
||||||
|
|
||||||
|
use OCP\EventDispatcher\Event;
|
||||||
|
use OCP\EventDispatcher\IEventListener;
|
||||||
|
use OCP\Activity\IManager as IActivityManager;
|
||||||
|
use OCP\IGroupManager;
|
||||||
|
use OCA\BigBlueButton\Event\RoomShareCreatedEvent;
|
||||||
|
use OCA\BigBlueButton\Event\RoomShareDeletedEvent;
|
||||||
|
use OCA\BigBlueButton\AppInfo\Application;
|
||||||
|
use OCA\BigBlueButton\Db\Room;
|
||||||
|
use OCA\BigBlueButton\Db\RoomShare;
|
||||||
|
use OCA\BigBlueButton\Service\RoomService;
|
||||||
|
|
||||||
|
class RoomShareListener implements IEventListener {
|
||||||
|
|
||||||
|
/** @var IActivityManager */
|
||||||
|
private $activityManager;
|
||||||
|
|
||||||
|
/** @var RoomService */
|
||||||
|
private $roomService;
|
||||||
|
|
||||||
|
/** @var IGroupManager */
|
||||||
|
private $groupManager;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
IActivityManager $activityManager,
|
||||||
|
RoomService $roomService,
|
||||||
|
IGroupManager $groupManager) {
|
||||||
|
$this->activityManager = $activityManager;
|
||||||
|
$this->roomService = $roomService;
|
||||||
|
$this->groupManager = $groupManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Event $event): void {
|
||||||
|
if ($event instanceof RoomShareCreatedEvent) {
|
||||||
|
$subject = Provider::SHARE_CREATED;
|
||||||
|
} elseif ($event instanceof RoomShareDeletedEvent) {
|
||||||
|
$subject = Provider::SHARE_DELETED;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$share = $event->getRoomShare();
|
||||||
|
$shareType = $share->getShareType();
|
||||||
|
$room = $this->roomService->find($share->getRoomId());
|
||||||
|
|
||||||
|
if ($shareType === RoomShare::SHARE_TYPE_USER) {
|
||||||
|
$this->shareWithUser($subject, $room, $share);
|
||||||
|
} elseif ($shareType === RoomShare::SHARE_TYPE_GROUP) {
|
||||||
|
$this->shareWithGroup($subject, $room, $share);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shareWithUser(string $subject, Room $room, RoomShare $share) {
|
||||||
|
$this->createActivityEvent($subject, $room->getUserId(), $room, $share);
|
||||||
|
$this->createActivityEvent($subject, $share->getShareWith(), $room, $share);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function shareWithGroup(string $subject, Room $room, RoomShare $share) {
|
||||||
|
$this->createActivityEvent($subject, $room->getUserId(), $room, $share);
|
||||||
|
|
||||||
|
$group = $this->groupManager->get($share->getShareWith());
|
||||||
|
|
||||||
|
if ($group === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($group->getUsers() as $user) {
|
||||||
|
$this->createActivityEvent($subject, $user->getUID(), $room, $share);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createActivityEvent(string $subject, string $affectedUser, Room $room, RoomShare $roomShare) {
|
||||||
|
$activityEvent = $this->activityManager->generateEvent();
|
||||||
|
|
||||||
|
$activityEvent->setApp(Application::ID);
|
||||||
|
$activityEvent->setType(Setting::Identifier);
|
||||||
|
$activityEvent->setAffectedUser($affectedUser);
|
||||||
|
$activityEvent->setSubject($subject, [
|
||||||
|
'id' => $room->getId(),
|
||||||
|
'name' => $room->getName(),
|
||||||
|
'shareType' => $roomShare->getShareType(),
|
||||||
|
'shareWith' => $roomShare->getShareWith(),
|
||||||
|
'permission' => $roomShare->getPermission(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->activityManager->publish($activityEvent);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Activity;
|
||||||
|
|
||||||
|
use OCP\Activity\ISetting;
|
||||||
|
|
||||||
|
class Setting implements ISetting {
|
||||||
|
public const Identifier = 'bbb';
|
||||||
|
|
||||||
|
public function getIdentifier() {
|
||||||
|
return self::Identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return 'BigBlueButton';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPriority() {
|
||||||
|
return 70;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canChangeStream() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isDefaultEnabledStream() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canChangeMail() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isDefaultEnabledMail() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,23 +5,50 @@ namespace OCA\BigBlueButton\AppInfo;
|
||||||
use \OCP\IConfig;
|
use \OCP\IConfig;
|
||||||
use \OCP\Settings\IManager as ISettingsManager;
|
use \OCP\Settings\IManager as ISettingsManager;
|
||||||
use \OCP\AppFramework\App;
|
use \OCP\AppFramework\App;
|
||||||
|
use \OCP\EventDispatcher\IEventDispatcher;
|
||||||
use \OCA\BigBlueButton\Middleware\JoinMiddleware;
|
use \OCA\BigBlueButton\Middleware\JoinMiddleware;
|
||||||
|
use \OCA\BigBlueButton\Middleware\HookMiddleware;
|
||||||
|
use \OCA\BigBlueButton\Event\RoomCreatedEvent;
|
||||||
|
use \OCA\BigBlueButton\Event\RoomDeletedEvent;
|
||||||
|
use \OCA\BigBlueButton\Activity\RoomListener;
|
||||||
|
use \OCA\BigBlueButton\Event\RoomShareCreatedEvent;
|
||||||
|
use \OCA\BigBlueButton\Event\RoomShareDeletedEvent;
|
||||||
|
use \OCA\BigBlueButton\Activity\RoomShareListener;
|
||||||
|
use \OCA\BigBlueButton\Event\MeetingStartedEvent;
|
||||||
|
use \OCA\BigBlueButton\Event\MeetingEndedEvent;
|
||||||
|
use \OCA\BigBlueButton\Event\RecordingReadyEvent;
|
||||||
|
use \OCA\BigBlueButton\Activity\MeetingListener;
|
||||||
|
|
||||||
if ((@include_once __DIR__ . '/../../vendor/autoload.php') === false) {
|
if ((@include_once __DIR__ . '/../../vendor/autoload.php') === false) {
|
||||||
throw new \Exception('Cannot include autoload. Did you run install dependencies using composer?');
|
throw new \Exception('Cannot include autoload. Did you run install dependencies using composer?');
|
||||||
}
|
}
|
||||||
|
|
||||||
class Application extends App {
|
class Application extends App {
|
||||||
|
public const ID = 'bbb';
|
||||||
|
|
||||||
public function __construct(array $urlParams = []) {
|
public function __construct(array $urlParams = []) {
|
||||||
parent::__construct('bbb', $urlParams);
|
parent::__construct(self::ID, $urlParams);
|
||||||
|
|
||||||
$container = $this->getContainer();
|
$container = $this->getContainer();
|
||||||
|
|
||||||
|
/* @var IEventDispatcher $eventDispatcher */
|
||||||
|
$dispatcher = $container->query(IEventDispatcher::class);
|
||||||
|
$dispatcher->addServiceListener(RoomCreatedEvent::class, RoomListener::class);
|
||||||
|
$dispatcher->addServiceListener(RoomDeletedEvent::class, RoomListener::class);
|
||||||
|
|
||||||
|
$dispatcher->addServiceListener(RoomShareCreatedEvent::class, RoomShareListener::class);
|
||||||
|
$dispatcher->addServiceListener(RoomShareDeletedEvent::class, RoomShareListener::class);
|
||||||
|
|
||||||
|
$dispatcher->addServiceListener(MeetingStartedEvent::class, MeetingListener::class);
|
||||||
|
$dispatcher->addServiceListener(MeetingEndedEvent::class, MeetingListener::class);
|
||||||
|
$dispatcher->addServiceListener(RecordingReadyEvent::class, MeetingListener::class);
|
||||||
|
|
||||||
$container->registerMiddleWare(JoinMiddleware::class);
|
$container->registerMiddleWare(JoinMiddleware::class);
|
||||||
|
$container->registerMiddleWare(HookMiddleware::class);
|
||||||
|
|
||||||
$config = $container->query(IConfig::class);
|
$config = $container->query(IConfig::class);
|
||||||
|
|
||||||
if ($config->getAppValue('bbb', 'app.navigation') === 'true') {
|
if ($config->getAppValue(self::ID, 'app.navigation') === 'true') {
|
||||||
$this->registerAsNavigationEntry();
|
$this->registerAsNavigationEntry();
|
||||||
} else {
|
} else {
|
||||||
$this->registerAsPersonalSetting();
|
$this->registerAsPersonalSetting();
|
||||||
|
@ -39,7 +66,7 @@ class Application extends App {
|
||||||
|
|
||||||
$server->getNavigationManager()->add(function () use ($server) {
|
$server->getNavigationManager()->add(function () use ($server) {
|
||||||
return [
|
return [
|
||||||
'id' => 'bbb',
|
'id' => self::ID,
|
||||||
'order' => 80,
|
'order' => 80,
|
||||||
'href' => $server->getURLGenerator()->linkToRoute('bbb.page.index'),
|
'href' => $server->getURLGenerator()->linkToRoute('bbb.page.index'),
|
||||||
'icon' => $server->getURLGenerator()->imagePath('bbb', 'app.svg'),
|
'icon' => $server->getURLGenerator()->imagePath('bbb', 'app.svg'),
|
||||||
|
|
|
@ -9,8 +9,11 @@ use BigBlueButton\Parameters\GetRecordingsParameters;
|
||||||
use BigBlueButton\Core\Record;
|
use BigBlueButton\Core\Record;
|
||||||
use BigBlueButton\Parameters\DeleteRecordingsParameters;
|
use BigBlueButton\Parameters\DeleteRecordingsParameters;
|
||||||
use BigBlueButton\Parameters\IsMeetingRunningParameters;
|
use BigBlueButton\Parameters\IsMeetingRunningParameters;
|
||||||
|
use OCP\EventDispatcher\IEventDispatcher;
|
||||||
|
use OCA\BigBlueButton\Event\MeetingStartedEvent;
|
||||||
use OCA\BigBlueButton\Db\Room;
|
use OCA\BigBlueButton\Db\Room;
|
||||||
use OCA\BigBlueButton\Permission;
|
use OCA\BigBlueButton\Permission;
|
||||||
|
use OCA\BigBlueButton\Crypto;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
use OCP\IURLGenerator;
|
use OCP\IURLGenerator;
|
||||||
|
|
||||||
|
@ -27,14 +30,24 @@ class API {
|
||||||
/** @var BigBlueButton|null */
|
/** @var BigBlueButton|null */
|
||||||
private $server;
|
private $server;
|
||||||
|
|
||||||
|
/** @var Crypto */
|
||||||
|
private $crypto;
|
||||||
|
|
||||||
|
/** @var IEventDispatcher */
|
||||||
|
private $eventDispatcher;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IConfig $config,
|
IConfig $config,
|
||||||
IURLGenerator $urlGenerator,
|
IURLGenerator $urlGenerator,
|
||||||
Permission $permission
|
Permission $permission,
|
||||||
|
Crypto $crypto,
|
||||||
|
IEventDispatcher $eventDispatcher
|
||||||
) {
|
) {
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->urlGenerator = $urlGenerator;
|
$this->urlGenerator = $urlGenerator;
|
||||||
$this->permission = $permission;
|
$this->permission = $permission;
|
||||||
|
$this->crypto = $crypto;
|
||||||
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getServer() {
|
private function getServer() {
|
||||||
|
@ -90,6 +103,10 @@ class API {
|
||||||
throw new \Exception('Can not create meeting');
|
throw new \Exception('Can not create meeting');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($response->getMessageKey() !== 'duplicateWarning') {
|
||||||
|
$this->eventDispatcher->dispatch(MeetingStartedEvent::class, new MeetingStartedEvent($room));
|
||||||
|
}
|
||||||
|
|
||||||
return $response->getCreationTime();
|
return $response->getCreationTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +118,14 @@ class API {
|
||||||
$createMeetingParams->setAllowStartStopRecording($room->record);
|
$createMeetingParams->setAllowStartStopRecording($room->record);
|
||||||
$createMeetingParams->setLogoutUrl($this->urlGenerator->getBaseUrl());
|
$createMeetingParams->setLogoutUrl($this->urlGenerator->getBaseUrl());
|
||||||
|
|
||||||
|
$mac = $this->crypto->calculateHMAC($room->uid);
|
||||||
|
|
||||||
|
$endMeetingUrl = $this->urlGenerator->linkToRouteAbsolute('bbb.hook.meetingEnded', ['token' => $room->uid, 'mac' => $mac]);
|
||||||
|
$createMeetingParams->setEndCallbackUrl($endMeetingUrl);
|
||||||
|
|
||||||
|
$recordingReadyUrl = $this->urlGenerator->linkToRouteAbsolute('bbb.hook.recordingReady', ['token' => $room->uid, 'mac' => $mac]);
|
||||||
|
$createMeetingParams->setRecordingReadyCallbackUrl($recordingReadyUrl);
|
||||||
|
|
||||||
$invitationUrl = $this->urlGenerator->linkToRouteAbsolute('bbb.join.index', ['token' => $room->uid]);
|
$invitationUrl = $this->urlGenerator->linkToRouteAbsolute('bbb.join.index', ['token' => $room->uid]);
|
||||||
$createMeetingParams->setModeratorOnlyMessage('To invite someone to the meeting, send them this link: ' . $invitationUrl);
|
$createMeetingParams->setModeratorOnlyMessage('To invite someone to the meeting, send them this link: ' . $invitationUrl);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Controller;
|
||||||
|
|
||||||
|
use OCA\BigBlueButton\Db\Room;
|
||||||
|
use OCP\IRequest;
|
||||||
|
use OCP\EventDispatcher\IEventDispatcher;
|
||||||
|
use OCA\BigBlueButton\Service\RoomService;
|
||||||
|
use OCA\BigBlueButton\Event\MeetingEndedEvent;
|
||||||
|
use OCA\BigBlueButton\Event\RecordingReadyEvent;
|
||||||
|
use OCP\AppFramework\Controller;
|
||||||
|
|
||||||
|
class HookController extends Controller {
|
||||||
|
/** @var string */
|
||||||
|
protected $token;
|
||||||
|
|
||||||
|
/** @var Room|null */
|
||||||
|
protected $room;
|
||||||
|
|
||||||
|
/** @var RoomService */
|
||||||
|
private $service;
|
||||||
|
|
||||||
|
/** @var IEventDispatcher */
|
||||||
|
private $eventDispatcher;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
string $appName,
|
||||||
|
IRequest $request,
|
||||||
|
RoomService $service,
|
||||||
|
IEventDispatcher $eventDispatcher
|
||||||
|
) {
|
||||||
|
parent::__construct($appName, $request);
|
||||||
|
|
||||||
|
$this->service = $service;
|
||||||
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setToken(string $token) {
|
||||||
|
$this->token = $token;
|
||||||
|
$this->room = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isValidToken(): bool {
|
||||||
|
$room = $this->getRoom();
|
||||||
|
|
||||||
|
return $room !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @PublicPage
|
||||||
|
* @NoCSRFRequired
|
||||||
|
*/
|
||||||
|
public function meetingEnded($recordingmarks = false) {
|
||||||
|
$recordingmarks = \boolval($recordingmarks);
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch(MeetingEndedEvent::class, new MeetingEndedEvent($this->getRoom(), $recordingmarks));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @PublicPage
|
||||||
|
* @NoCSRFRequired
|
||||||
|
*/
|
||||||
|
public function recordingReady() {
|
||||||
|
$this->eventDispatcher->dispatch(RecordingReadyEvent::class, new RecordingReadyEvent($this->getRoom()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRoom(): ?Room {
|
||||||
|
if ($this->room === null) {
|
||||||
|
$this->room = $this->service->findByUid($this->token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->room;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton;
|
||||||
|
|
||||||
|
use OCP\Security\ICrypto;
|
||||||
|
|
||||||
|
class Crypto {
|
||||||
|
/** @var ICrypto */
|
||||||
|
private $crypto;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ICrypto $crypto
|
||||||
|
) {
|
||||||
|
$this->crypto = $crypto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function calculateHMAC(string $message): string {
|
||||||
|
if ($message === null) {
|
||||||
|
throw new \InvalidArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->encodeBase64UrlSafe(\sha1($this->crypto->calculateHMAC($message), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verifyHMAC(string $message, string $mac) {
|
||||||
|
if ($message === null || $mac === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$validMac = $this->encodeBase64UrlSafe(\sha1($this->crypto->calculateHMAC($message), true));
|
||||||
|
|
||||||
|
return $validMac === $mac;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function encodeBase64UrlSafe($data) {
|
||||||
|
$b64 = \base64_encode($data);
|
||||||
|
|
||||||
|
if ($b64 === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return \rtrim(\strtr($b64, '+/', '-_'), '=');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Event;
|
||||||
|
|
||||||
|
use OCA\BigBlueButton\Db\Room;
|
||||||
|
|
||||||
|
class MeetingEndedEvent extends RoomEvent {
|
||||||
|
private $recordingMarks = false;
|
||||||
|
|
||||||
|
public function __construct(Room $room, bool $recordingMarks) {
|
||||||
|
parent::__construct($room);
|
||||||
|
|
||||||
|
$this->recordingMarks = $recordingMarks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasRecordingMarks(): bool {
|
||||||
|
return $this->recordingMarks;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Event;
|
||||||
|
|
||||||
|
class MeetingStartedEvent extends RoomEvent {
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Event;
|
||||||
|
|
||||||
|
class RecordingReadyEvent extends RoomEvent {
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Event;
|
||||||
|
|
||||||
|
class RoomCreatedEvent extends RoomEvent {
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Event;
|
||||||
|
|
||||||
|
class RoomDeletedEvent extends RoomEvent {
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Event;
|
||||||
|
|
||||||
|
use OCP\EventDispatcher\Event;
|
||||||
|
use OCA\BigBlueButton\Db\Room;
|
||||||
|
|
||||||
|
abstract class RoomEvent extends Event {
|
||||||
|
|
||||||
|
/** @var Room */
|
||||||
|
private $room;
|
||||||
|
|
||||||
|
public function __construct(Room $room) {
|
||||||
|
$this->room = $room;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoom(): Room {
|
||||||
|
return $this->room;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Event;
|
||||||
|
|
||||||
|
class RoomShareCreatedEvent extends RoomShareEvent {
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Event;
|
||||||
|
|
||||||
|
class RoomShareDeletedEvent extends RoomShareEvent {
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Event;
|
||||||
|
|
||||||
|
use OCP\EventDispatcher\Event;
|
||||||
|
use OCA\BigBlueButton\Db\RoomShare;
|
||||||
|
|
||||||
|
abstract class RoomShareEvent extends Event {
|
||||||
|
|
||||||
|
/** @var RoomShare */
|
||||||
|
private $roomShare;
|
||||||
|
|
||||||
|
public function __construct(RoomShare $roomShare) {
|
||||||
|
$this->roomShare = $roomShare;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoomShare(): RoomShare {
|
||||||
|
return $this->roomShare;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Middleware;
|
||||||
|
|
||||||
|
use OCA\BigBlueButton\Controller\HookController;
|
||||||
|
use OCA\BigBlueButton\NoPermissionException;
|
||||||
|
use OCA\BigBlueButton\NotFoundException;
|
||||||
|
use OCA\BigBlueButton\Crypto;
|
||||||
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
|
use OCP\AppFramework\Http;
|
||||||
|
use OCP\AppFramework\Middleware;
|
||||||
|
use OCP\IRequest;
|
||||||
|
|
||||||
|
class HookMiddleware extends Middleware {
|
||||||
|
/** @var IRequest */
|
||||||
|
private $request;
|
||||||
|
|
||||||
|
/** @var Crypto */
|
||||||
|
private $crypto;
|
||||||
|
|
||||||
|
public function __construct(IRequest $request, Crypto $crypto) {
|
||||||
|
$this->request = $request;
|
||||||
|
$this->crypto = $crypto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function beforeController($controller, $methodName) {
|
||||||
|
if (!($controller instanceof HookController)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$token = $this->request->getParam('token');
|
||||||
|
if ($token === null) {
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$mac = $this->request->getParam('mac');
|
||||||
|
if ($mac === null) {
|
||||||
|
throw new NoPermissionException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->crypto->verifyHMAC($token, $mac)) {
|
||||||
|
throw new NoPermissionException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$controller->setToken($token);
|
||||||
|
|
||||||
|
if ($controller->isValidToken()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function afterException($controller, $methodName, \Exception $exception) {
|
||||||
|
if (!($controller instanceof HookController)) {
|
||||||
|
throw $exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exception instanceof NotFoundException) {
|
||||||
|
return new JSONResponse(null, Http::STATUS_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($exception instanceof NoPermissionException) {
|
||||||
|
return new JSONResponse(null, Http::STATUS_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $exception;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,17 +6,26 @@ use Exception;
|
||||||
|
|
||||||
use OCP\AppFramework\Db\DoesNotExistException;
|
use OCP\AppFramework\Db\DoesNotExistException;
|
||||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||||
|
use OCP\EventDispatcher\IEventDispatcher;
|
||||||
|
|
||||||
use OCA\BigBlueButton\Db\Room;
|
use OCA\BigBlueButton\Db\Room;
|
||||||
use OCA\BigBlueButton\Db\RoomMapper;
|
use OCA\BigBlueButton\Db\RoomMapper;
|
||||||
|
use OCA\BigBlueButton\Event\RoomCreatedEvent;
|
||||||
|
use OCA\BigBlueButton\Event\RoomDeletedEvent;
|
||||||
|
|
||||||
class RoomService {
|
class RoomService {
|
||||||
|
|
||||||
/** @var RoomMapper */
|
/** @var RoomMapper */
|
||||||
private $mapper;
|
private $mapper;
|
||||||
|
|
||||||
public function __construct(RoomMapper $mapper) {
|
/** @var IEventDispatcher */
|
||||||
|
private $eventDispatcher;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
RoomMapper $mapper,
|
||||||
|
IEventDispatcher $eventDispatcher) {
|
||||||
$this->mapper = $mapper;
|
$this->mapper = $mapper;
|
||||||
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findAll(string $userId, array $groupIds, array $circleIds): array {
|
public function findAll(string $userId, array $groupIds, array $circleIds): array {
|
||||||
|
@ -70,7 +79,11 @@ class RoomService {
|
||||||
$room->setAccess($access);
|
$room->setAccess($access);
|
||||||
$room->setUserId($userId);
|
$room->setUserId($userId);
|
||||||
|
|
||||||
return $this->mapper->insert($room);
|
$createdRoom = $this->mapper->insert($room);
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch(RoomCreatedEvent::class, new RoomCreatedEvent($createdRoom));
|
||||||
|
|
||||||
|
return $createdRoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update($id, $name, $welcome, $maxParticipants, $record, $access, $everyoneIsModerator, $requireModerator) {
|
public function update($id, $name, $welcome, $maxParticipants, $record, $access, $everyoneIsModerator, $requireModerator) {
|
||||||
|
@ -98,7 +111,11 @@ class RoomService {
|
||||||
public function delete($id) {
|
public function delete($id) {
|
||||||
try {
|
try {
|
||||||
$room = $this->mapper->find($id);
|
$room = $this->mapper->find($id);
|
||||||
|
|
||||||
$this->mapper->delete($room);
|
$this->mapper->delete($room);
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch(RoomDeletedEvent::class, new RoomDeletedEvent($room));
|
||||||
|
|
||||||
return $room;
|
return $room;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->handleException($e);
|
$this->handleException($e);
|
||||||
|
|
|
@ -6,17 +6,26 @@ use Exception;
|
||||||
|
|
||||||
use OCP\AppFramework\Db\DoesNotExistException;
|
use OCP\AppFramework\Db\DoesNotExistException;
|
||||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||||
|
use OCP\EventDispatcher\IEventDispatcher;
|
||||||
|
|
||||||
use OCA\BigBlueButton\Db\RoomShare;
|
use OCA\BigBlueButton\Db\RoomShare;
|
||||||
use OCA\BigBlueButton\Db\RoomShareMapper;
|
use OCA\BigBlueButton\Db\RoomShareMapper;
|
||||||
|
use OCA\BigBlueButton\Event\RoomShareCreatedEvent;
|
||||||
|
use OCA\BigBlueButton\Event\RoomShareDeletedEvent;
|
||||||
|
|
||||||
class RoomShareService {
|
class RoomShareService {
|
||||||
|
|
||||||
/** @var RoomShareMapper */
|
/** @var RoomShareMapper */
|
||||||
private $mapper;
|
private $mapper;
|
||||||
|
|
||||||
public function __construct(RoomShareMapper $mapper) {
|
/** @var IEventDispatcher */
|
||||||
|
private $eventDispatcher;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
RoomShareMapper $mapper,
|
||||||
|
IEventDispatcher $eventDispatcher) {
|
||||||
$this->mapper = $mapper;
|
$this->mapper = $mapper;
|
||||||
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findAll(int $roomId): array {
|
public function findAll(int $roomId): array {
|
||||||
|
@ -53,7 +62,11 @@ class RoomShareService {
|
||||||
$roomShare->setShareWith($shareWith);
|
$roomShare->setShareWith($shareWith);
|
||||||
$roomShare->setPermission($permission);
|
$roomShare->setPermission($permission);
|
||||||
|
|
||||||
return $this->mapper->insert($roomShare);
|
$createdRoomShare = $this->mapper->insert($roomShare);
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch(RoomShareCreatedEvent::class, new RoomShareCreatedEvent($createdRoomShare));
|
||||||
|
|
||||||
|
return $createdRoomShare;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +90,8 @@ class RoomShareService {
|
||||||
$roomShare = $this->mapper->find($id);
|
$roomShare = $this->mapper->find($id);
|
||||||
$this->mapper->delete($roomShare);
|
$this->mapper->delete($roomShare);
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch(RoomShareDeletedEvent::class, new RoomShareDeletedEvent($roomShare));
|
||||||
|
|
||||||
return $roomShare;
|
return $roomShare;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$this->handleException($e);
|
$this->handleException($e);
|
||||||
|
|