[ANN] %messages.cgi 0.5.0
[1/3] from: ryan::christiansen::intellisol::com at: 29-Mar-2001 16:55
Following is an all-inclusive script for running a site with news
headlines. It is best suited for use within a FRAME or IFRAME. It includes
administration functions for creating, editing, and deleting news
headlines. It also includes options for displaying news headlines in index
form or normal output with all headlines and content. It includes options
for displaying news headlines with or without reference numbers.
The script defaults to displaying all messages which exist in a /news
directory when it is hit without CGI input (if no news directory exists or
there are no messages, it will display an error.)
To login to use admin functions, you use a URL as such:
http://www.domain.com/cgi-bin/messages.cgi?actionType=display-login&messageType=news&messageID=none
The script includes the following function for creating a %logins.bin file
which contains login usernames and passwords for logging in.
encrypt-logins: func [
{Encrypt login usernames and passwords.}
logins [string!] {A string containing the 'login word and a database of
usernames and associated passwords.}
][
write/binary %logins.bin encrypt {logins:[["username1" "password1"]
["username2" "password2"]]}
]
Once you login, when you navigate the admin functions, the script will pass
a sessionID which will time out after 10 minutes of non-use.
The script follows. If you want to know more or to see a live demo, let me
know. Thanks to Bohdan Lechnowsky for the encryption functions.
#!rebol -cs
REBOL [
Title: "Messages"
Date: 29-Mar-2001
Version: 0.5.0
File: %messages.cgi
Home: http://www.dangeroustechnology.com
Author: "Ryan C. Christiansen"
Email: [norsepower--qwest--net]
Rights: "Copyright (C) Ryan C. Christiansen 1999-2001"
Purpose: {
Create, display, edit, and delete messages using a standard XML
storage format and CSS2-reference <DIV> tags for display. The script is
dependent on the use of .css stylesheets for separate messageTypes.
}
Comment: {
This file %messages.cgi is a single engine for creating,
displaying, editing, and deleting messages. For displaying, editing, and
deleting messages, %messages.cgi must receive the following variables as
CGI input: actionType, messageType, and messageID. For creating messages,
%messages.cgi must receive a REBOL e-mail object! as input or the following
variables as CGI input: actionType, messageType, subject, author, and
content. During message creation, %messages.cgi creates the following
variables: date and messageID.
}
History: [
0.0.9 [4-Jan-2001 "Created %std_msg_func_lib.r based on previous
work." "Ryan"]
0.1.1 [5-Jan-2001 "Added 'display-markup object! functions and
changed file name to %standard-message-function-library.r" "Ryan"]
0.1.2 [8-Jan-2001 "Fixed 'read-message-directory to output file
names including path to directory defined by messageType." "Ryan"]
0.2.1 [9-Jan-2001 "Corrected target 'word in 'write-xml-message.
Added 'create-message object! functions. Corrected 'display-markup to
output string! datatype instead of block! datatype. Negated use of
'message-request-data target variable in 'read-directory-messages. Added
'get-messages-for-display object! functions." "Ryan"]
0.2.3 [10-Jan-2001 "Added 'display-messages function, the
top-level function for displaying messages. Pared down usage in 'Example
portion of header to include only top-most functions. Removed /html-output
function from 'get-messages-for-display object! and removed /html function
from 'display-markup object!" "Ryan"]
0.2.4 [11-Jan-2001 "Changed the order of values (switched 'author'
and 'subject') for the XML grammar in all functions. Changed the 'either
switch in 'display-messages from 'none to the string! datatype 'none'."
Ryan
]
0.2.5 [8-Feb-2001 "Removed incorrect class/id combinations from CSS
font designations. Changed 'display-markup and 'display-messages to markup
content using only CSS class designations instead of class/id
combinations." "Ryan"]
0.2.7 [18-Feb-2001 "Added routine to 'display-messages function
which will display all messages in a directory minus the content value. The
index option is called by sending 'index' as the 'messageID value to
'display-messages." "Ryan"]
0.3.7 [28-Mar-2001 "Changed name of script to %messages.cgi.
Changed e-mail address in header. Updated Comment and Example field in
header. Changed 'display-markup to markup messages using <div> tags instead
of <font> tags. Changed 'display-markup from a function to an object which
includes 'for-reading object including 'with-reference (display messageID
and messageType) and 'without-reference functions, and also 'for-editing
object with 'with-reference function to display a message or messages for
editing, including <FORM> and <INPUT> tags. Added 'edit-message function
for editing messages. Added 'edited-from-cgi function to 'decode-to-object
object! Added 'delete-message function. Added 'message-action-cgi
uber-function." "Ryan"]
0.5.0 [29-Mar-2001 "Added return display for delete, create, and
edit switches in 'message-action-cgi. Changed 'append to 'insert in
'read-directory-messages function, which will make newest messages display
first. Changed radio button value for edit/delete choice from 'choice' to
'actionType'. Fixed the way 'for-editing object functions display form
values and form targets. Added form for creating new messages to
'for-editing object functions. Added 'create-form' action type to switch in
'message-action-cgi function. Added 'display-create-form function to
display message creation form. Added Bohdan Lechnowsky's %encrypt.r
functions. Created 'encrypt-logins function for creating %.bin files
containing usernames and passwords. Added 'display-login-form function to
display login form. Added 'sessionID check to all administration functions
including delete, edit, display-admin, create, and create-form. Added
'sessionID variables to form output in all admin forms. Added sort/reverse
statement in 'read-dir
ectory-messages function in an attempt to make the newest messages display
first. Added if error? try statement to program section script which will
default to displaying messages in the absence of cgi input data." "Ryan"]
]
Example: {
Decode CGI input and create, display, edit, or delete message(s).
This is the script's uber-function for CGI.
message-action-cgi
To decode CGI input from the web server:
cgi-input: retrieve-user-data
Using decoded CGI data, write XML standard message file to
directory determined by messageType.
create-message/from-cgi cgi-input
Using an e-mail message or newsgroup message in the form of a
REBOL e-mail object!, write XML standard message file to 'email' directory.
create-message/from-email email-message
Convert decoded CGI data into the standard message object!,
overwriting a previously created message.
edit-message cgi-input
Delete a previously created message.
delete-message cgi-input
Using decoded CGI data containing messageID and messageType
variables, either display a single message (messageID specified), a
directory of messages (messageID = "none"), or an index of messages
(messageID = "index") to the browser, including displaying the messageID
and messageType to the reader.
display-messages/for-reading/with-reference cgi-input
Using decoded CGI data containing messageID and messageType
variables, either display a single message (messageID specified), a
directory of messages (messageID = "none"), or an index of messages
(messageID = "index") to the browser, not displaying the messageID nor the
messageType to the reader.
display-messages/for-reading/without-reference cgi-input
Using decoded CGI data containing messageID and messageType
variables, either display a single message (messageID specified), a
directory of messages (messageID = "none"), or an index of messages
(messageID = "index") to the browser, including displaying the messageID
and messageType to the reader, in an HTML form for editing.
display-messages/for-editing/with-reference cgi-input
}
]
;########################################
;# FUNCTIONS #
;########################################
translate-message: make object! [
xml-tags: [
["subject" "/subject"]
["author" "/author"]
["date" "/date"]
["content" "/content"]
["messageID" "/messageID"]
["messageType" "/messageType"]
]
markup-data: func [
"Converts a standard message object! into a string containing the
XML-format standard message."
data [object!] "The standard message object!"
][
data-object: make data []
object-data: next first data-object
output: copy ""
for x 1 (length? xml-tags) 1 [
item: reform [rejoin ["data-object" "/" (first object-data)]]
made-tag: rejoin ["" (build-tag [(xml-tags/1/1)]) (do item)
(build-tag [(xml-tags/1/2)])]
xml-tags: next xml-tags
object-data: next object-data
append output made-tag
]
xml-tags: head xml-tags
output
]
read-markup: func [
"Converts a file containing the XML-format standard message into a
standard message object!"
xml-file [file!] "File containing the XML-format standard message."
][
message-data: load/markup xml-file
xml-data: make object! [
subject: message-data/<subject>
author: message-data/<author>
date: message-data/<date>
content: message-data/<content>
messageID: message-data/<messageID>
messageType: message-data/<messageType>
]
xml-data
]
]
decode-to-object: make object! [
from-cgi: func [
"Converts decoded CGI data into the standard message object!"
cgi-data [object!] "Decoded CGI data."
][
make object! [
subject: cgi-data/subject
author: cgi-data/author
date: now
content: cgi-data/content
messageID: time-in-digits now
messageType: cgi-data/messageType
]
]
edited-from-cgi: func [
"Converts decoded CGI data into the standard message object!"
cgi-data [object!] "Decoded CGI data."
][
make object! [
subject: cgi-data/subject
author: cgi-data/author
date: cgi-data/date
content: cgi-data/content
messageID: cgi-data/messageID
messageType: cgi-data/messageType
]
]
from-email: func [
"Converts the standard REBOL e-mail object! into the standard
message object!"
email-data [object!] "Standard REBOL e-mail object!"
][
make object! [
subject: email-data/subject
author: email-data/from
date: email-data/date
content: email-data/content
messageID: time-in-digits now
messageType: "email"
]
]
time-in-digits: func [
"Convert the date and time from 'now' into a string of digits."
sun-dial [date!] "The current date and time from 'now."
][
year: to-string sun-dial/year
month: to-string sun-dial/month
if (length? month) < 2 [insert month "0"]
day: to-string sun-dial/day
if (length? day) < 2 [insert day "0"]
current-time: sun-dial/time
hour: to-string current-time/hour
if (length? hour) < 2 [insert hour "0"]
minutes: to-string current-time/minute
if (length? minutes) < 2 [insert minutes "0"]
seconds: to-string current-time/second
if (length? seconds) < 2 [insert seconds "0"]
rejoin [year month day hour minutes seconds]
]
]
time-in-digits: func [
"Convert the date and time from 'now' into a string of digits."
sun-dial [date!] "The current date and time from 'now'"
][
year: to-string sun-dial/year
month: to-string sun-dial/month
if (length? month) < 2 [insert month "0"]
day: to-string sun-dial/day
if (length? day) < 2 [insert day "0"]
current-time: sun-dial/time
hour: to-string current-time/hour
if (length? hour) < 2 [insert hour "0"]
minutes: to-string current-time/minute
if (length? minutes) < 2 [insert minutes "0"]
seconds: to-string current-time/second
if (length? seconds) < 2 [insert seconds "0"]
rejoin [year month day hour minutes seconds]
]
retrieve-user-data: func [] [
return make object! decode-cgi
either system/options/cgi/request-method = "POST" [
input
][
system/options/cgi/query-string
]
]
write-xml-message: func [
"Write the XML-formatted standard message data with a file name
determined by messageID and to a directory determined by messageType."
xml-message-string [string!] "The XML-formatted standard message as it
resides in memory as a string! datatype."
][
message-data: load/markup xml-message-string
save-path: make file! (rejoin [message-data/<messageType> "/"
message-data/<messageID>])
write/binary save-path xml-message-string
]
read-message-directory: func [
"Read a directory of file names corresponding to a directory of
XML-formatted standard messages with the directory determined by
messageType."
message-request-data [object!] "The data from the request to view
messages, typically from an HTML form submitted to CGI."
][
message-directory: read (directory-name: make file! (rejoin
[message-request-data/messageType "/"]))
foreach message message-directory [
replace message message (make file! (rejoin
[message-request-data/messageType "/" message]))
]
message-directory
]
read-message: func [
"Read a specific XML-formatted standard message with the directory
determined by messageType and the file name determined by messageID."
message-request-data [object!] "The data from the request to view a
specific message, typically from an HTML form submitted to CGI."
][
message-directory: read (directory-name: make file! (rejoin
[message-request-data/messageType "/" message-request-data/messageID]))
]
read-directory-messages: func [
"Read a directory of XML-formatted standard messages with the directory
determined by messageType."
message-directory [block!] "A block of file names corresponding to a
directory of XML-formatted standard messages."
][
message-block: copy []
foreach file-name message-directory [
file-contents: read file-name
insert message-block file-contents
sort/reverse message-block
]
]
display-markup: make object! [
xml-values: ["subject" "author" "date" "content" "messageID"
messageType
]
css: func [
"Markup a standard message using standardized cascading style
sheets tags as the display markup."
xml-message-string [string!] "The XML-formatted standard message as
it resides in memory as a string! datatype."
][
css-markup: copy []
standard-message-data: load/markup xml-message-string
foreach value xml-values [
value-content: reform [rejoin ["standard-message-data" "/" "<"
(first xml-values) ">"]]
append css-markup (rejoin [{<div class="} value {">} (do
value-content) {</div>}])
xml-values: next xml-values
]
xml-values: head xml-values
css-markup: make string! css-markup
]
]
create-message: make object! [
from-cgi: func [
"Using decoded CGI data, writes XML standard message file to
directory determined by messageType."
cgi-input [object!] "Decoded CGI data as submitted from an HTML
form."
][
standard-message-object: decode-to-object/from-cgi cgi-input
xml-message-string: translate-message/markup-data
standard-message-object
write-xml-message xml-message-string
]
from-email: func [
"Using an e-mail message in the form of a REBOL e-mail obj
[2/3] from: sharriff:aina:med-iq at: 30-Mar-2001 6:25
Although I haveŽnt tried it out yet: "This rocks! way to go Ryan!" now I
might consider this or something like this over RSS or strange Java
Portal-Servlet solutions.
Cheers
Sharriff Aina
[3/3] from: ryan:christiansen:intellisol at: 30-Mar-2001 8:24
>Although I haveŽnt tried it out yet: "This rocks! way to go Ryan!"
>now I might consider this or something like this over RSS
>or strange Java Portal-Servlet solutions.
Thanks!
Plans for the future:
Online documentation.
Support for the mysql:// protocol (save messages in a database instead of
XML files)
Built-in search engine.
Customization: Some of the functions are built specifically to handle only
messages with subject, author, date, content, messageType, and messageID
values. I want to pull this out of the code so that you can create your own
values and plug them in using a configuration file, making it basically a
display and editing engine for any kind of data.
Ryan C. Christiansen
Web Developer
Intellisol International
4733 Amber Valley Parkway
Fargo, ND 58104
701-235-3390 ext. 6671
FAX: 701-235-9940
http://www.intellisol.com
Global Leader in People Performance Software
_____________________________________
Confidentiality Notice
This message may contain privileged and confidential information. If you
think, for any reason, that this message may have been addressed to you in
error, you must not disseminate, copy or take any action in reliance on it,
and we would ask you to notify us immediately by return email to
[ryan--christiansen--intellisol--com]