Showing 621 - 630 of 693 Postings (
summary)
Created by Jim Lynch, last modified by Jim Lynch 13 Jul 2012, at 12:35 AM
description/intro paragraph (this might as well be inline)
(all the rest are menu items, which probably open into submenu which has content)
getting started with git for openacs
git for openacs users
git for openacs coders and contributors
openacs release management using git
managing the repos
Created by Malte Sussdorff, last modified by Gustaf Neumann 03 Nov 2011, at 02:26 PM
I worked off the work of Dave Bauer and used Macports.
Unfortunately, the default configuration of Mac OS X does not allow suitable amounts of shared memory to be created to run the database server.
Therefore you should edit your /etc/sysctl.conf
On a MacBook Pro with 2GB of RAM, the author's sysctl.conf contains:
kern.sysv.shmmax=1610612736
kern.sysv.shmall=393216
kern.sysv.shmmin=1
kern.sysv.shmmni=32
kern.sysv.shmseg=8
kern.maxprocperuid=512
kern.maxproc=2048
Download and install MacPorts from http://www.macports.org/install.php and get the latest version (1.7.1 as of 2009-04-18)
Install PostgreSQL 8.4
sudo port -k install postgresql84
cd `port work postgresql84`/postgresql-8.4.7/contrib/ltree
make all
sudo make install
sudo port install postgresql84-server
This installs expat, gperf, libiconv, ncursesw, ncurses, gettext, m4, bison, zlib, libxml2, libxslt1, openssl, readline, postgresql82. The macports install then says
To create a database instance, after install do
sudo mkdir -p /opt/local/var/db/postgresql84/defaultdb
sudo chown postgres:postgres /opt/local/var/db/postgresql84/defaultdb
sudo su postgres -c '/opt/local/lib/postgresql84/bin/initdb -D /opt/local/var/db/postgresql84/defaultdb'
Then after initdb postgres says to start postgresql. Before that edit the config file to make it compatible with ACS
sudo emacs -nw /opt/local/var/db/postgresql84/defaultdb/postgresql.conf
Once you have emacs open, change the following config items:
autovacuum = on
add_missing_from = on
default_with_oids = on
regex_flavor = extended
Now start the PostgreSQL Server
sudo su postgres -c '/opt/local/lib/postgresql84/bin/postgres -D /opt/local/var/db/postgresql84/defaultdb' &
Install plpgsql as a language
/opt/local/lib/postgresql84/bin/createlang plpgsql template1 -U postgres
Last but not least, put postgresql under launchctl so you can start and stop it:
sudo launchctl load -w /Library/LaunchDaemons/org.macports.postgresql84-server.plist
To start it from then on just call
sudo launchctl start org.macports.postgresql84-server
To stop it:
sudo launchctl stop org.macports.postgresql84-server
Install AOLserver 4.5
sudo port install tcl +threads +headers
This will install Tcl with threads enabled, which is needed for AOLserver.
sudo port install aolserver
Now we have AOLserver installed into /opt/local/aolserver. You now need to configure the server to your needs. You might want to create another user (e.g. aolserver) to run the server. First get all the files:
cd /usr/local/src
mkdir aolserver
cd aolserver
TCLLIB=1.13
XOTCL=1.6.7
# Path for the AOLserver installation
NS=/opt/local/aolserver
cvs -z3 -d:pserver:anonymous@aolserver.cvs.sourceforge.net:/cvsroot/aolserver co nssha1
cvs -z3 -d:pserver:anonymous@aolserver.cvs.sourceforge.net:/cvsroot/aolserver co nspostgres
echo "Getting TDOM ..."
git clone git://github.com/tDOM/tdom.git
echo "Getting TCL modules ..."
curl -L -O http://downloads.sourceforge.net/tcllib/tcllib-${TCLLIB}.tar.bz2
curl -L -O http://downloads.sourceforge.net/tcl/thread2.6.5.tar.gz
curl -L -O http://media.wu-wien.ac.at/download/xotcl-${XOTCL}.tar.gz
Now install nssha1
cd nssha1
sudo make install NSHOME=${NS}
cd ..
Now go for nspostgres
cd nspostgres/
# Edit the Makefile so it reads (adding the "-lnsdb")
MODLIBS = -L$(PGLIB) -lpq -lnsdb
sudo make install AOLSERVER=/opt/local/aolserver/ PGCONFIG=/opt/local/lib/postgresql84/bin/pg_config POSTGRES=/opt/local PGINC=/opt/local/include/postgresql84/ PGLIB=/opt/local/lib/postgresql84/ ACS=1
cd ..
tDOM
cd tDOM-0.8.2/unix
../configure --mandir=/usr/local/share/man --libdir=/opt/local/aolserver/lib --with-tcl=/opt/local/lib --with-aolserver=/opt/local/aolserver
sudo make install
cd ../..
Thread
tar xvfz thread2.6.5.tar.gz
cd thread2.6.5/unix
../configure --mandir=/usr/local/share/man --libdir=/Library/Tcl --with-tcl=/System/Library/Frameworks/Tcl.framework --with-tclinclude=/System/Library/Frameworks/Tcl.framework/Headers --with-aolserver=/opt/local/aolserver
sudo make install
cd ../..
XOTcl
The private header files of Tcl are missing, therefore I got the source and recompiled Tcl:
curl -L -O http://downloads.sourceforge.net/tcl/tcl8.5.9-src.tar.gz
tar xfz tcl8.5.9-src.tar.gz
cd tcl8.5.9/unix
./configure --enable-threads --prefix=/opt/local --disable-corefoundation
sudo make install
cd ../..
tar xvfz xotcl-1.6.7.tar.gz
cd xotcl-1.6.7
NS=/opt/local/aolserver/
./configure --enable-threads --enable-symbols --prefix=${NS} --exec-prefix=${NS} --with-tcl=/opt/local/lib
sudo make install-aol
cd ..
Now we finish off with tcllib
tar xvfj tcllib-1.13.tar.bz2
cd tcllib-1.13
./configure --prefix=/opt/local/aolserver/
sudo make install
Type in terminal before starting nsd
ulimit -n 256
I would recommend to install the server in ~/Sites/
yourserver if you don't intend to run multiple different servers with access rights on your machine. Checkout the OpenACS code and Edit ~/Sites/
yourserver/etc/config.tcl and make the following changes
# Change the server root
set serverroot "~/Sites/${server}"
# Make sure that OpenACS finds PostgreSQL. Add two lines to the $database if statement
if { $database eq "oracle" } {
set db_password "mysitepassword"
} else {
set db_host localhost
set db_port ""
set db_user $server
ns_section "ns/db/driver/postgres"
ns_param pgbin /opt/local/lib/postgresql84/bin/
}
# Change the AOLserver location
set homedir /opt/local/aolserver
Now you can start up your server. First try ist with /opt/local/aolserver/bin/nsd -t ~/Sites/yourserver/etc/config.tcl. If this works you might want to create a launchctl entry as you did above for postgresql
Edit /Library/LaunchDaemons/org.openacs.YOURSERVER.plist and enter the following
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.openacs.YOURSERVER</string>
<key>OnDemand</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>/Users/youruser/Sites/yourserver/etc/daemontools/run</string>
</array>
<key>ServiceDescription</key>
<string>OpenACS Service</string>
<key>UserName</key>
<string>youruser</string>
<key>GroupName</key>
<string>staff</string>
</dict>
</plist>
Now put yourserver under launchctl so you can start and stop it:
sudo launchctl load -w /Library/LaunchDaemons/org.openacs.yourserver.plist
To start it from then on just call
sudo launchctl start org.openacs.yourserver
To stop it:
sudo launchctl stop org.openacs.yourserver
It is a good idea to schedule regular backups for your server(s). To do this create a shell script, e.g. backup.sh which executes your backups and then create a launchdaemon plist to run your backups nightly
Edit /Library/LaunchDaemons/org.openacs.backup.plist and enter the following
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.openacs.backup</string>
<key>ProgramArguments</key>
<array>
<string>/Users/youruser/Sites/backup.sh</string>
</array>
<key>LowPriorityIO</key>
<true/>
<key>Nice</key>
<integer>1</integer>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>15</integer>
</dict>
</dict>
</plist>
If you intend to run AOLserver on a continous basis remember that it is a great idea to make sure it responds properly. To do this you can run a keepalive service.
Edit /Library/LaunchDaemons/org.openacs.keepalive.plist and enter the following
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.openacs.keepalive.plist</string>
<key>ProgramArguments</key>
<array>
<string>/Users/youruser/Sites/keepalive.sh</string>
<string>yourserver</string>
<string>yourport</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>180</integer>
</dict>
</plist>
Your keepalive.sh could look like this
#!/bin/bash
GREP=/usr/bin/grep
HEAD="/usr/bin/head -1"
INSTANCE="$1";
PORT="$2"
[ -z "$1" ] && exit
[ -z "$2" ] && exit
MAIL_ADDR=""
WGET_FILE=/tmp/.output-keepalive-${INSTANCE}
URL_TEST="http://127.0.0.1:${PORT}/SYSTEM/dbtest"
[ -f ${WGET_FILE} ] && rm -f ${WGET_FILE}
_restartwebserver ()
{
/bin/launchctl start org.openacs.$INSTANCE
sleep 3
/bin/launchctl start org.openacs.$INSTANCE
}
_sendmail ()
{
echo "${1}" |mailx -s AolWebserver ${MAIL_ADDR}
}
while [ 1 -eq 1 ];
do
[ -f ${WGET_FILE} ] && /bin/rm -f ${WGET_FILE}
/usr/bin/curl -s -o $WGET_FILE --connect-timeout 3 --retry 3 "${URL_TEST}"
if [ -f ${WGET_FILE} ]
then
FIRST_LINE=`${HEAD} ${WGET_FILE} | ${GREP} -i "success"`
[ -z "${FIRST_LINE}" ] && _restartwebserver && _sendmail "I just restarted the $INSTANCE webserver on `uname -n`" && echo "`date +'%D-%H:%M'` :: FAILURE" || echo "`date +'%D-%H:%M'` :: success $INSTANCE" >>/Users/malte/Sites/keepalive.log
else
_restartwebserver && _sendmail "I just restarted the $INSTANCE webserver on `uname -n`"
# _restartwebserver
echo "`date +'%D-%H:%M'` :: FAILURE"
fi
done
If you intend to run AOLserver on a continous basis remember that it is a great idea to restart your server once per night, otherwise the memory footprint will grow and grow and grow.
Edit /Library/LaunchDaemons/org.openacs.restart.plist and enter the following
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.openacs.restart</string>
<key>OnDemand</key>
<false/>
<key>ProgramArguments</key>
<array>
<string>/Users/youruser/Sites/restart.sh</string>
</array>
<key>LowPriorityIO</key>
<true/>
<key>Nice</key>
<integer>1</integer>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>4</integer>
<key>Minute</key>
<integer>15</integer>
</dict>
</dict>
</plist>
Now put scripts under launchctl so they will run in the night:
sudo launchctl load -w /Library/LaunchDaemons/org.openacs.backup.plist
sudo launchctl load -w /Library/LaunchDaemons/org.openacs.restart.plist
sudo launchctl load -w /Library/LaunchDaemons/org.openacs.keepalive.plist
Your restart.sh could look like this
#!/bin/bash
echo "cognovis"
sudo launchctl stop org.openacs.yourserver
sleep 10
sudo launchctl start org.openacs.yourserver
Created by Jeff Davis, last modified by Jeff Davis 04 Nov 2010, at 03:22 PM
commits.png | image/png | 2010-11-04 15:22:29+01 | Jeff Davis | 4670500 |
Created by Jeff Davis, last modified by Jeff Davis 04 Nov 2010, at 03:20 PM
Commit graph
Created by Ryan Gallimore, last modified by Ryan Gallimore 10 Apr 2010, at 07:29 PM
To automatically install packages with specific parameters and mount points, create an install.xml file in your /path/to/service/ directory, according to:
Automated Install Thread
Created by OpenACS community, last modified by Ryan Gallimore 10 Apr 2010, at 06:49 PM
Testing with TCLWebtest
by Simon Carstensen and Joel Aufrecht
Tclwebtest is primarily for testing user interface and acceptance testing.
API testing is only part of testing your package - it doesn't test the
code in our adp/tcl pairs. For this, we can use TCLWebtest (see sourceforge). TCLWebtest provides a library of functions
(see command reference) that make it easy to call a page through HTTP, examine the results, and
drive forms. TCLwebtest's functions overlap slightly with
acs-automated-testing; see the example provided for one approach on
integrating them.
TCLWebtest
must be installed for to work. Since automated testing uses it, it should be part of every OpenACS installation. Note that TCLwebtest is installed automatically by Malte's install script.
Forum Posts:
Command Reference:
- http://tclwebtest.sourceforge.net/doc/api_public.html
Articles:
- Automated Testing Best Practices see: https://openacs.org/doc/automated-testing-best-practices.html
- testing packages for release en:Package_Testing_Process_
Tools:
- Webtest-Recorder Firefox extension (TwtR) see http://www.km.co.at/km/twtr This module is a plugin for Firefox. It is used to generate/edit a tclwebtest script which can be used later
for regression testing without the need of a browser. There is a
certain overlap of the application range between selenium and TwtR.
This plugin was developed by Åsmund Realfsen for regression/load
testing of the assessment module.
Here are some guidelines on how to write automated tests with TCLWebtest. It is a joy to work with automated testing once you get the hang of it. We will use the "myfirstpackage" as an example.
Create the directory that will contain the test
script and edit the script file. The directory location and file name are standards which are recognized by the automated testing package:
[$OPENACS_SERVICE_NAME www]$ mkdir /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/tcl/test
[$OPENACS_SERVICE_NAME www]$ cd /var/lib/aolserver/$OPENACS_SERVICE_NAME/packages/myfirstpackage/tcl/test
[$OPENACS_SERVICE_NAME test]$ emacs myfirstpackages-procs.tcl
Write the tests. This is obviously the big step :) The script should first call ad_library like any normal -procs.tcl file:
ad_library {
...
}
To create a test case you call
aa_register_case test_case_name..
Once you've created the test case you start writing the needed logic.
We'll use the tutorial package, "myfirstpackage," as an example.
Let's say you just wrote an API for adding and deleting notes in the
notes packages and wanted to test that. You'd probably want to write a
test that first creates a note, then verifies that it was inserted,
then perhaps deletes it again, and finally verifies that it is
gone.
Naturally this means you'll be adding a lot of bogus data to the
database, which you're not really interested in having there. To avoid
this I usually do two things. I always put all my test code inside a
call to aa_run_with_teardown which basically means that all the
inserts, deletes, and updates will be rolled back once the test has
been executed. A very useful feature. Instead of inserting bogus data
like: set name "Simon", I tend to generate a random script in order avoid inserting a value that's already in the database:
set name [ad_generate_random_string]
Here's how the test case looks so far:
aa_register_case mfp_basic_test {
My test
} {
aa_run_with_teardown \
-rollback \
-test_code {
}
}
Now look at the actual test code. That's the code that
goes inside -test_code {}. We want to implement test case API-001, "Given an object id from API-001, invoke mfp::note::get. Proc should return the specific word in the title."
set name [ad_generate_random_string]
set new_id [mfp::note::add -title $name]
aa_true "Note add succeeded" [exists_and_not_null new_id]
To test our simple case, we must load the test file into the system (just as with the /tcl file in the basic tutorial, since the file didn't exist when the system started, the system doesn't know about it.) To make this file take effect, go to the APM and choose "Reload changed" for "MyFirstPackage". Since we'll be changing it frequently, select "watch this file" on the next page. This will cause the system to check this file every time any page is requested, which is bad for production systems but convenient for developing. We can also add some aa_register_case flags to make it easier to run the test. The -procs flag, which indicates which procs are tested by this test case, makes it easier to find procs in your package that aren't tested at all. The -cats flag, setting categories, makes it easier to control which tests to run. The smoke test setting means that this is a basic test case that can and should be run any time you are doing any test. (a definition of "smoke test")
Once the file is loaded, go to ACS Automated Testing and click on myfirstpackage. You should see your test case. Run it and examine the results.
Example
Now we can add the rest of the API tests, including a test with deliberately bad data. The complete test looks like:
ad_library {
Test cases for my first package.
}
aa_register_case \
-cats {smoke api} \
-procs {mfp::note::add mfp::note::get mfp::note::delete} \
mfp_basic_test \
{
A simple test that adds, retrieves, and deletes a record.
} {
aa_run_with_teardown \
-rollback \
-test_code {
set name [ad_generate_random_string]
set new_id [mfp::note::add -title $name]
aa_true "Note add succeeded" [exists_and_not_null new_id]
mfp::note::get -item_id $new_id -array note_array
aa_true "Note contains correct title" [string equal $note_array(title) $name]
mfp::note::delete -item_id $new_id
set get_again [catch {mfp::note::get -item_id $new_id -array note_array}]
aa_false "After deleting a note, retrieving it fails" [expr $get_again == 0]
}
}
aa_register_case \
-cats {api} \
-procs {mfp::note::add mfp::note::get mfp::note::delete} \
mfp_bad_data_test \
{
A simple test that adds, retrieves, and deletes a record, using some tricky data.
} {
aa_run_with_teardown \
-rollback \
-test_code {
set name {-Bad [BAD] \077 { $Bad}}
append name [ad_generate_random_string]
set new_id [mfp::note::add -title $name]
aa_true "Note add succeeded" [exists_and_not_null new_id]
mfp::note::get -item_id $new_id -array note_array
aa_true "Note contains correct title" [string equal $note_array(title) $name]
aa_log "Title is $name"
mfp::note::delete -item_id $new_id
set get_again [catch {mfp::note::get -item_id $new_id -array note_array}]
aa_false "After deleting a note, retrieving it fails" [expr $get_again == 0]
}
}
aa_register_case \
-cats {web smoke} \
-libraries tclwebtest \
mfp_web_basic_test \
{
A simple tclwebtest test case for the tutorial demo package.
@author Peter Marklund
} {
# we need to get a user_id here so that it's available throughout
# this proc
set user_id [db_nextval acs_object_id_seq]
set note_title [ad_generate_random_string]
# NOTE: Never use the aa_run_with_teardown with the rollback switch
# when running Tclwebtest tests since this will put the test code in
# a transaction and changes won't be visible across HTTP requests.
aa_run_with_teardown -test_code {
#-------------------------------------------------------------
# Login
#-------------------------------------------------------------
# Make a site-wide admin user for this test
# We use an admin to avoid permission issues
array set user_info [twt::user::create -admin -user_id $user_id]
# Login the user
twt::user::login $user_info(email) $user_info(password)
#-------------------------------------------------------------
# New Note
#-------------------------------------------------------------
# Request note-edit page
set package_uri [apm_package_url_from_key myfirstpackage]
set edit_uri "${package_uri}note-edit"
aa_log "[twt::server_url]$edit_uri"
twt::do_request "[twt::server_url]$edit_uri"
# Submit a new note
tclwebtest::form find ~n note
tclwebtest::field find ~n title
tclwebtest::field fill $note_title
tclwebtest::form submit
#-------------------------------------------------------------
# Retrieve note
#-------------------------------------------------------------
# Request index page and verify that note is in listing
tclwebtest::do_request $package_uri
aa_true "New note with title \"$note_title\" is found in index page" \
[string match "*${note_title}*" [tclwebtest::response body]]
#-------------------------------------------------------------
# Delete Note
#-------------------------------------------------------------
# Delete all notes
# Three options to delete the note
# 1) go directly to the database to get the id
# 2) require an API function that takes name and returns ID
# 3) screen-scrape for the ID
# all options are problematic. We'll do #1 in this example:
set note_id [db_string get_note_id_from_name "
select item_id
from cr_items
where name = :note_title
and content_type = 'mfp_note'
" -default 0]
aa_log "Deleting note with id $note_id"
set delete_uri "${package_uri}note-delete?item_id=${note_id}"
twt::do_request $delete_uri
# Request index page and verify that note is in listing
tclwebtest::do_request $package_uri
aa_true "Note with title \"$note_title\" is not found in index page after deletion." \
![string match "*${note_title}*" [tclwebtest::response body]]
} -teardown_code {
twt::user::delete -user_id $user_id
}
}
Created by Alvaro Rodriguez, last modified by Alvaro Rodriguez 10 Mar 2010, at 04:41 AM
Next Meeting: 2010-03-10 18:00 CET/CEST Convert to your local time
Agenda
Previous Meetings
- September 23, 2009
- September 15, 2009
- July 14, 2009
- July 07, 2009
- June 30, 2009
- June 23, 2009
- June 16, 2009
- June 09, 2009
- June 02, 2009
- May 26, 2009
- May 19, 2009
- May 12, 2009
- May 05, 2009
- April 28, 2009
- April 21, 2009
- April 14, 2009
- April, 07, 2009
- March 31, 2009
- March 24, 2009
- March 17, 2009
- March 10, 2009
- March 03, 2009
- February 24, 2009
- February 17, 2009
- February 10, 2009
- February 03, 2009
- January 27, 2009
- January 20, 2009
- January 13, 2009
- January 06, 2009
2008
- December 30, 2008
- December 23, 2008
- December 16, 2008
- December 09, 2008
- December 02, 2008
- November 25, 2008
- November 18, 2008
- November 11, 2008
- November 04, 2008
- October 28, 2008
- October 21, 2008
- October 14, 2008
- October 7, 2008
- September 30, 2008
- September 23, 2008
- September 16, 2008
- September 09, 2008
- September 02, 2008
- August 26, 2008
- August 19, 2008
- August 12, 2008
- August 05, 2008
- July 29, 2008
- July 22, 2008
- July 15, 2008
- July 08, 2008
Created by Michael Steigman, last modified by Michael Steigman 09 Dec 2009, at 06:09 PM
What can we provide now?
* WIKI
new pages this week
average: new pages per month
page edits this week
average: page edits per month
average: editors per page
* FORUMS
new threads this week
posts this week
average: new threads per month
average: posts per month
average: forum notification subscriptions per month
ratio: posts per thread (monthly?)
example queries:
hub=# select to_char(r.publish_date, 'YYYY-MM') as month, count(*) from cr_items i join cr_revisions r on (i.item_id = r.item_id) where parent_id = '2239905' group by month order by month desc;
month | count
---------+-------
2009-10 | 123
2009-09 | 394
2009-08 | 410
2009-07 | 671
2009-06 | 158
2009-05 | 4
2009-03 | 8
2009-01 | 4
2008-12 | 56
(9 rows)
hub=# select to_char(o.creation_date, 'YYYY-MM') as month, count(*) from cr_items i join acs_objects o on (i.item_id = o.object_id) where parent_id = '2239905' group by month order by month desc;
month | count
---------+-------
2009-10 | 2
2009-09 | 31
2009-08 | 38
2009-07 | 71
2009-06 | 39
2009-05 | 2
2009-03 | 4
2009-01 | 1
2008-12 | 12
(9 rows)
hub=# select max(count) from (select count(distinct creation_user) as count from cr_items i join cr_revisions r on (i.item_id = r.item_id) join acs_object\
s o on (o.context_id = r.item_id) where parent_id = '2239905' group by i.item_id) a;
max
-----
7
(1 row)
hub=# select avg(count) from (select count(distinct creation_user) as count from cr_items i join cr_revisions r on (i.item_id = r.item_id) join acs_object\
s o on (o.context_id = r.item_id) where parent_id = '2239905' group by i.item_id) a;
avg
--------------------
1.4900000000000000
(1 row)
hub=# select count(distinct creation_user), i.item_id from cr_items i join cr_revisions r on (i.item_id = r.item_id) join acs_objects o on (o.context_id =\
r.item_id) where parent_id = '2239905' group by i.item_id;
count | item_id
-------+---------
2 | 2239907
1 | 2240099
1 | 2240101
2 | 2240276
1 | 2240751
1 | 2240763
1 | 2240769
7 | 2240772
1 | 2248445
1 | 2249069
1 | 2249119
1 | 2249149
...
2 | 2714595
1 | 2716420
1 | 2721530
1 | 2722191
2 | 2724344
1 | 2731842
1 | 2752093
(200 rows)
What could we provide in the future?
average: # new/departed group members per day/month/year
average: visit length of group members
2 day answer rate for new threads
average: uploads/downloads per month
average: first answer time for threads
ratio: page view per post (lurk)
etc.
Created by Dave Bauer, last modified by Dave Bauer 02 Nov 2009, at 09:00 PM
Spec for File Management Overhaul on Hub
Michael Steigman (09/25/09) Updated 11/2/2009
User interface mockups
Big Picture
File management in OpenACS is a complicated affair at the moment. There are
several ways to upload and link to files and this has led to duplicate files, broken links
throughout content blocks and “embedded” files in rich text that are difficult to manage
(among many other issues). We are aiming to unify the file upload, linking and
management model and UI across the site, in order to make it simple to upload, update,
share, reference and delete files.
Organization of Files
To help users in a community or on a site collaborate, weʼd like to allow them to
organize and view files in ways that are intuitive. Taking from OS X, Google, Zoho, Windows et.
al., we envision a series of organizational areas in the files UI corresponding to different
filtering criteria.
Places - within a community, default “places” will include all applications and any other
subfolders the admin wishes to include. All users will see these places.
Views - the views area will include some basic views which should cover a lot of
scenarios (search for in OS Xʼs finder) and will expand with custom views created and
saved on the advanced tab.
Favorites (or bookmarks?) - this organizational area will display folders and files in the
personal file area which the user has marked as interesting anywhere on the site.
Shared - implied by the title, this area shows up in the personal file space and shows
files shared by and to you.
Upload and Linking Mechanisms
We want to allow users to link to/attach/upload files to any type of content and present a
consistent UI when doing this. The easiest way to do this would be to provide the same
interface users normally browse by, as OS X does. The WYSIWYG editor will have to
replicate this environment in a plugin setting. Apps that donʼt use the richtext widget
should be able to “include” a version of the browsing interface that allows for single (and
multiple?) file selection.
Much like hard links in Unix, we envision multiple links to each files. The links should be
viewable at the fileʼs canonical location (visible in the mockups). When no more links to
a file exist, the file can be deleted (think callbacks on link removal). Storing a checksum
for the file upon upload so that we can determine if it already exists within the
community would be beneficial.
Metadata Requirements
We need to be able to map from link to destination file. Within this link, we need to
capture some information - the object weʼre linking from being the primary bit of
information. If this link were to be an instance of a dedicated object type, it could also be
permissioned (i.e., a proxy). It could also point to a particular revision, which would
enable a learning module to point at a stable revision and prevent teaching material
from moving beneath a module author. These do not need to be part of the initial
implementation but should be considered.
Navigation and Page Requirements
We should provide an generic overview page (detailed in the mockups) that describes
the files attached to a piece of content. We need to be able to generate navigation for
content such as wiki pages or forum posts that include a link to the overview page if files
are attached. We also need a single, permanent page to display information about a file (File View in the
mockups).
Shared Folders
Referece Google Docs Shared Folders Feature http://docs.google.com/support/bin/answer.py?hl=en&answer=158074
Reference Zoho Document Management http://www.zoho.com/online-document-management/share-documents-collaborate.html
Use Cases
Upload File From Subsite/Group Files tab
User clicks "Add File" link or button from "Subsite->Files" page.
User sees upload dialog and chooses a file from their computer to upload.
File is added to subsite default folder.
Creation_user is the uploading user.
Parent_id is the default folder for the subsite.
Permissions are inherited from context_id, all members of subsite can view this file.
Context_id is the default folder for the subsite.
Upload file as attachment to Forums Message (or wiki page, etc.)
(note forums post workflow is not addressed)
User chooses to attach a file to a forum message.
User sees upload dialog and chooses a file from their computer to upload.
File is added to subsite default folder.
Creation_user is the uploading user.
Parent_id is the related object, ie: forum_message
Permissions are inherited from context_id, all members who can see the forum post can see the attached file.
Context_id is the parent_id.
Attach existing file from subsite folder as attachment to Forums Message (or wiki page, etc.)
User chooses to attach a file to a forum message.
User sees file chooser dialog (embedded filter view of subsite files).
User chooses existing file.
Acs_data_link created between forums_message and the uploaded file.
Upload file to personal folder
User browsers to their "workspace" (blah) and chooses Files.
This shows the My Files view.
User chooses Add File.
File is added to user default folder (child of user object).
Parent_id is the user default folder.
Context_id is the parent_id.
Permissions are inherited from the context_id.
Noone else can see or manage these files except the user.
Attach Existing file from personal folder to a forums message etc.
User chooses to attach file to a forums message.
User sees file chooser dialog (embedded filter view of subsite files).
Somehow the user chooses to list My Files and sees a list of all files this user has created.
Use chooses file from personal folder.
User sees message that they will share this file with the group/subsite/community with a checkbox to acknowlege.
A cr_symlink is created (this is the manifestation of "share" in this case.) in the subsite default folder.
Acs_data_link created between symlink and the forums message.
Permissions, parent_id, context_id of original file do not change!
Parent_id of symlink is default folder.
Context_id of symlink is parent_id.
Permissions
are inherited from context_id, all members of the subsite can view the
symlink (which resolves to the file) as long as it is being shared (the
symlink exists.)
View subsite files
User sees a list of files in the subsite folder or any subfolders, that they have permission to see (by default all of them.)
Shows filename/title, description, updated date/time, tags, creation user???
User
sees list of Places (packages in the subsite.) Each place filters files
that have acs_data_link to objects owned by that package.
User can
search filenames(titles/descriptions/tags) using the Search Within
feature. Just like google docs. Does not search file contents??
Clicking on a file name opens it but there should be an obvious place to view file information (permissions, revisions, links)
Clicking on a folder shows files/folders in that folder.
User can sort by name or date (asc/desc options, perhaps arrow next to name/date sort option?)
What do we do with pagination? How does search/sort affect pagination?
Experimental!! Sharing a Folder
User creates a folder or chooses an existing folder to share.
Symlink is created in group or target users folders to the shared folder depending on sharing level.
Permissions are granted on the ORIGINAL folder based on the sharing settings.
NOTE:
how do we do this without screwing something up? That is the sharers
are not allowed to DELETE or ADMIN the original folder. But we want to
simplify dealing with the items IN that folder.
Created by Hector Amado, last modified by Hector Amado 07 Oct 2009, at 11:34 PM
Educational Wiki (Eduwiki)
Description
The Educational Wiki (Eduwiki) Package is a Wiki tool based on xowiki, Eduwiki aims to be a simple tool for Wiki pages creation in the educational context.
This package lets the teacher to easily define Eduwiki Activities, there are three Eduwiki Types activities: Teacher Wiki, Group Wiki and Student Wiki.
Teacher Wiki activity is a single Wiki Activity managed by the Teacher, Teacher may set permissions to the students to read and write Wiki pages.
Group Wiki activity creates a Wiki per Group, Teacher may set permissions to read and write Wiki pages by other groups members.
Student Wiki type creates individual Wiki pages per student, each student can edit an create Wiki pages, teacher may set permissions to the rest of students to view and edit student Wiki pages.
How to Install
Eduwiki package works on: Postgresql 8.2.x+
Requires:
dotlrn 2.4.1
xowiki 0.116
xotcl-core 0.106
ajaxhelper 0.87d
Installation process:
1. Get the following packages from HEAD: eduwiki, eduwiki-portlet, dotlrn-eduwiki
2. Save packages to packages dir in your .LRN installation
3. Browse to Package Manager to install new packages (eduwiki, eduwiki-portlet, dotlrn-eduwiki)
4. Restart the server
5. Activate the applet in a course
Release Notes
Name: Educational Wiki (eduwiki)
Version: 0.1d3 (July 2009)
Developed by: Hector Amado (Galileo University)
Designed by: Rocael Hernández, Byron Linares (Galileo University)
Requirements by: Daniel Contreras, Rocael Hernández (Galileo University)
Provides a simple interface to create Wiki Activities, Teacher may set permissions to read, write and create Wiki Pages.
Provides a simple interface to create Wiki Pages (a no-brainer 1 click), and easily include and manipulate web assets such as flash, videos, images, etc.
The package is an OO extension of xowiki, leaves xowiki package unmodified, is based in XOWiki, since it is a very well maintained tool, and have many of the desired features such as: easy content tool (plus the advantage that a wiki tools is becoming more and more common), directories, versioning, basic template management, variables, multi-language support.
It provides portlets for .LRN
Technical specs
The Educational Wiki (eduwiki) Package is an OO extension of xowiki. It's based on Policy ::xowiki::policy3, to set permissions per pages.
A new proc was created to manage Eduwiki Activities, eduwiki::set_eduwiki_permissions, this proc set permissions to new pages based
on the activity definition.
To-Do
Start and end date editing functionality
Integration with evaluation package