Warning: include_once(/var/www/html/pmwiki-2.2.86/cookbook/soap4pmwiki/soap4pmwiki.php): failed to open stream: No such file or directory in /var/www/html/fields/dbp13/local/config.php on line 4

Warning: include_once(): Failed opening '/var/www/html/pmwiki-2.2.86/cookbook/soap4pmwiki/soap4pmwiki.php' for inclusion (include_path='.:/opt/php/lib/php') in /var/www/html/fields/dbp13/local/config.php on line 4

Warning: Cannot modify header information - headers already sent by (output started at /var/www/html/fields/dbp13/local/config.php:4) in /var/www/html/pmwiki-2.2.86/pmwiki.php on line 1250
Datenbankpraktikum SS 2013 - MMOG - Spieler Allianzen Und Nachrichten Messagesystem

Messagesystem

Konstantin Obermann

Planung

Relationale Beziehungen zwischen User und den Messages

Da die Nachricht an mehrere Nutzer gerichtet sein kann, ist der Nachricht selbst kein recipient_id zugewiesen, um die 1.Normalform zu bewerkstelligen. Das Senden an mehrere Empfänger funktioniert nur über eine Rundmail, siehe: Allianzen.

  • user_id verweist auf den Sender der Nachricht
  • subject ist der Betreff der Nachricht
  • body ist der Inhalt der Nachricht
  • sender_deleted? (siehe Problemstellung beim Löschen der Nachrichten)

In der Relation receives werden ggf. mehrere Verweise auf diese Nachricht abgespeichert mit unterschiedlichen recipient_ids.

  • recipient_idsverweist auf einen Empfänger
  • read? dieser boolische Wert wird geändert, sobald der Empfänger die Nachricht öffnet.
  • recipient_deleted? (siehe Problemstellung beim Löschen der Nachrichten)

Problemstellung beim Löschen der Nachrichten

Wenn ein Spieler seinen Posteingang oder Postausgang bereinigen möchte, sollte dies erfolgen ohne dass die Nachricht aus der Datenbank gelöscht wird. Hierzu besitzt die Nachricht selbst das Attribut sender_deleted?, welches dafür sorgt, dass die Nachricht aus dem Postausgang gelöscht werden kann, ohne dass der/die Empfänger nicht mehr auf diese Nachricht zugreifen können.

Das Attribut recipient_deleted? sorgt hier ebenfalls dafür, dass Spieler ihre Nachrichten aus dem Posteingang löschen können, während andere Spieler, an die diese Nachricht gerichtet war, auf diese noch zugreifen und ebenfalls unabhängig von anderen Empfängern aus dem Posteingang löschen können.

Zwar existiert diese Nachricht noch in der Datenbank, kann jedoch von dem Benutzer, der sie "gelöscht" hat, nicht mehr abgefragt werden.

Implementierung

Model

Als erstes sollten die Beziehungen zwischen dem Sender, der Message und der (ggf. mehreren Empfängern) hergestellt werden.

user.rb:

  has_many :messages_user
  has_many :messages, -> { select("`messages`.*, `messages_users`.`read` AS `read`,
  `messages_users`.`recipient_deleted` as `deleted`") },
  :through => :messages_user
  accepts_nested_attributes_for :messages_user
  has_many :sent_messages, :class_name => 'Message', :foreign_key => 'sender_id'

message.rb:

  belongs_to :sender, :class_name => 'User', :foreign_key => 'sender_id'
    has_many :messages_users
    has_many :recipients, :class_name => 'User', :through => :messages_users, :source => :user

messages_user.rb:

  belongs_to :message 
  belongs_to :user

Das Usermodel besitzt eine Hilfsmethode, mit welcher man die Anzahl der ungelesenen Nachrichten abrufen kann.

  def unread_messages
    count=0
    self.messages.each do |message|
        count+=1 unless message.read?
    end
    return count
  end

Die Message besitzt zwei Hilfsmethoden:

Damit der Spieler nicht auf Nachrichten zugreifen kann, die nicht von ihm selbst verfasst oder nicht an ihn gerichtet wurden, besitzt das Message Model folgende Methode, der zur Überprüfung ein User übergeben wird:

  def is_readable?(user)
    return false if user==nil
    return (user==self.sender or self.recipients.exists?(user)==1)
  end

Sobald der Empfänger seine Nachricht gelesen/geöffnet hat, wird diese Relation in der messages_user Tabelle als "gelesen" markiert.

  def tag_msg_as_seen!(user)
    if(self.sender!=user)
      @entry=MessagesUser.all.where(:user_id=>user,:message_id=>self).first
      @entry.read=true
      @entry.save
    end
  end

Controller

Zuerst muss immer ein Spieler authentifiziert werden:

  before_filter :authenticate_user!

Der Spieler darf keine Nachrichten an sich selbst oder nicht existierende Spieler schicken. Das wird in der create Methode abgefangen:

    if @recipient!=nil and current_user!=@recipient and @message.save 
      @message.recipients<<@recipient      
      format.html { redirect_to @message, notice: GameSettings.get("SUCCESSMSG_MESSAGE_CREATED") }
    else
      format.html { redirect_to messages_path, notice: GameSettings.get("ERRMSG_MESSAGE_CREATED") }
    end

Die Methode destroy zerstört nicht die Nachricht selbst, sondern setzt (je nachdem, welcher Spieler gerade eingeloggt ist) das Attribut recipient_deleted? oder sender_deleted? auf true.


Da das Postfach aufgrund der Vielzahl an Forschungs- und Kampfberichten teilweise sehr unübersichtlich werden kann, hat der Controller zwei Methoden

  • Bereinigung des Postausgangs
  • Bereinigung des Posteingangs
  def flush_outbox
    relations=Message.all.where(:sender_id=>current_user)
    relations.each do |r|
      r.sender_deleted=true
      r.save
    end
    respond_to do |format|
      format.html { redirect_to messages_url }
    end
  end

Diese Methode sucht alle Nachrichten in der Datenbank, deren sender_id auf den aktuell eingeloggten Spieler verweist und setzt das Attribut sender_deleted auf true, um den Postausgang zu bereinigen. Das gleiche wird mit dem Posteingang und der Methode flush_inbox gemacht.

View

Die index.html.erb ist die Hauptseite des Nachrichtensystems. Hier können die Nachrichten verwaltet werden.

Die Sicht des Posteingang/-ausgang

Hier ist folgendes zu beachten: wenn sich im Posteingang Nachrichten befinden, deren Sender nicht mehr existiert, dann wird der Benutzername durch System ersetzt.

Fazit

Die Implementierung des Messagesystems war nicht die schwierigste Teilaufgabe. Trotzdem mussten wir viele Kleinigkeiten, wie Nullpointer unter verschieden Bedingungen (wie das Löschen der Nachrichten) beachten und abfangen.


Page last modified on August 23, 2013, at 04:13 PM