Skip to content

Commit 5b0886c

Browse files
committed
Implement resending message and messages to students
1 parent 93371c9 commit 5b0886c

File tree

7 files changed

+347
-157
lines changed

7 files changed

+347
-157
lines changed

src/ui/failsbasis.jsx

Lines changed: 40 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import { faDesktop, faWindowMaximize } from '@fortawesome/free-solid-svg-icons'
2121
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
22-
import katex from 'katex'
2322
import 'katex/dist/katex.min.css'
2423
import { Button } from 'primereact/button'
2524
import { confirmDialog } from 'primereact/confirmdialog'
@@ -457,6 +456,46 @@ export class FailsBasis extends Component {
457456
})
458457
}
459458

459+
sendChatMessageInt({
460+
chattext,
461+
videoquestion,
462+
resendSender,
463+
showSendername
464+
}) {
465+
const encoder = new TextEncoder()
466+
const afunc = async () => {
467+
console.log('Send chat message', chattext, videoquestion, videoquestion)
468+
const iv = globalThis.crypto.getRandomValues(new Uint8Array(12))
469+
console.log('Send chat message 1')
470+
const keyindex = await this.keystore.getCurKeyId()
471+
console.log('Send chat message 2')
472+
const key = await this.keystore.getKey(keyindex)
473+
console.log('Send chat message 3')
474+
const message = resendSender ? resendSender + ':\n' + chattext : chattext
475+
const encData = await globalThis.crypto.subtle.encrypt(
476+
{
477+
name: 'AES-GCM',
478+
iv
479+
},
480+
key.e2e,
481+
encoder.encode(message)
482+
)
483+
console.log('Send chat message 4')
484+
this.netSendSocket('chatquestion', {
485+
text: 'Encrypted',
486+
encData,
487+
keyindex,
488+
iv,
489+
videoquestion,
490+
resend: !!resendSender,
491+
showSendername
492+
})
493+
}
494+
afunc().catch((error) => {
495+
console.log('Problem in sendChatMessageInt', error)
496+
})
497+
}
498+
460499
processAVoffers() {
461500
// avoffers have updated, now we may change everything
462501
const audio = this.avoffers.audio
@@ -880,56 +919,4 @@ export class FailsBasis extends Component {
880919
}
881920
this.setState(args)
882921
}
883-
884-
maybeUseLatex(item) {
885-
return this.detectLatex(item) ? this.convertToLatex(item) : item
886-
}
887-
888-
detectLatex(string) {
889-
return string.indexOf('$') !== -1
890-
}
891-
892-
convertToLatex(string) {
893-
const retarray = []
894-
let secstart = 0
895-
let seclatex = false
896-
for (let curpos = 0; curpos < string.length; curpos++) {
897-
const curchar = string.charAt(curpos)
898-
if (curchar === '$') {
899-
if (seclatex) {
900-
const html = katex.renderToString(
901-
string.substring(secstart, curpos),
902-
{
903-
throwOnError: false,
904-
displayMode: false
905-
}
906-
)
907-
retarray.push(
908-
<span
909-
key={'latex-' + retarray.length}
910-
dangerouslySetInnerHTML={{ __html: html }}
911-
></span>
912-
)
913-
secstart = curpos + 1
914-
seclatex = false
915-
} else {
916-
retarray.push(
917-
<React.Fragment key={'latex-' + retarray.length}>
918-
{string.substring(secstart, curpos - 1)}{' '}
919-
</React.Fragment>
920-
)
921-
secstart = curpos + 1
922-
seclatex = true
923-
}
924-
}
925-
}
926-
927-
retarray.push(
928-
<React.Fragment key={'latex-' + retarray.length}>
929-
{string.substring(secstart, string.length)}{' '}
930-
</React.Fragment>
931-
)
932-
933-
return retarray
934-
}
935922
}

src/ui/failsboard.jsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { ShortcutsMessage } from './widgets/shortcutsmessage'
3737
import Pica from 'pica'
3838
import ImageBlobReduce from 'image-blob-reduce'
3939
import { notebookEditPseudoAppid } from './blackboard/jupyterhublet'
40+
import { maybeUseLatex, convertToLatex } from './misc/latex'
4041

