diff --git a/smserver/chat_commands/general.py b/smserver/chat_commands/general.py index 1f48c0c..716deb5 100644 --- a/smserver/chat_commands/general.py +++ b/smserver/chat_commands/general.py @@ -1,7 +1,9 @@ """ General Chat command to handle """ from smserver import models +from smserver import smutils from smserver.chatplugin import ChatPlugin +from smserver.chathelper import with_color class ChatHelp(ChatPlugin): @@ -75,3 +77,230 @@ def __call__(self, serv, message): for user in serv.active_users: user.chat_timestamp = serv.conn.chat_timestamp + +class FriendNotifications(ChatPlugin): + command = "friendnotif" + helper = "Enable notifications whenever a friend gets on/off line. /friendnotif" + + def __call__(self, serv, message): + + for user in serv.active_users: + if user.friend_notifications: + user.friend_notifications = False + serv.send_message("Friend notifications disabled", to="me") + else: + user.friend_notifications = True + serv.send_message("Friend notifications enabled", to="me") + +class AddFriend(ChatPlugin): + command = "addfriend" + helper = "Add a friend. /addfriend user" + + def __call__(self, serv, message): + for user in serv.active_users: + if not user: + return + newfriend = serv.session.query(models.User).filter_by(name=message).first() + if not newfriend: + serv.send_message("Unknown user %s" % with_color(message), to="me") + return + if newfriend.name == user.name: + serv.send_message("Cant befriend yourself", to="me") + return + relationships = serv.session.query(models.Relationship).filter( \ + ((models.Relationship.user1_id == user.id) & (models.Relationship.user2_id == newfriend.id)) | \ + (models.Relationship.user2_id == user.id) & (models.Relationship.user1_id == newfriend.id)) + if not relationships.first(): + serv.session.add(models.Relationship(user1_id = user.id, user2_id = newfriend.id, state = 0)) + serv.send_message("Friend request sent to %s" % with_color(message), to="me") + else: + relationships = relationships.all() + if len(relationships) != 1: + if friendship[0].state == 2: + if friendship.user1_id == user.id: + Unignore.__call__(self, serv, message) + friendship = relationships[1] + if friendship[1].state == 2: + if friendship.user1_id == user.id: + Unignore.__call__(self, serv, message) + friendship = relationships[0] + else: + friendship = relationships[0] + if friendship.state == 1: + serv.send_message("%s is already friends with you" % with_color(message), to="me") + return + if friendship.state == 2: + serv.send_message("Cant send %s a friend request" % with_color(message), to="me") + return + if friendship.user1_id == user.id: + serv.send_message("Already sent a friend request to %s" % with_color(message), to="me") + return + friendship.state = 1 + serv.send_message("Accepted friend request from %s" % with_color(message), to="me") + serv.session.commit() + +class RemoveFriend(ChatPlugin): + command = "removefriend" + helper = "Remove a friend. /removefriend user" + + def __call__(self, serv, message): + for user in serv.active_users: + if not user: + return + oldfriend = serv.session.query(models.User).filter_by(name=message).first() + if not oldfriend: + serv.send_message("Unknown user %s" % with_color(message), to="me") + return + friendship = serv.session.query(models.Relationship).filter( \ + ((models.Relationship.user1_id == user.id) & (models.Relationship.user2_id == oldfriend.id) & ((models.Relationship.state == 1) | (models.Relationship.state == 0))) | \ + ((models.Relationship.user2_id == user.id) & (models.Relationship.user1_id == oldfriend.id) & ((models.Relationship.state == 1) | (models.Relationship.state == 0))) ) + friendships = friendship.first() + if not friendships: + serv.send_message("%s is not your friend" % with_color(message), to="me") + serv.session.delete(friendships) + serv.session.commit() + serv.send_message("%s is no longer your friend" % with_color(message), to="me") + + +class Ignore(ChatPlugin): + command = "ignore" + helper = "Ignore someone(Can't send friend requests or pm). /ignore user" + + def __call__(self, serv, message): + for user in serv.active_users: + if not user: + return + newignore = serv.session.query(models.User).filter_by(name=message).first() + if not newignore: + serv.send_message("Unknown user %s" % with_color(message), to="me") + return + if newignore.name == user.name: + serv.send_message("Cant ignore yourself", to="me") + return + relationships = serv.session.query(models.Relationship).filter( \ + ((models.Relationship.user1_id == user.id) & (models.Relationship.user2_id == newignore.id)) | \ + (models.Relationship.user2_id == user.id) & (models.Relationship.user1_id == newignore.id)) + relationships = relationships.all() + ignored = False + for relationship in relationships: + if relationship.state == 0 or relationship.state == 1: + serv.session.delete(relationship) + serv.send_message("%s is no longer your friend" % with_color(message), to="me") + elif relationship.state == 2 and relationship.user1_id == user.id: + serv.send_message("%s is already ignored" % with_color(message), to="me") + ignored = True + if not ignored: + serv.session.add(models.Relationship(user1_id = user.id, user2_id = newignore.id, state = 2)) + serv.send_message("%s ignored" % with_color(message), to="me") + serv.session.commit() + + + +class Unignore(ChatPlugin): + command = "unignore" + helper = "Stop ignoring someone. /unignore user" + + def __call__(self, serv, message): + for user in serv.active_users: + if not user: + return + newignore = serv.session.query(models.User).filter_by(name=message).first() + if not newignore: + serv.send_message("Unknown user %s" % with_color(message), to="me") + return + ignore = serv.session.query(models.Relationship).filter_by(user1_id = user.id).filter_by(user2_id = newignore.id).filter_by(state = 2).first() + if ignore: + serv.session.delete(ignore) + serv.session.commit() + serv.send_message("%s unignored" % with_color(message), to="me") + return + serv.send_message("%s is not currently ignored. Cant unignore" % with_color(message), to="me") + + + +class Friendlist(ChatPlugin): + command = "friendlist" + helper = "Show friendlist" + + def __call__(self, serv, message): + for user in serv.active_users: + if not user: + return + friends = serv.session.query(models.Relationship).filter_by(state = 1).filter((models.Relationship.user1_id == user.id) | models.Relationship.user2_id == user.id).all() + friendsStr = "" + for friend in friends: + if friend.user1_id == user.id: + frienduser = serv.session.query(models.User).filter_by(id = friend.user2_id).first() + else: + frienduser = serv.session.query(models.User).filter_by(id = friend.user1_id).first() + friendsStr += frienduser.name + ", " + if friendsStr.endswith(", "): + friendsStr = friendsStr[:-2] + requests = serv.session.query(models.Relationship).filter_by(user2_id = user.id).filter_by(state = 0).all() + requestsStr = "" + for request in requests: + requestsStr += serv.session.query(models.User).filter_by(id=request.user1_id).first().name + ", " + if requestsStr.endswith(", "): + requestsStr = requestsStr[:-2] + requestsoutgoing = serv.session.query(models.Relationship).filter_by(user1_id = user.id).filter_by(state = 0).all() + requestsoutgoingStr = "" + for request in requestsoutgoing: + requestsoutgoingStr += serv.session.query(models.User).filter_by(id=request.user2_id).first().name + ", " + if requestsoutgoingStr.endswith(", "): + requestsoutgoingStr = requestsoutgoingStr[:-2] + ignores = serv.session.query(models.Relationship).filter_by(user1_id = user.id).filter_by(state = 2).all() + ignoresStr = "" + for ignore in ignores: + ignoresStr += serv.session.query(models.User).filter_by(id=ignore.user2_id).first().name + ", " + if ignoresStr.endswith(", "): + ignoresStr = ignoresStr[:-2] + + serv.send_message("Friends: %s" % friendsStr, to="me") + serv.send_message("Incoming requests: %s" % requestsStr, to="me") + serv.send_message("Outgoing requests: %s" % requestsoutgoingStr, to="me") + serv.send_message("Ignoring: %s" % ignoresStr, to="me") + + +class PrivateMessage(ChatPlugin): + command = "pm" + helper = "Send a private message. /pm user message" + + def __call__(self, serv, message): + user = models.User.from_ids(serv.conn.users, serv.session) + user = user[0] + #user = serv.session.query(models.User).filter_by(online = True).filter_by(last_ip = serv.conn.ip).first() + if not user: + return + message = message.split(' ', 1) + if len(message) < 2: + serv.send_message("Need a text message to send", to="me") + return + if self.sendpm(serv, user, message[0], message[1]) == False: + if '_' in message[0]: + self.sendpm(serv, user, message[0].replace('_',' '), message[1]) + + def sendpm(self, serv, user, receptorname, message): + receptor = serv.session.query(models.User).filter_by(online=True).filter_by(name=receptorname).first() + if not receptor: + serv.send_message("Could not find %s online" % with_color(receptorname), to="me") + return False + if receptor.name == user.name: + serv.send_message("Cant pm yourself", to="me") + return False + ignore = serv.session.query(models.Relationship).filter( \ + (((models.Relationship.user1_id == user.id) & (models.Relationship.user2_id == receptor.id)) | \ + ((models.Relationship.user2_id == user.id) & (models.Relationship.user1_id == receptor.id))) & \ + (models.Relationship.state == 2)).first() + if ignore: + serv.send_message("Cant send %s a private message" %with_color(receptorname), to="me") + return False + if not receptor: + serv.send_message("Could not find %s online" % with_color(receptorname), to="me") + return False + serv.send_message("To %s : %s" % (with_color(receptor.name), message), to="me") + receptor = serv.server.find_connection(receptor.id) + #if i do what's commented both players get the message + #serv.send_message("From %s : %s" % (with_color(user.name), message), receptor) + receptor.send(smutils.smpacket.SMPacketServerNSCCM(message="From %s : %s" % (with_color(user.name), message))) + return True + diff --git a/smserver/controllers/legacy/login.py b/smserver/controllers/legacy/login.py index 0d7f8ff..85ff50f 100644 --- a/smserver/controllers/legacy/login.py +++ b/smserver/controllers/legacy/login.py @@ -60,6 +60,25 @@ def handle(self): )) self.send(models.Room.smo_list(self.session, self.active_users)) + friends = self.session.query(models.Relationship).filter_by(state = 1).filter((models.Relationship.user1_id == user.id) | (models.Relationship.user2_id == user.id)).all() + for friend in friends: + if friend.user1_id == user.id: + friendid = friend.user2_id + else: + friendid = friend.user1_id + friendconn = self.server.find_connection(friendid) + self.server.send_friend_list(friendid, friendconn) + frienduser = self.session.query(models.User).filter_by(id = friendid).first() + if frienduser.online == True: + if frienduser.friend_notifications == True and friendconn: + self.send_message( + "Your friend %s connected" % user.name, + friendconn) + if user.friend_notifications: + self.send_message( + "Your friend %s is online" % frienduser.name, + to="me") + self.server.send_friend_list(user.id, self.conn) def _send_server_resume(self, nb_onlines, max_users): self.send_message(self.server.config.server.get("motd", ""), to="me") diff --git a/smserver/models/__init__.py b/smserver/models/__init__.py index b7b336a..365ad36 100644 --- a/smserver/models/__init__.py +++ b/smserver/models/__init__.py @@ -8,3 +8,4 @@ from smserver.models.ban import Ban from smserver.models.game import Game from smserver.models.connection import Connection +from smserver.models.relationship import Relationship diff --git a/smserver/models/relationship.py b/smserver/models/relationship.py new file mode 100644 index 0000000..1f1afe9 --- /dev/null +++ b/smserver/models/relationship.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# -*- coding: utf8 -*- + + +import datetime +import enum +from sqlalchemy import Column, Integer, String, DateTime, Boolean, ForeignKey, func +from sqlalchemy.orm import relationship, reconstructor, object_session + +from smserver.models import schema +from smserver.chathelper import with_color, nick_color +from smserver.models.privilege import Privilege +from smserver import ability + +class Relationship(schema.Base): + __tablename__ = 'relationships' + + REPR = { + 0: "", + 2: "%", + 3: "@", + 5: "&", + 10: "~" + } + + id = Column(Integer, primary_key=True) + user1_id = Column(Integer) + user2_id = Column(Integer) + state = Column(Integer, default=0) + + def __repr__(self): + return "" % (self.id, self.user1_id, self.user2_id) diff --git a/smserver/models/user.py b/smserver/models/user.py index f3f0116..648810a 100644 --- a/smserver/models/user.py +++ b/smserver/models/user.py @@ -48,6 +48,8 @@ class User(schema.Base): status = Column(Integer, default=1) chat_timestamp = Column(Boolean, default=False) + friend_notifications = Column(Boolean, default=False) + room_id = Column(Integer, ForeignKey('rooms.id')) room = relationship("Room", back_populates="users") diff --git a/smserver/server.py b/smserver/server.py index 547ff88..b283a62 100644 --- a/smserver/server.py +++ b/smserver/server.py @@ -252,7 +252,22 @@ def on_disconnect(self, session, conn): #pylint: disable=arguments-differ for user in users: models.User.disconnect(user, session) self.log.info("Player %s disconnected", user.name) - + + friends = session.query(models.Relationship).filter_by(state = 1).filter((models.Relationship.user1_id == user.id) | (models.Relationship.user2_id == user.id)).all() + for friend in friends: + if friend.user1_id == user.id: + friendid = friend.user2_id + else: + friendid = friend.user1_id + friendconn = self.find_connection(friendid) + self.send_friend_list(friendid, friendconn) + frienduser = session.query(models.User).filter_by(id = friendid).first() + if frienduser.online == True and frienduser.friend_notifications == True and not friendconn == None: + self.send_message( + "Your friend %s disconnected" % user.name, + conn=friendconn + ) + room = connection.room if room: self.send_message( @@ -272,6 +287,40 @@ def send_user_list(self, room): self.sendroom(room.id, room.nsccuul) + + def send_friend_list(self, userid, conn): + + return + + """ + Requires FLU packets added in smpacket + def send_friend_list(self, userid, conn): + if conn == None: + return + usernames = [] + userstates = [] + with self.db.session_scope() as session: + friends = session.query(models.Relationship).filter_by(state = 1).filter((models.Relationship.user1_id == userid) | (models.Relationship.user2_id == userid)).all() + + for friend in friends: + if friend.user1_id == userid: + frienduser = session.query(models.User).filter_by(id = friend.user2_id).first() + else: + frienduser = session.query(models.User).filter_by(id = friend.user1_id).first() + usernames.append(frienduser.name) + if frienduser.online == True: + userstates.append(1 + frienduser.status) + else: + userstates.append(0) + + + packet = smpacket.SMPacketServerFLU( + nb_players=len(usernames), + players=[{"name": name, "status": state} + for name, state in zip(usernames, userstates)] + ) + conn.send(packet) + """ def send_message(self, message, room=None, conn=None, func=None): """ Send a chat message (default to all)