mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-19 18:13:41 -05:00
web: implement knocking on rooms (#615)
This commit is contained in:
parent
b754240715
commit
eb893989bd
9 changed files with 70 additions and 14 deletions
|
@ -72,14 +72,14 @@ require (
|
||||||
golang.org/x/mod v0.24.0 // indirect
|
golang.org/x/mod v0.24.0 // indirect
|
||||||
golang.org/x/net v0.38.0 // indirect
|
golang.org/x/net v0.38.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.32.0 // indirect
|
||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
golang.org/x/tools v0.31.0 // indirect
|
golang.org/x/tools v0.31.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
maunium.net/go/mautrix v0.23.2 // indirect
|
maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38 // indirect
|
||||||
mvdan.cc/xurls/v2 v2.6.0 // indirect
|
mvdan.cc/xurls/v2 v2.6.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -221,8 +221,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
|
@ -260,7 +260,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
maunium.net/go/mautrix v0.23.2 h1:Bo3tPrQJwkxyL7aMmy/T+d2tqIrypZjHqeHe8fyeAOg=
|
maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38 h1:fIe2+kYndm3Mm/DwQ4FsODk2DjrLeEeW7tKtZjyERqM=
|
||||||
maunium.net/go/mautrix v0.23.2/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE=
|
maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE=
|
||||||
mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
|
mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
|
||||||
mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk=
|
mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk=
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -27,7 +27,7 @@ require (
|
||||||
golang.org/x/text v0.23.0
|
golang.org/x/text v0.23.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
maunium.net/go/mauflag v1.0.0
|
maunium.net/go/mauflag v1.0.0
|
||||||
maunium.net/go/mautrix v0.23.2
|
maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38
|
||||||
mvdan.cc/xurls/v2 v2.6.0
|
mvdan.cc/xurls/v2 v2.6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,6 +42,6 @@ require (
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.1 // indirect
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.32.0 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -86,8 +86,8 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
|
@ -99,7 +99,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
|
||||||
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
|
||||||
maunium.net/go/mautrix v0.23.2 h1:Bo3tPrQJwkxyL7aMmy/T+d2tqIrypZjHqeHe8fyeAOg=
|
maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38 h1:fIe2+kYndm3Mm/DwQ4FsODk2DjrLeEeW7tKtZjyERqM=
|
||||||
maunium.net/go/mautrix v0.23.2/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE=
|
maunium.net/go/mautrix v0.23.3-0.20250405234116-e675a3c09c38/go.mod h1:pCYLHmo02Jauak/9VlTkbGPrBMvLXsGqTGMNOx+L2PE=
|
||||||
mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
|
mvdan.cc/xurls/v2 v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI=
|
||||||
mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk=
|
mvdan.cc/xurls/v2 v2.6.0/go.mod h1:bCvEZ1XvdA6wDnxY7jPPjEmigDtvtvPXAD/Exa9IMSk=
|
||||||
|
|
|
@ -173,6 +173,13 @@ func (h *HiClient) handleJSONCommand(ctx context.Context, req *JSONCommand) (any
|
||||||
Reason: params.Reason,
|
Reason: params.Reason,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
case "knock_room":
|
||||||
|
return unmarshalAndCall(req.Data, func(params *joinRoomParams) (*mautrix.RespKnockRoom, error) {
|
||||||
|
return h.Client.KnockRoom(ctx, params.RoomIDOrAlias, &mautrix.ReqKnockRoom{
|
||||||
|
Via: params.Via,
|
||||||
|
Reason: params.Reason,
|
||||||
|
})
|
||||||
|
})
|
||||||
case "leave_room":
|
case "leave_room":
|
||||||
return unmarshalAndCall(req.Data, func(params *leaveRoomParams) (*mautrix.RespLeaveRoom, error) {
|
return unmarshalAndCall(req.Data, func(params *leaveRoomParams) (*mautrix.RespLeaveRoom, error) {
|
||||||
return h.Client.LeaveRoom(ctx, params.RoomID, &mautrix.ReqLeave{Reason: params.Reason})
|
return h.Client.LeaveRoom(ctx, params.RoomID, &mautrix.ReqLeave{Reason: params.Reason})
|
||||||
|
|
|
@ -265,6 +265,10 @@ export default abstract class RPCClient {
|
||||||
return this.request("join_room", { room_id_or_alias, via, reason })
|
return this.request("join_room", { room_id_or_alias, via, reason })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
knockRoom(room_id_or_alias: RoomID | RoomAlias, via?: string[], reason?: string): Promise<RespRoomJoin> {
|
||||||
|
return this.request("knock_room", { room_id_or_alias, via, reason })
|
||||||
|
}
|
||||||
|
|
||||||
leaveRoom(room_id: RoomID, reason?: string): Promise<Record<string, never>> {
|
leaveRoom(room_id: RoomID, reason?: string): Promise<Record<string, never>> {
|
||||||
return this.request("leave_room", { room_id, reason })
|
return this.request("leave_room", { room_id, reason })
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,6 +316,7 @@ export interface RoomSummary {
|
||||||
room_type: RoomType
|
room_type: RoomType
|
||||||
topic?: string
|
topic?: string
|
||||||
world_readable: boolean
|
world_readable: boolean
|
||||||
|
allowed_room_ids?: RoomID[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RespRoomJoin {
|
export interface RespRoomJoin {
|
||||||
|
|
|
@ -76,4 +76,16 @@ div.room-view.preview > div.preview-inner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
> input.knock-reason {
|
||||||
|
padding: .5rem;
|
||||||
|
border-radius: .25rem;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 1px solid var(--primary-color);
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,21 @@ const RoomPreview = ({ roomID, via, alias, invite }: RoomPreviewProps) => {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [buttonClicked, setButtonClicked] = useState(false)
|
const [buttonClicked, setButtonClicked] = useState(false)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
const [knockRequest, setKnockRequest] = useState<string>("")
|
||||||
|
const doKnockRoom = () => {
|
||||||
|
setButtonClicked(true)
|
||||||
|
client.rpc.knockRoom(alias || roomID, alias ? undefined : via, knockRequest || undefined).then(
|
||||||
|
() => {
|
||||||
|
setButtonClicked(false)
|
||||||
|
mainScreen.clearActiveRoom()
|
||||||
|
window.alert("Successfully knocked on room")
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
setError(`Failed to knock: ${err}`)
|
||||||
|
setButtonClicked(false)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
const doJoinRoom = () => {
|
const doJoinRoom = () => {
|
||||||
let realVia = via
|
let realVia = via
|
||||||
if (!via?.length && invite?.invited_by) {
|
if (!via?.length && invite?.invited_by) {
|
||||||
|
@ -87,6 +102,12 @@ const RoomPreview = ({ roomID, via, alias, invite }: RoomPreviewProps) => {
|
||||||
const topic = summary?.topic ?? invite?.topic ?? ""
|
const topic = summary?.topic ?? invite?.topic ?? ""
|
||||||
const showInviteAvatars = usePreference(client.store, null, "show_invite_avatars")
|
const showInviteAvatars = usePreference(client.store, null, "show_invite_avatars")
|
||||||
const noAvatarPreview = invite && !showInviteAvatars
|
const noAvatarPreview = invite && !showInviteAvatars
|
||||||
|
const joinRule = summary?.join_rule ?? invite?.join_rule ?? "invite"
|
||||||
|
const allowKnock = ["knock", "knock_restricted"].includes(joinRule) && !invite
|
||||||
|
const requiresKnock = joinRule === "knock_restricted" && !invite
|
||||||
|
&& (summary?.allowed_room_ids ?? []).findIndex(roomID => client.store.rooms.has(roomID)) !== -1
|
||||||
|
const acceptAction = invite ? "Accept" : "Join room"
|
||||||
|
|
||||||
return <div className="room-view preview">
|
return <div className="room-view preview">
|
||||||
<div className="preview-inner">
|
<div className="preview-inner">
|
||||||
{invite?.invited_by && !invite.dm_user_id ? <div className="inviter-info">
|
{invite?.invited_by && !invite.dm_user_id ? <div className="inviter-info">
|
||||||
|
@ -152,17 +173,28 @@ const RoomPreview = ({ roomID, via, alias, invite }: RoomPreviewProps) => {
|
||||||
</table>
|
</table>
|
||||||
</details>}
|
</details>}
|
||||||
{invite?.invited_by && <MutualRooms client={client} userID={invite.invited_by}/>}
|
{invite?.invited_by && <MutualRooms client={client} userID={invite.invited_by}/>}
|
||||||
|
{allowKnock && <input
|
||||||
|
className="knock-reason"
|
||||||
|
onChange={event => setKnockRequest(event.currentTarget.value)}
|
||||||
|
placeholder="Why do you want to join this room?"
|
||||||
|
value={knockRequest}
|
||||||
|
/>}
|
||||||
<div className="buttons">
|
<div className="buttons">
|
||||||
{invite && <button
|
{invite && <button
|
||||||
disabled={buttonClicked}
|
disabled={buttonClicked}
|
||||||
className="reject"
|
className="reject"
|
||||||
onClick={doRejectInvite}
|
onClick={doRejectInvite}
|
||||||
>Reject</button>}
|
>Reject</button>}
|
||||||
<button
|
{!requiresKnock && <button
|
||||||
disabled={buttonClicked}
|
disabled={buttonClicked}
|
||||||
className="primary-color-button"
|
className="primary-color-button"
|
||||||
onClick={doJoinRoom}
|
onClick={doJoinRoom}
|
||||||
>{invite ? "Accept" : "Join room"}</button>
|
>{acceptAction}</button>}
|
||||||
|
{allowKnock && <button
|
||||||
|
disabled={buttonClicked}
|
||||||
|
className="primary-color-button"
|
||||||
|
onClick={doKnockRoom}
|
||||||
|
>Ask to join</button>}
|
||||||
</div>
|
</div>
|
||||||
{error && <div className="error">
|
{error && <div className="error">
|
||||||
<ErrorIcon color="var(--error-color)"/>
|
<ErrorIcon color="var(--error-color)"/>
|
||||||
|
|
Loading…
Add table
Reference in a new issue