Laurel,

I recommend using google to search the mailing lists for questions like this 
also. There are times (like right now) when I have time to write this email but 
it's harder to make time to integrate this into the documentation.

Hiroki,

Learner data from all membership versions is saved in the SDS but there isn't 
yet a way to ask for just the data from session bundles for membership version 
3 of a workgroup. There could be ... but there isn't right now.

Right now researcher report data is based on ALL the valid session bundles for 
a workgroup and the reports don't specify the specific membership for each item 
of data.

So for example consider this scenario:

The membership for Workgroup "Oranges" starts with sail-users A, B, and C and 
this is followed with three learner sessions where three session bundles are 
created and delivered back to the SDS after which the membership is changed to 
C, D, and E and three more learner sessions occur.

The reports for researchers (right now) would list the membership of the 
workgroup as: C, D, and E but would include data from ALL six learner sessions 
(from sail-users A, B, C, D, and E). While it is not present in the current 
researcher reports the data to distinguish these differences is preserved.

All learner artifacts have directly or indirectly a foreign key pointing to the 
bundle they were extracted from. In addition the bundles all have a foreign key 
referring to the workgroup they relate to as well as an attribute specifying 
the workgroup membership version this bundle relates to.

This is implemented by including both the workgroup id and the workgroup 
membership version in the Bundle Poster URL delivered as a property in the 
config file to a SAIL to the SAIL EMF Classes managing learner data persistence 
for a client session. When the bundle is POSTed back the information in the url 
is used by the SDS to persist the bundle with the correct relationships to it's 
related resources.

Aaron,

Updating the SDS confluence doc is great. Please synch any changes you make 
there with this file: doc/sds_doc_confluence.txt checked into the SDS svn 
repository. Please feel free to copy relevant content from any of these 
messages to the documentation also ;-)

Laurel and Aaron,

Actually there is no way to fully delete a membership in a workgroup once it 
has been made however you probably should be able to make a new version of the 
membership consisting of 0 members. I implemented this capability but please 
read and test my CAVEAT about this below.

What appears to be deleting membership in the workgroup (on the web) is really 
just making a new membership version without some or all of the previous 
membership.

The reason for this implementation is based on the assumption that once someone 
is a member of a workgroup there could be learner data associated with that 
specific version of the membership and unless the whole workgroup is deleted 
(and all the associated data) the SDS will always keep track returned session 
bundles of learner data in relation to the workgroup membership in existence at 
the time the learner session was initiated. This is why workgroup membership is 
versioned.

I thought hard about this last August when I expanded the SDS from it's initial 
version tied to the original SAIL microportal. I kept getting stuck with this 
part of the domain until I realized that workgroup membership needs to be 
versioned.

Basically I implemented a policy that states you can only throw out everyone's 
data in a workgroup (by deleting it) you can't just through out a some member's 
data.

Aaron, There is some kind of initial fence post kind of issue with the version 
number when creating a new workgroup. It doesn't affect any functionality and I 
can't quite recall how it shows up but if you look at the code carefully and 
test it you'll see what I mean.

Exactly why the web version could make a new membership consisting of the empty 
set is not clear. I specifically designed it not to allow this.

*** New functionality added to the DEV SDS ***

1) I just added an optional version string to the url for workgroup membership. 
This works in both REST and web access methods. There is no UI exposed for this 
on the web other then manually suffixing "/<version-number>" onto the end of 
the url.

2) I also modified the workgroup controller so you can now use the REST API as 
Laurel wanted to set the workgroup membership to the empty set when creating a 
new versioned membership (see example further down).

*** CAVEAT ***

We should find out what happens when an offering is run for workgroup with no 
active members -- it may not be anything good! What does it mean to collect 
learner data for a workgroup with no members? The SDS only allows you to run a 
client session with a reference to a workgroup. Right now if makes no check to 
see if the membership is empty. It needs to have a rational policy for this 
case. It certainly makes no sense to save learner data in this situation. The 
SDS could automatically apply the property that tells the client not to allow 
saving of learner data when a session config file is generated for a workgroup 
with a membership consisting of the empty set. The SAIL EMF persistence code 
may or may not deal well with  no learners (it should be tested and checked) 
and the PAS VLE displays the names of the learners, what does it do when no 
learner names are available?

**************

Here's some testing that shows how versions work with these new features:

At the start the membership for workgroup 1354 is empty and it's at version 4:

