1
0
Fork 0

Compare commits

...

5 Commits

Author SHA1 Message Date
nicoco ae21c6f365 ci: install golang from bookworm-backports 2024-02-17 14:57:33 +01:00
nicoco e3c36becdc feat: group creation and affiliation changes 2024-02-17 14:51:10 +01:00
nicoco 4c88f75a88 doc: point to raver's dockerhub for arm64 containers 2024-02-17 14:50:01 +01:00
nicoco c745aa4050 chore: update entrypoint 2024-02-17 14:49:38 +01:00
nicoco 065252fba4 chore: update DOAP 2024-02-17 14:49:28 +01:00
8 changed files with 94 additions and 15 deletions

View File

@ -1,7 +1,6 @@
image: debian/bookworm
packages:
- curl
- golang
- python-is-python3
- python3-dev
- python3-pybindgen
@ -12,6 +11,10 @@ artifacts:
- ./docs.tar.gz
- ./package.tar
tasks:
- install-golang: |
echo "deb http://deb.debian.org/debian bookworm-backports main"|sudo tee -a /etc/apt/sources.list
sudo apt update
sudo apt install -y golang -t bookworm-backports
- install-poetry: |
curl -sSL https://install.python-poetry.org | python3 -
sudo ln -s ~/.local/bin/poetry /usr/local/bin

View File

@ -1,5 +1,5 @@
# Changes here will be overwritten by Copier; NEVER EDIT MANUALLY
_commit: ae31af1
_commit: d5866b9
_src_path: git+https://git.sr.ht/~nicoco/slidge-template
author: deuill
author_email: alex@deuill.org
@ -17,10 +17,9 @@ srht_secret_docker: 173244e1-c233-43de-969f-65965c5487e1
srht_secret_pypi: 3ecea679-dec7-4ac0-8821-75d0f4fe0773
srht_username: nicoco
xeps:
- note: Participating in groups work, but creation/deletion/moderation is not yet
possible from Slidge.
- note: Groups are supported, including administration, moderation and creation.
number: 45
status: partial
status: complete
- note: Typing notifications only.
number: 85
status: complete

View File

