Community manual

Community Application Manual
Dirk-Jan Hoekstra
Januari 2001
Preface
The VPRO websites are getting more and more specific drawing people sharing the same
interests. The number of emails the editorial staff received showed a need for people to get in
contact with each other. To solve the absence for visitors to communicate with each other the
Community application has been build.
I carried out this project within the framework of a teaching practice as part of the study
Hogere Informatica (Software engineering) followed at the Noordelijke Hogeschool
Leeuwarden.
I want to thank the VPRO for this great assignment!
Januari 2001
Dirk-Jan Hoekstra
Table of contents
Preface .................................................................................................................................... 2
Table of contents .................................................................................................................... 3
Introduction ............................................................................................................................ 4
1 Architecture ......................................................................................................................... 5
1.1 MMObjectBuilders and MMObjectNodes ................................................................... 5
1.2 Fields of the MMObjectNodes message, channel and community .............................. 6
2 Writing a forum ................................................................................................................... 8
2.1 Making a listing of messages ....................................................................................... 8
2.2 Viewing a message ....................................................................................................... 9
2.2 How to post a message ............................................................................................... 10
3 Writing a chatbox .............................................................................................................. 12
3.1 Listing messages ........................................................................................................ 12
3.2 Connecting and disconnecting users .......................................................................... 13
3.3 Switching channels ..................................................................................................... 13
Appendix B Interface .......................................................................................................... 16
B.1 LIST TREE ................................................................................................................ 16
B.2 Message ..................................................................................................................... 17
B.3 Channel ...................................................................................................................... 18
B.4 Community ................................................................................................................ 19
Introduction
The Community application is part of the opensource content management system MMBase
(www.mmbase.org). It lays the foundation for several message systems by providing a way
for storing, editing and retrieving messages. Messages are grouped together in channels or in
other messages and channels are grouped together in communities so discussions can take
place in a logical order.
This manual describes all the commando’s of the Community application and shows how to
write a forum and chatbox as examples. If you are not familiar with the MMBase system it’s
advisable to read the documentation on the MMBase website first.
In chapter one you will find an explanation of the architecture of the application. While
chapter two and three describes making a forum and chatbox. At the end of this document a
listing of all commands with a short subscription is given that can be used while reading the
other chapters.
1 Architecture
1.1 MMObjectBuilders and MMObjectNodes
All content in MMBase is stored in MMObjectNodes. Each type of nodes have their own
MMObjectBuilder. These builders perform operations on there own subcloud of
MMObjectNodes like deleting, searching and managing their objects. All MMObjectNodes
together form one big cloud.
The four most important builders of the Community application are the Message, Channel,
Community and Users builder. The first three builders were specially designed for the
application and the last one existed already.
You can make relations between their MMObjectNodes (see figure 1). A parent-child relation
between a channel and a message means that the message is posted in that channel and a
parent-child relation between two messages means that one is written as a reply to the other.
Messages whose parent message is related to a particular channel or have a parent message
somewhere above in the chain whose related to the channel are also considered to be posted in
that channel. In technical terminology a chain of messages started somewhere in a channel or
message is called a thread.
Usually messages that are posted in a channel have something to do with the subject of the
channel. For example if the subject of the channel is “cars” the posted messages discuss cars.
Likewise channels with related subjects could be grouped together in communities making the
community the meta-subject.
When a user has a creator-subject relation with a message it means that the user has written
the message.
For some message systems like a chatbox it’s important to know which users are connected to
a channel therefor the Channel builder can make a relation between a user and a channel that
will expire after a particular amount of time. With a special commando the user can tell the
Channel builder he is still connected to the channel so the expire-time will get updated.
Channel
Com munity
number : integer
otype : integer
owner : varchar(12,0)
nam e : varchar(255)
subtitile : varchar(255)
intro : char(2047)
body : text
kind : varchar(15,0)
com munity has channel
number : integer
otype : integer
owner : varchar(12,0)
nam e : varchar(255)
subtitle : varchar(255)
intro : char(2047)
body : text
session : integer
state : integer
open : integer
highseq : integer
m axusers : integer
m essage is posted in channel
user is connected to channel
Message
Users
user has written m essage
number : integer
otype : integer
owner : varchar(12,0)
subject : varchar(255)
body : text
tim estampl : integer
tim estanph : integer
thread : integer
sequence : integer
info : char(512)
message is reply to m essage
Figure 1 – Architecture of the message, channel, community and user nodes
1.2 Fields of the MMObjectNodes message, channel and community
For now it’s not necessary to give a description of all fields of the nodes and only a
description is given about the most used and important fields.
To start with the message node it has a “number” field like all other MMObjectNodes which
contains an identification number that’s unique for every node. The “subject” and “body” may
be the most important fields of a message node because they tell the message. In every
message a timestamp is written splitted in two integers when the message gets posted. The
timestamp can be retrieved by asking the virtual timestamp field.
Every community has a name and a subtitle, a forum discussing cars could have the name
“Cars” with subtile “The Carlovers Forum”. Then “intro” could contain some summary about
why the community was started while “body” contains the whole story about how great cars
are. The “kind” field specifies as what kind of message system the community acts, in the
examples choosen in this manual these are “forum” and “chatbox”.
The fields the channel node has the same as the community have the same function, only their
contents would likely have some more precise meaning. A channel can be open, closed or
readonly according the “open” field. The maxium of users that may be connected to a channel
is specified in the “maxusers” field.
If a user has to login before he may read messages or he only has to login to be allowed to
post a message of he even doesn’t has to log in is specified in one of the flags in the status
field. These can easily be set in the MMBase editor.
[ Besides fields that get stored in the underlaying database a MMObjectNode can have some
virtual fields that get calculated by the nodes his builder. The virtual “timestamp” field was
already metioned, but a message node has three more virtual fields: resubject, replycount and
getinfovalue. “resubject” returns the subject pre added with one “RE: “, replycount returns the
number of childmessages and a the meaning of “getinfovalue” is explained in apendix A. ]
2 Writing a forum
2.1 Making a listing of messages
One of the first things you see when visiting a forum is an index of posted messages. LIST
TREE generates a listing of messages. After each parent message follow the child messages.
How messages of the same parent are sorted depends on the SORTFIELDS and SORTDIRS
attributes.
For example you have three messages in channel 2137 with subjects: “Volkswagens are
better cars than FIATs”, “I don’t agree, it depends on the car” and “Who wants to buy my old
grandma’s car?” and message two, you guessed, is a reply to the first message.
In a list tag you’ve to specifie what kind of MMObjectNodes you want to list, in this case we
want nodes of the type “message”. The NODE attribute specifies to which node these
messages must be related so we fill in the channel number, but we could also had filled in a
message number to show only the replies of that message.
<HTML>
<LIST TREE TYPE=”message” NODE=”2137” FIELDS=”subject”
SORTFIELDS=”subject” SORTDIRS=”DOWN” PROCESSOR=”COMMUNITYPRC”>
$ITEM1<BR>
</LIST>
</HTML>
Asking MMBase to parse the above LIST TREE would generate the following HTML page:
<HTML>
Volkswagens are better cars than FIATs<BR>
I don’t agree, it depends on the car<BR>
Who wants to buy my old grandma’s car? <BR>
</HTML>
As you can see the first message is alphabetically correct written before the third message
whose subject starts with a “W”, but message two with a subject starting with a “I” is written
after “V”, because it’s a reply to the first message.
Without telling which message is a reply to who this is not a very clear list for the visitors of
the forum, therefor the Message builder can calculate some virtual fields that make it possible
to create a HTML unnumbered list.
These are the virtual fields: listhead and listtail. They contain <UL> and </UL> tags and can’t
be used without each other. When you use these fields you should put listhead directly after
the <LIST> tag and listtail directly before </LIST> tag to get a correct listing. Also you have
to put <LI> and </LI> in the HTML code yourself. Here’s an example:
<HTML>
<LIST TREE TYPE=”message” NODE=”2137”
FIELDS=”listhead,listtail,subject” SORTFIELDS=”subject”
SORTDIRS=”DOWN” PROCESSOR=”COMMUNITYPRC”>
$ITEM1<LI>$ITEM3</LI>$ITEM2
</LIST>
</HTML>
The result will be:
<HTML>
<UL><LI>Volkswagens are better cars than FIATs</LI>
<UL><LI>I don’t agree, it depends on the car</LI></UL>
<LI>Who wants to buy my old grandma’s car?</LI></UL>
</HTML>
Now messages at the same depth in a thread get sorted on their subject, a more commen way
is to sort messages in the order they were posted. For every new message that gets posted a
sequence number can be asked from the Channel builder so they can be sorted on posting
order. It would also be possible to do this by sorting on the timestamp, but the advantage of
sorting by sequence number is that it's faster and messages can be re-ordered by the editorial
staff or a moderator.
To end our simple version of a messages listing we need to be able to jump to a page that
views the whole message by clicking on the subject. Herefor we use the number field of the
message that's unique for every MMObjectNode in MMBase:
<HTML>
<LIST TREE TYPE=”message” NODE=”2137”
FIELDS=”number,listhead,listtail,subject”
SORTFIELDS=”sequence” SORTDIRS=”UP” PROCESSOR=”COMMUNITYPRC”>
$ITEM2<LI><A HREF=”showmsg.shtml?2137+$ITEM1>$ITEM4
</A></LI>$ITEM3
</LIST>
</HTML>
2.2 Viewing a message
We use the page with the message listing to jump to a page that views the contents of the
message like his subject and body. To get a fieldvalue out of a node use the syntax $MODMMBASE-FIELD-{number}-{fieldname}^ where number is replaced by the
MMObjectNodes object number and fieldname by a fieldname of the node.
In this example we show the subject of the message, the name of the channel in which it got
posted and the message body. Because we added the object numbers of the channel and
message as parameters to the URL we can use $PARAM instead of typing the numbers.
<HTML>
<HEAD>
<TITLE>$MMBASE-FIELD-$PARAM2-subject^ posted in $MMBASE-FIELD$PARAM1-name^</TITLE>
<BODY>
$MOD-MMBASE-FIELD-$PARAM2-subject^
</BODY>
</HTML>
To make it possible for the user to jump to any replie the message may have got we add our
previous made LIST TREE and replace NODE=”2137” by NODE=”$PARAM2”. Now the
user can browse forward through the forum, but except for using the browers backbutton he
can’t browse backwards therefor we add a link to the messages parent:
<A HREF=”showmsg.shtml?$PARAM1+$MOD-MMBASE-FIELD-$PARAM2parent^”>One level higher</A>
But what if messages parent is not another message but a channel? Then we have to jump to
page with the LIST TREE, this can done with a simple check:
<IF $MOD-MMBASE-FIELD-$PARAM2-parent^=E$PARAM1>
<A HREF=”channel.shtml?$PARAM1”>
<ELSE>
<A HREF=”showmsg.shtml?$PARAM1+$MOD-MMBASE-FIELD-$PARAM2parent^”>
</IF>
One level higher</A>
2.2 How to post a message
There are two ways for posting messages, one is using the process method of the
COMMUNITYPRC processor that directly sends the input of a <FORM> to the Message
builder and the second and better way is using the transaction manager.
How to use the process method is explained in chapter three “Writing a Chatbox”. This
paragraph describes how to use the transaction manager to post a message, not how the
transaction manager works, because the transaction manager has it’s own documentation you
can find on the MMBase website and are recommended to read first before you continue.
Posting a message is at least a two steps process. For the next example there are two pages
used. In the first page the session variables are set by a <FORM> and in the other page the
message and the relations with the parent and optionally the user are created and commited to
MMBase.
This form lets the user enter a message with a subject so they are available in the page
“msgpost2.shtml” as session variables. Besides the subject and the body we need a sequence
number we later can use to sort on. The Channel builder can provides us with such number
with the command $MOD-MMBASE-BUILDER-channel{number}-NEWSEQ^ where
number is the number of the channel in which the messages gets posted. The channel number
and the number of the thread in which the message has to get posted, this can be the same as
the channel, are given to the page as parameters:
<FORM METHOD=”POST” ACTION="msgpost2.shtml?$PARAM1+$PARAM2">
<INPUT TYPE="TEXT" NAME="SESSION-SUBJECT" SIZE=80
MAXLENGTH=80>
<TEXTAREA NAME="SESSION-BODY" COLS="100" ROWS="20" WRAP="ON">
<INPUT TYPE="SUBMIT" NAME="SESSION-ACTION" VALUE="Post
message">
</FORM>
As long the bug in MMBase is not fixed that it isn’t clear who’s the parent and who’s the
child in relations between MMObjectNodes of the same type we also need to store the number
of the parent in the messages “thread” field.
For some forums it’s necessary to log in before a user may post a message, in that case there
exists a users node for that user that can be related to the message. When it’s not necessary to
log in the “info” field can be used to store the posters name as explained in appendix A.
Now all needed information is available on the next page and the transaction can be started. In
this example the transaction is directly commited but it would have been possible to put a
page that gives a preview inbetween the creation of the transaction and commiting it.
<HTML>
<transactions><create commitOnClose="true">
<createObject type="message" id="chn$PARAM1seq$SESSIONSEQUENCE^message" >
<setField name="subject">$SESSION-SUBJECT^</setField>
<setField name="body">$SESSION-BODY^</setField>
<setField name="thread">$PARAM2</setField>
<setField name="sequence">$SESSIONSEQUENCE^</setField>
<setField name="owner">system</setField>
</createObject>
<accessObject id="chn$PARAM1seq$SESSION-SEQUENCE^parent"
mmbaseId="$PARAM2"/>
<createRelation type="parent"
source="chn$PARAM1seq$SESSION-SEQUENCE^parent"
destination="chn$PARAM1seq$SESSION-SEQUENCE^message”/>
<IF $SESSION-LOGGEDIN^=Etrue>
<accessObject id="chn$PARAM1seq$SESSION-SEQUENCE^user"
mmbaseId="$SESSION-USERNUMBER^"/>
<createRelation type="creator"
source="chn$PARAM1seq$SESSION-SEQUENCE^user"
destination="chn$PARAM1seq$SESSION-SEQUENCE^message"/>
</IF>
</create></transactions>
<GOTO channel.shtml?$PARAM1>
</HTML>
3 Writing a chatbox
3.1 Listing messages
A webpage with a chatbox exists of multiple parts: a part that shows the messages, a part with
the user names of the connected users, a part that lets the user write a message and maybe a
part where the user can switch channels.
Usually in a chatbox there are more messages posted in a particular time than in a forum,
therefor messages are stored in memory for performance reasons. Listings on those temporary
nodes can be done with LIST TREE. Also to keep the performance as high as possible we
don’t want to ask for messages we’ve already got, so we store the messages in memory at the
clientside using JavaScript.
To be able to get new messages every second a webpage has to get reloaded doing a new
server request. If we put the variables that store the messages and the input box where the user
can type a message in the same page these data will be lost, therefor we use a frameset. The
variables are put in the frames their parent and the input box is put in a separate frame from
the frame that shows the messages. First the showmsg frame stores the results of LIST TREE
in the variables after which it uses these variables to write the messages to screen.
<PROCESSOR COMMUNITYPRC>
<HTML><!--showmsg.shtml -->
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
function reload()
{
location="msgframe.shtml?$PARAM1+$PARAM2";
}
parent.last = "";
<LIST TREE TYPE="temporary message" MAXCOUNT="20"
FIELDS="number,sequence,timestamp,body" NODE="$PARAM1"
STARTAFTERNODE="$PARAM2">
parent.add($ITEM2, "$MOD-INFO-TIMEFORMAT-$ITEM3-HH:mm:ss^",
$SESSION-USERNUMBER^, "$ITEM4");
</LIST>
</SCRIPT>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
for(i = 0; i < parent.msgCount; i++)
{
m = parent.messages[i];
if (m != null) document.write("[" + m.time + "] <FONT
COLOR=\"red\"><" + m.chatter + "></FONT> " + m.body +
"<BR>");
}
setTimeout("reload()", 5000);
</SCRIPT>
</BODY>
</HTML>
In this example PARAM1 contains the number of the channel and $PARAM2 the number of
the last message that was received. Adding the attribute STARTAFTERNODE makes that
only messages that come after STARTAFTERNODE are returned.
3.2 Connecting and disconnecting users
Because people using a chatbox are directly communicating with each other it’s important to
know who are reading and available to talk with, therefor users that enter the chatbox have to
log in and a relation between the user and the channel is made. This way a listing of all
connected users can be done with a simple LIST RELATIONS:
<LIST RELATIONS TYPE="users" FIELDS="number" NODE="$PARAM1"
PROCESSOR="MMBASE"><PART parts/username.shtml?$ITEM1></LIST>
It’s possible that users leave the chatbox without first disconnecting, for example when they
close their browser, herefor are three commandos: $MOD-MMBASE-BUILDER-channel{channel number}-join-{user number}, $MOD-MMBASE-BUILDER-channel-{channel
number}-quit-{user number} and $MOD-MMBASE-BUILDER-channel-{channel number}stillhere-{user number}. “join” makes the relation between the user and the channel and tells
the intern RelationBreaker about the relation. The RelationBreaker will automatically
disconnect the user after some period of time when the user doesn’t give regulary a signal
using the “stillhere” command he still has a window open with the chatbox. The “quit”
command also disconnect the user and can be used with JavaScript to signal MMBase the user
has disconnected if his browser supports the JavaScript “onClose” command.
It’s not nescessary to tell the RelationBreaker the user is still there every second, just every
five or ten minutes would be enough. Adding the folowing JavaScript code calls the
“stillhere”command every ten minutes.
<SCRIPT LANGUAGE=”JavaScript”>
function stillhere()
{
location="stillhere.shtml?$PARAM1+$SESSIONUSERNUMBER^";
}
setTimeout("stillhere", 1 * 60000);
</SCRIPT>
The “stillhere.shtml” page looks like this:
$MOD-MMBASE-BUILDER-channel-$PARAM1-STILLACTIVE-$PARAM2>
<GOTO showmsg.shtml?$PARAM1>
3.3 Switching channels
Switching channels is simple. When a user joins another channel of the same community the
old relation is broken and a relation with the new channel is made unless for some reason
joining the other channel isn’t possible. When the user joins the channel of another
community he still remains connected to the other channel, so it’s possible to chat on more
than one community.
Before the user may think of switching channels he should have a list of all the channels in
the community:
<LIST RELATIONS TYPE="channel" FIELDS="number,name"
NODE="$PARAM1" PROCESSOR="MMBASE"><A
HREF=”join.shml?$ITEM1+$SESSION-USERNUMBER^">$ITEM2</A>
</LIST>
Appendix A The info field
The message has an extra field called “info” that can be used for all kind of things. Ofcourse
it’s not adviseble to use it for something that gets used a lot, then it may be better to make it
an object staying in the practice of MMBase.
An exception is when users don’t have to login on a message system so more than one person
can use the same name. In this case it’s the question if making the name an objec makes any
sense, because the name hasn’t much of a meaning. The only meaning it has is that someone
used it for posting the message, but the name isn’t related to a particular person, therefor it has
only a relation with the message itself and is stored in the message.
When we use the “info” field to store a name we can’t use it to store other data, unless we
store a StringTagger in the “info” field and put the name in the StringTagger in which more
than one value can be stored. The data in StingTagger is stored in the same way as in a HTML
tag, for example: name=”Billy Jones” agreed=”11” disagreed=”34” votes=”117”.
Adding an attribute or setting a value can be done with $MOD-MMBASE-BUILDERmessage-{number}-SETINFOFIELD-{name of the attribute}-{new value for the attribute}^.
Values can be read with $MOD-MMBASE-BUILDER-message-{number}GETINFOFIELD-{name of the attribute}^.
Take into account that the maxium length of the “info” fied is 512 characters.
Appendix B Interface
B.1 LIST TREE
<LIST TREE> attributes and parameters
attributes
parameters
TYPE
“message”/
”temporary message”
NODE
thread number
meaning
comment
Required
The channel or
message node of
which you want the
child messages
Required
FIELDS
(virtual) fieldnames of
the message node
OPENTAG
contents of a HTML tag Specifies which
without the < and >
HTML tag to use in
defeault = UL
the virtual field
listhead
contens of HTML tag
Specifies which
without < and />
HTML tag to use in
default = UL
the virtua field listtail
a number
Skips the first number
of FROMCOUNT
nodes
CLOSETAG
FROMCOUNT
MAXCOUNT
a number
STARTAFTER
NODE
a number
SORTFIELDS
(virtual) fieldnames of
the message node
SORTDIRS
“UP”/”DOWN”
MAXDEPTH
a number
PROCESSOR
“COMMUNITYPRC”
The maximum
number of nodes to
return
Skips the first
messages until the
node STARTAFTER
NODE is passed
Returned nodes are
sorted the first field,
the on the second, etc
“UP” sort from “A”
to “Z” of from “0” to
>= 0
No messages with a
depth higher than
MAXDEPTH are
returned
Required; listhead and
listtail can only used
together
Instead of = use # and
instead of “ use “
Instead of = use # and
instead of “ use “
FROMCOUNT can
be used with
MAXCOUNT to get
the nodes 23 to 40 for
example
STARTAFTER
NODE has to be a
node with a depth of
zero
By listing a TREE
child nodes are
always returned after
their parent node
When not specified
the default sort
direction is “UP”
Not required when
specified in page
B.2 Message
Fields of the message node
name
type
number
integer
otype
owner
subject
body
timestampl
integer
varchar(12,0)
varchar(255)
text
integer
timestamph
integer
thread
integer
sequence
integer
info
char(512)
Virtual fields
name
depth
type
integer
getinfovalue(x)
string
parent
a number
replycount
integer
resubject
string
description
A unique number for every
MMObjectNode
Type of the node
Owner of the node
Subject of the message
The message itself
Stores the lower bits
of the timestamp
comment
description
How depth the message is
posted in a thread or with
other words the number of
nodes between the message
and the beginning of the
thread
Where x is the name of a
field of the tagger in info
comment
This virtual field can
only be used in <LIST
TREE>
Use the virtual field
timestamp instead
for getting the
timestamp
Stores the higher bits
Use the virtual field
of the timestamp
timestamp instead
for getting the
timestamp
node number of the parent Workaround for the
message or channel
bug in relations
The sequence number of
You have to set this
messages getting post in the value yourself
channel
Field for storing some extra To put en get values
date
out of the info field
use the getinfofield
and setinfofield
commands
Does the same as
GETINFOFIELD of
the builder
The number of the message
or channel whose his parent
The number of replies the
message got inclusive those
of his child messages
The value of the subject
When the subject
field pre added with RE:
already starts with
RE: nothing is added
timestamp
long
Time in miliseconds at
which the message got
posted
Commands of the message node
$MOD-MMBASE-BUILDER-message-{message number}-{command}-{params}
command
params
description
comment
DEL
Removes the node
and his child
messages
GETINFOFIELD
fieldname
Returns the value of
the field out of info
tagger
SETINFOFIELD
fieldname-value
The fieldname to set
in the tagger with the
specified value
B.3 Channel
Fields of the channel node
name
type
number
integer
otype
owner
name
subtitle
integer
varchar(12,0)
varchar(255)
varchar(255)
intro
char(2047)
body
text
session
integer
state
integer
open
integer
maxusers
integer
description
A unique number for
every
MMObjectNode
Type of the node
Owner of the node
Name of the channel
Subtitle of the
channel, add some
extra info to the name
Summary about the
subject of the channel
More specific than
intro
Specifies of the
channel is a recording
session
The state of the
channel
If a channel is open,
closed or readonly.
The maximum of
users that can connect
to the channel
comment
Recording discussions
isn’t yet implemented
Not implemented
Commands of the channel node
$MOD-MMBASE-BUILDER-channel-{channel number}-{command}-{params}
command
params
description
comment
CLOSE
Closes the channel
DELALLMESSAGES
Removes all messages A quick way for
in a channel
ISOPEN
JOINS
a user number
NEWSEQ
OPEN
QUIT
a user number
STILLACTIVE
a user number
removing all
messages in a channel
Returns open, closed
or readonly
Connects the user to
the channel
Returns the next free
sequence number
Opens the channel
Disconnects from the
channel
Tell the builder the
After some period of
user is still connected inactivity the user is
to the channel
automatically
disconnected
B.4 Community
Fields of the community node
name
type
number
integer
otype
owner
name
subtitle
integer
varchar(12,0)
varchar(255)
varchar(255)
intro
char(2047)
body
text
kind
char(12)
description
A unique number for every
MMObjectNode
Type of the node
Owner of the node
Name of the community
Subtitle of the community,
add some extra info to the
name
Summary about the subject
of the channel
More specific information
about the community, what
kind of channels, etc
The kind of community. At
this moment “forum” and
“chatbox” are implemented
comment
It’s possible to make
other kinds of
message systems.