4142
export class FailsBoard extends FailsBasis {
4243
constructor(props) {
@@ -169,7 +170,8 @@ export class FailsBoard extends FailsBasis {
169170
<ChatMessage
170171
data={data}
171172
blockChat={() => this.blockChat(userhash)}
172-
latex={this.convertToLatex(text)}
173+
latex={convertToLatex(text)}
174+
text={text}
173175
isEncrypted={isEncrypted}
174176
allowVideoquestion={this.allowVideoquestion}
175177
videoQuestion={
@@ -178,6 +180,13 @@ export class FailsBoard extends FailsBasis {
178180
data?.videoquestion &&
179181
this.hasMediaSend
180182
}
183+
sendMessageHandler={({ resend, sender, text }) => {
184+
this.sendChatMessageInt({
185+
chattext: text,
186+
resendSender: resend && sender,
187+
showSendername: true
188+
})
189+
}}
181190
/>
182191
)
183192
this.toast.show({ severity: 'info', content: retobj, sticky: true })
@@ -558,15 +567,13 @@ export class FailsBoard extends FailsBasis {
558567
let childlist = []
559568
if (item.children)
560569
childlist = item.children.map((el, ind) => (
561-
<li key={item.id + ind}>{this.maybeUseLatex(el.name)}</li>
570+
<li key={item.id + ind}>{maybeUseLatex(el.name)}</li>
562571
))
563572
return (
564573
<div key={item.id}>
565574
<h3>
566575
{' '}
567-
{this.maybeUseLatex(
568-
item.name + (item.multi ? ' (multi)' : ' (single)')
569-
)}
576+
{maybeUseLatex(item.name + (item.multi ? ' (multi)' : ' (single)'))}
570577
{item.note ? <small> {' ' + item.note} </small> : ''}
571578
</h3>
572579
<ol>{childlist}</ol>
@@ -683,7 +690,7 @@ export class FailsBoard extends FailsBasis {
683690
pollanswers.push(
684691
<div key={ind + 'anw'}>
685692
{' '}
686-
<b>{'A ' + (ind + 1) + ': '} </b> {this.maybeUseLatex(mine.name)}{' '}
693+
<b>{'A ' + (ind + 1) + ': '} </b> {maybeUseLatex(mine.name)}{' '}
687694
</div>
688695
)
689696
polldata.datasets[0].data.push(tpolldata[choice])
@@ -761,6 +768,12 @@ export class FailsBoard extends FailsBasis {
761768
this.startUpAVinterface()
762769
}
763770
}
771+
sendChatMessage={({ chattext }) => {
772+
this.sendChatMessageInt({
773+
chattext,
774+
showSendername: true
775+
})
776+
}}
764777
></NoteScreenBase>
765778
{!this.state.casttoscreens && (
766779
<div
@@ -912,7 +925,7 @@ export class FailsBoard extends FailsBasis {
912925
<h3>
913926
{' '}
914927
{this.state.curpoll
915-
? this.maybeUseLatex(
928+
? maybeUseLatex(
916929
this.state.curpoll.name +
917930
(this.state.curpoll.multi
918931
? ' (multi)'

src/ui/failsnotes.jsx

Lines changed: 64 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { Dialog } from 'primereact/dialog'
2727
import { InputText } from 'primereact/inputtext'
2828
import { InputTextarea } from 'primereact/inputtextarea'
2929
import { OverlayPanel } from 'primereact/overlaypanel'
30+
import { ChatMessage } from './widgets/chatmessage'
3031
import { Toast } from 'primereact/toast'
3132
import React from 'react'
3233
import { FloatingVideo, AVVideoRender, VideoControl } from '../avwidgets'
@@ -44,6 +45,7 @@ import failsLogoExp from './logo/logo2exp.svg'
4445
import { NoteScreenBase } from './notepad/notepad'
4546
import { NoteTools } from './toolbox'
4647
import { VideoChatSender } from './widgets/videochat'
48+
import { maybeUseLatex, convertToLatex, detectLatex } from './misc/latex'
4749

4850
export class FailsNotes extends FailsBasis {
4951
constructor(props) {
@@ -148,6 +150,60 @@ export class FailsNotes extends FailsBasis {
148150
polldata: data.result
149151
})
150152
})
153+
154+
notessocket.on('chatquestion', async (data) => {
155+
console.log('Incoming chat', data)
156+
let {
157+
text,
158+
encData,
159+
iv,
160+
keyindex,
161+
resend = false,
162+
showSendername = false
163+
} = data
164+
let isEncrypted = false
165+
try {
166+
if ((text === 'Encrypted' && encData, iv, keyindex)) {
167+
isEncrypted = true
168+
const decoder = new TextDecoder()
169+
const key = await this.keystore.getKey(keyindex)
170+
const decdata = await globalThis.crypto.subtle.decrypt(
171+
{
172+
name: 'AES-GCM',
173+
iv
174+
},
175+
key.e2e,
176+
encData
177+
)
178+
text = decoder.decode(decdata)
179+
}
180+
} catch (error) {
181+
console.log('Error in chatquestion', error)
182+
text = 'Error: receiving/decrypting chat: ' + error
183+
}
184+
let senderName
185+
if (resend) {
186+
const splitind = text.indexOf(':\n')
187+
if (splitind !== -1) {
188+
senderName = text.substring(0, splitind)
189+
text = text.substring(splitind + 2)
190+
}
191+
}
192+
const retobj = (
193+
<ChatMessage
194+
data={data}
195+
latex={convertToLatex(text)}
196+
resend={!!resend}
197+
showSendername={!!showSendername}
198+
senderName={senderName}
199+
isEncrypted={isEncrypted}
200+
noHideName
201+
noBlockUser
202+
noForensicReport
203+
/>
204+
)
205+
this.toast.show({ severity: 'info', content: retobj, sticky: true })
206+
})
151207
}
152208

153209
informDraw() {
@@ -236,41 +292,7 @@ export class FailsNotes extends FailsBasis {
236292
sendChatMessage() {
237293
const chattext = this.state.chattext
238294
const videoquestion = this.state.videoquestion ? true : undefined
239-
const encoder = new TextEncoder()
240-
const afunc = async () => {
241-
console.log(
242-
'Send chat message',
243-
chattext,
244-
this.state.videoquestion,
245-
videoquestion
246-
)
247-
const iv = globalThis.crypto.getRandomValues(new Uint8Array(12))
248-
console.log('Send chat message 1')
249-
const keyindex = await this.keystore.getCurKeyId()
250-
console.log('Send chat message 2')
251-
const key = await this.keystore.getKey(keyindex)
252-
console.log('Send chat message 3')
253-
const encData = await globalThis.crypto.subtle.encrypt(
254-
{
255-
name: 'AES-GCM',
256-
iv
257-
},
258-
key.e2e,
259-
encoder.encode(chattext)
260-
)
261-
console.log('Send chat message 4')
262-
this.netSendSocket('chatquestion', {
263-
text: 'Encrypted',
264-
encData,
265-
keyindex,
266-
iv,
267-
videoquestion
268-
})
269-
}
270-
afunc().catch((error) => {
271-
console.log('Problem in sendChatMessage', error)
272-
})
273-
295+
this.sendChatMessageInt({ chattext, videoquestion })
274296
this.setState({ chattext: '' })
275297
this.chatop.hide()
276298
}
@@ -546,10 +568,10 @@ export class FailsNotes extends FailsBasis {
546568
<OverlayPanel ref={(el) => (this.chatop = el)}>
547569
<div className='p-grid p-align-end'>
548570
<div className='p-col'>
549-
{this.detectLatex(this.state.chattext) && (
571+
{detectLatex(this.state.chattext) && (
550572
<React.Fragment>
551573
<h4>Preview: </h4>
552-
{this.convertToLatex(this.state.chattext)}
574+
{convertToLatex(this.state.chattext)}
553575
<br></br>
554576
</React.Fragment>
555577
)}
@@ -636,7 +658,7 @@ export class FailsNotes extends FailsBasis {
636658
pollanswers = pd.map((el, ind) => (
637659
<div key={ind + 'anw'}>
638660
{' '}
639-
<b>{'A ' + (ind + 1) + ': '} </b> {this.maybeUseLatex(el.name)}{' '}
661+
<b>{'A ' + (ind + 1) + ': '} </b> {maybeUseLatex(el.name)}{' '}
640662
</div>
641663
))
642664
}
@@ -655,7 +677,7 @@ export class FailsNotes extends FailsBasis {
655677
}
656678
></Checkbox>
657679
<label htmlFor='cb2' className='p-checkbox-label p-m-2'>
658-
{this.maybeUseLatex(el.name)}
680+
{maybeUseLatex(el.name)}
659681
</label>
660682
</div>
661683
))
@@ -672,7 +694,7 @@ export class FailsNotes extends FailsBasis {
672694

673695
return (
674696
<div>
675-
<Toast ref={(el) => (this.toast = el)} position='top-left' />
697+
<Toast ref={(el) => (this.toast = el)} position='bottom-left' />
676698
{!this.state.tokenexpired && this.loadDataDialog()}
677699
{this.expiredTokenDialog()}
678700
<OverlayPanel
@@ -856,7 +878,7 @@ export class FailsNotes extends FailsBasis {
856878
<h3>
857879
{' '}
858880
{this.state.curpoll
859-
? this.maybeUseLatex(
881+
? maybeUseLatex(
860882
this.state.curpoll.name +
861883
(this.state.curpoll.multi ? ' (multi)' : ' (single)')
862884
)
@@ -881,7 +903,7 @@ export class FailsNotes extends FailsBasis {
881903
<h3>
882904
{' '}
883905
{this.state.curpoll
884-
? this.maybeUseLatex(
906+
? maybeUseLatex(
885907
this.state.curpoll.name +
886908
(this.state.curpoll.multi ? ' (multi)' : ' (single)')
887909
)

0 commit comments

Comments
 (0)