@ -28,6 +28,7 @@ for general info on how to set up an XMPP server component.
From [dockerhub](https://hub.docker.com/r/nicocool84/slidge-whatsapp)
```sh
# use ravermeister/slidge-whatsapp for arm64 (thanks raver! <3)
docker run docker.io/nicocool84/slidge-whatsapp
```

View File

@ -47,8 +47,8 @@
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0045.html" />
<xmpp:status>partial</xmpp:status>
<xmpp:note>Participating in groups work, but creation/deletion/moderation is not yet possible from Slidge.</xmpp:note>
<xmpp:status>complete</xmpp:status>
<xmpp:note>Groups are supported, including administration, moderation and creation.</xmpp:note>
</xmpp:SupportedXep>
</implements>
<implements>

View File

@ -1,11 +1,8 @@
import sys
from slidge.__main__ import main as slidge_main
from slidge import entrypoint
def main() -> None:
sys.argv.extend(["--legacy", "slidge_whatsapp"])
slidge_main()
def main():
entrypoint("slidge_whatsapp")
if __name__ == "__main__":

View File

@ -3,7 +3,7 @@ from datetime import datetime, timezone
from typing import TYPE_CHECKING, Optional
from slidge.group import LegacyBookmarks, LegacyMUC, LegacyParticipant, MucType
from slidge.util.types import Mention
from slidge.util.types import Mention, MucAffiliation
from slixmpp.exceptions import XMPPError
from .generated import whatsapp
@ -88,13 +88,15 @@ class MUC(LegacyMUC[str, str, Participant, str]):
if data.Action == whatsapp.GroupParticipantActionRemove:
self.remove_participant(participant)
else:
participant.affiliation = "member"
if data.Affiliation == whatsapp.GroupAffiliationAdmin:
participant.affiliation = "admin"
participant.role = "moderator"
elif data.Affiliation == whatsapp.GroupAffiliationOwner:
participant.affiliation = "owner"
participant.role = "moderator"
else:
participant.affiliation = "member"
participant.role = "participant"
def replace_mentions(self, t: str):
return replace_whatsapp_mentions(
@ -128,6 +130,29 @@ class MUC(LegacyMUC[str, str, Participant, str]):
if self.subject != subject:
self.session.whatsapp.SetGroupTopic(self.legacy_id, subject)
async def on_set_affiliation(
self,
contact: "Contact", # type:ignore
affiliation: MucAffiliation,
reason: Optional[str],
nickname: Optional[str],
):
if affiliation == "member":
if contact in self._participants_by_contacts:
change = "demote"
else:
change = "add"
elif affiliation == "admin":
change = "promote"
elif affiliation == "outcast" or affiliation == "none":
change = "remove"
else:
raise XMPPError(
"bad-request",
f"You can't make a participant '{affiliation}' in whatsapp",
)
self.session.whatsapp.SetAffiliation(self.legacy_id, contact.legacy_id, change)
class Bookmarks(LegacyBookmarks[str, MUC]):
session: "Session"

View File

@ -453,6 +453,32 @@ func (s *Session) GetGroups() ([]Group, error) {
return groups, nil
}
// CreateGroup attempts to create a new WhatsApp group for the given human-readable name and
// participant JIDs given.
func (s *Session) CreateGroup(name string, participants []string) (Group, error) {
if s.client == nil || s.client.Store.ID == nil {
return Group{}, fmt.Errorf("Cannot create group for unauthenticated session")
}
var jids []types.JID
for _, p := range participants {
jid, err := types.ParseJID(p)
if err != nil {
return Group{}, fmt.Errorf("Could not parse participant JID: %s", err)
}
jids = append(jids, jid)
}
req := whatsmeow.ReqCreateGroup{Name: name, Participants: jids}
info, err := s.client.CreateGroup(req)
if err != nil {
return Group{}, fmt.Errorf("Could not create group: %s", err)
}
return newGroup(s.client, info), nil
}
// GetAvatar fetches a profile picture for the Contact or Group JID given. If a non-empty `avatarID`
// is also given, GetAvatar will return an empty [Avatar] instance with no error if the remote state
// for the given ID has not changed.
@ -543,6 +569,23 @@ func (s *Session) SetGroupTopic(resourceID, topic string) error {
return s.client.SetGroupTopic(jid, "", "", topic)
}
func (s *Session) SetAffiliation(groupID, participantID string, change whatsmeow.ParticipantChange) ([]types.GroupParticipant, error) {
if s.client == nil || s.client.Store.ID == nil {
return make([]types.GroupParticipant, 0), fmt.Errorf("Cannot set affiliation for unauthenticated session")
}
groupJID, err := types.ParseJID(groupID)
if err != nil {
return make([]types.GroupParticipant, 0), fmt.Errorf("Could not parse JID for affiliation change: %s", err)
}
participantJID, err := types.ParseJID(participantID)
if err != nil {
return make([]types.GroupParticipant, 0), fmt.Errorf("Could not parse JID for affiliation change: %s", err)
}
return s.client.UpdateGroupParticipants(groupJID, []types.JID{participantJID}, change)
}
// FindContact attempts to check for a registered contact on WhatsApp corresponding to the given
// phone number, returning a concrete instance if found; typically, only the contact JID is set. No
// error is returned if no contact was found, but any unexpected errors will otherwise be returned

View File

@ -443,6 +443,17 @@ class Session(BaseSession[str, Recipient]):
"""
self.whatsapp.SetAvatar("", await get_bytes_temp(bytes_) if bytes_ else "")
async def on_create_group(
self, name: str, contacts: list[Contact] # type:ignore
):
"""
Creates a WhatsApp group for the given human-readable name and participant list.
"""
group = self.whatsapp.CreateGroup(
name, go.Slice_string([c.legacy_id for c in contacts])
)
return await self.bookmarks.legacy_id_to_jid_local_part(group.JID)
async def on_search(self, form_values: dict[str, str]):
"""
Searches for, and automatically adds, WhatsApp contact based on phone number. Phone numbers