$ curl -i -X GET -H 'Accept: application/xml' 
http://rails.dev.concord.org/sds/2/workgroup/1354/membership
HTTP/1.1 200 OK
Date: Sat, 26 May 2007 04:00:25 GMT
Server: lighttpd/1.4.11
Content-Type: application/xml
Cache-Control: no-cache
Content-Length: 87
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<workgroup-memberships></workgroup-memberships>

Here's the memberships sequencing through previous versions. Version 3 is still 
the empty set.

$ curl -i -X GET -H 'Accept: application/xml' 
http://rails.dev.concord.org/sds/2/workgroup/1354/membership/3
HTTP/1.1 200 OK
Date: Sat, 26 May 2007 04:00:32 GMT
Server: lighttpd/1.4.11
Content-Type: application/xml
Cache-Control: no-cache
Content-Length: 87
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<workgroup-memberships></workgroup-memberships>

But version 2 has two members:

$ curl -i -X GET -H 'Accept: application/xml' 
http://rails.dev.concord.org/sds/2/workgroup/1354/membership/2
HTTP/1.1 200 OK
Date: Sat, 26 May 2007 04:00:36 GMT
Server: lighttpd/1.4.11
Content-Type: application/xml
Cache-Control: no-cache
Content-Length: 266
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<workgroup-memberships>
  <workgroup-membership>
    <sail-user-id>5373</sail-user-id>
  </workgroup-membership>
  <workgroup-membership>
    <sail-user-id>5372</sail-user-id>
  </workgroup-membership>
</workgroup-memberships>

And version 1 once again has a membership consisting of the empty set.

$ curl -i -X GET -H 'Accept: application/xml' 
http://rails.dev.concord.org/sds/2/workgroup/1354/membership/1
HTTP/1.1 200 OK
Date: Sat, 26 May 2007 04:00:40 GMT
Server: lighttpd/1.4.11
Content-Type: application/xml
Cache-Control: no-cache
Content-Length: 87
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<workgroup-memberships></workgroup-memberships>

$ curl -i -X GET -H 'Accept: application/xml' 
http://rails.dev.concord.org/sds/2/workgroup/1354/membership/0
HTTP/1.1 200 OK
Date: Sat, 26 May 2007 04:00:47 GMT
Server: lighttpd/1.4.11
Content-Type: application/xml
Cache-Control: no-cache
Content-Length: 177
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<workgroup-memberships>
  <workgroup-membership>
    <sail-user-id>1945</sail-user-id>
  </workgroup-membership>
</workgroup-memberships>:

I added two members with the web interfaces and here's what it looks like now:

$ curl -i -X GET -H 'Accept: application/xml' 
http://rails.dev.concord.org/sds/2/workgroup/1354/membership
HTTP/1.1 200 OK
Date: Sat, 26 May 2007 04:43:07 GMT
Server: lighttpd/1.4.11
Content-Type: application/xml
Cache-Control: no-cache
Content-Length: 266
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<workgroup-memberships>
  <workgroup-membership>
    <sail-user-id>5373</sail-user-id>
  </workgroup-membership>
  <workgroup-membership>
    <sail-user-id>5372</sail-user-id>
  </workgroup-membership>
</workgroup-memberships>
[~/dev/rails/sds]$

OK, now delete them in the new version:

$ curl -i -H 'Content-Type: application/xml' -X POST -d 
'<workgroup-memberships></workgroup-memberships>' 
http://rails.dev.concord.org/sds/2/workgroup/1354/membership
HTTP/1.1 201 Created
Date: Sat, 26 May 2007 04:47:01 GMT
Server: lighttpd/1.4.11
Content-Type: application/xml
Location: http://rails.dev.concord.org/sds/2/workgroup/1354/membership
Cache-Control: no-cache
Content-Length: 0

And see what's there now:

[~/dev/rails/sds]$ curl -i -X GET -H 'Accept: application/xml' 
http://rails.dev.concord.org/sds/2/workgroup/1354/membership
HTTP/1.1 200 OK
Date: Sat, 26 May 2007 04:47:06 GMT
Server: lighttpd/1.4.11
Content-Type: application/xml
Cache-Control: no-cache
Content-Length: 87
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<workgroup-memberships></workgroup-memberships>

Looks good

----------------------------------------------------------------------

I wrote this in last September (so it's a bit out of date) but it might provide 
some useful background.

At 7:39 PM -0400 9/2/06, Stephen Bannasch wrote:
>A bit more possible useful info. This background might be helpful if you want 
>to look more at the ruby code before the documentation re-appears.
>
>The model files in this dir:
>
>  http://svn.rails.dev.concord.org/svn/sds/trunk/app/models/
>
>Have a great deal of easily read info about the relationships between the 
>objects and how they are setup in the database. This may give you insight into 
>what elements need to be included when you are creating sds resources.
>
>For example the workgroup model:
>
>  http://svn.rails.dev.concord.org/svn/sds/trunk/app/models/workgroup.rb
>
>Is defined like this:
>
>class Workgroup < ActiveRecord::Base
> 
>  set_table_name "sds_workgroups"
>
>  validates_presence_of :portal_id, :offering_id, :portal_token, :name
>  validates_uniqueness_of :portal_token, :scope => :portal_id
>
>  belongs_to :portal
>  belongs_to :offering
>  has_many :workgroup_memberships
>  has_many :users, :through => :workgroup_memberships do
>    def version(version)
>      find :all, :conditions => ['version = ?', version]
>    end
>  end
>  # this creates the following possible search
>  # members = workgroup.users.version(1)
>
>  before_create :generate_uuid
> 
>  def generate_uuid
>    self.uuid = UUID.timestamp_create().to_s
>  end
>
>  before_destroy :delete_workgroup_memberships
> 
>  def delete_workgroup_memberships
>    WorkgroupMembership.delete_all(["workgroup_id = ?", self.id])
>  end
> 
>  def self.find_all_in_portal(pid)
>    Workgroup.find(:all, :conditions => ["portal_id = ?", pid])
>  end
>
>end
>
>Ths is a domain-specific language created in classes that inherit from 
>ActiveRecord::Base. I do not need to specify any sql and this will work with a 
>number of different databases in assition to mysql.
>
>Each 'belongs_to' statement declares that a workgroup will be related to the 
>listed model. So in a workgroup record in the database there will be one field 
>for the specific portal realm and one for the offering this workgroup is for.  
>You will never need to specify the portal_id when you create a resource 
>because it is already specified in the url.
>
>The 'has_many :workgroup_memberships' statement declares that 
>workgroup_memberships will relate to a workgroup.
>
>The 'has_many :users, :through => :workgroup_memberships' statement declares 
>that workgroup_memberships will also act as a join table connecting workgroups 
>to users.
>
>Here's the schema definition for sds_workgroups:
>
>  create_table "sds_workgroups", :force => true do |t|
>    t.column "portal_id", :integer
>    t.column "offering_id", :integer
>    t.column "portal_token", :string, :default => "", :null => false
>    t.column "name", :string, :limit => 60, :default => "", :null => false
>    t.column "uuid", :string, :limit => 36, :default => "", :null => false
>    t.column "version", :integer, :default => 0, :null => false
>    t.column "created_at", :datetime
>    t.column "updated_at", :datetime
>  end
>
>So the 2 fields portal_id and offering_id are the foreign key references . 
>ActiveRecord uses a convention that field names ending in '_id' are foreign 
>key references to tables specified in the first part of the field name. The 
>field portal_id is specified in the url but you will need to specify the sds 
>offering_id when you create a workgroup. The two fields created_at and 
>updated_at are managed by rails and you will never specify them.
>
>In this model there is no obvious way to tell but you also do not specify uuid 
>or version. The uuid and the version are created by the sds when the workgroup 
>is created and the version is incremented everytime you specify a new 
>workgroup_membership. Right now the version is handled internally by the sds 
>and in it's communication with the PLR. However because he sds keeps track of 
>this it knows what group of users were responsible for specific data saved 
>into the total data saved by a workgroup. This could be used later by a 
>reporting system.
>
>Here's the schema definition for workgroup_memberships:
>
>  create_table "sds_workgroup_memberships", :force => true do |t|
>    t.column "user_id", :integer, :default => 0, :null => false
>    t.column "workgroup_id", :integer, :default => 0, :null => false
>    t.column "version", :integer, :default => 0, :null => false
>  end
>
>You can tell it's a join table with it's two foreign key references to users 
>and workrgoups, in addition each join record holds a the version attribute for 
>that specific relationship. This allows me to the following in ruby to get the 
>names of members of version 1 of workgroup 2 when running in an sds console 
>(interactive shell with all the classes and objects for the sds loaded):
>
>w = Workgroup.find(2)
>members = w.users.version(1)
>members.each { |m| puts m.name }
>
>produces:
>
>  Stephen Bannasch
>  Scott Cytacki
>  Grace Bannasch
>  John Smith




--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"SAIL-Dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/SAIL-Dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to