Index: openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-packages-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-packages-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-packages-create.sql 20 Mar 2004 11:04:38 -0000 1.1 @@ -0,0 +1,405 @@ +-- +-- Postgresql packages for the News Aggregator package +-- +-- @author Simon Carstensen (simon@bcuni.net) +-- @creation-date 2003-06-26 + + +---------------- +-- +-- Aggregators +-- +---------------- + +create or replace function na_aggregator__new ( + integer, -- aggregator_id + varchar, -- aggregator_name + varchar, -- description + integer, -- package_id + boolean, -- public_p + integer, -- creation_user + varchar -- creation_ip +) returns integer as ' +declare + p_aggregator_id alias for $1; + p_aggregator_name alias for $2; + p_description alias for $3; + p_package_id alias for $4; + p_public_p alias for $5; + p_creation_user alias for $6; + p_creation_ip alias for $7; + v_aggregator_id integer; + v_max_item_id integer; +begin + v_aggregator_id := acs_object__new ( + p_aggregator_id, + ''na_aggregator'', + current_timestamp, + p_creation_user, + p_creation_ip, + p_package_id + ); + + select max(item_id) into v_max_item_id + from na_items; + + insert into na_aggregators ( + aggregator_id, + aggregator_name, + description, + maintainer_id, + package_id, + public_p, + aggregator_bottom + ) values ( + v_aggregator_id, + p_aggregator_name, + p_description, + p_creation_user, + p_package_id, + p_public_p, + v_max_item_id + ); + + PERFORM acs_permission__grant_permission( + v_aggregator_id, + p_creation_user, + ''admin'' + ); + + return v_aggregator_id; + +end;' language 'plpgsql'; + + +create or replace function na_aggregator__delete ( + integer -- aggregator_id +) +returns integer as ' +declare + p_aggregator_id alias for $1; +begin + + delete from acs_permissions + where object_id = p_aggregator_id; + + delete from na_subscriptions + where aggregator_id = p_aggregator_id; + + update na_user_preferences + set default_aggregator = null + where default_aggregator = p_aggregator_id; + + delete from na_purges + where aggregator_id = p_aggregator_id; + + delete from na_saved_items + where aggregator_id = p_aggregator_id; + + delete from na_aggregators + where aggregator_id = p_aggregator_id; + + PERFORM acs_object__delete(p_aggregator_id); + + return 0; + +end;' language 'plpgsql'; + + +create or replace function na_aggregator__name (integer) +returns varchar as ' +declare + p_aggregator_id alias for $1; + v_aggregator_name na_aggregators.aggregator_name%TYPE; +begin + select aggregator_name + into v_aggregator_name + from na_aggregators + where aggregator_id = p_aggregator_id; + + return v_aggregator_name; + +end;' language 'plpgsql'; + + +---------------- +-- +-- Sources +-- +---------------- + +create or replace function na_source__new ( + integer, -- source_id + varchar, -- feed_url + varchar, -- link + varchar, -- title + varchar, -- description + varchar, -- last_modified + boolean, -- listed_p + integer, -- package_id + integer, -- creation_user + varchar -- creation_ip +) returns integer as ' +declare + p_source_id alias for $1; + p_feed_url alias for $2; + p_link alias for $3; + p_title alias for $4; + p_description alias for $5; + p_last_modified alias for $6; + p_listed_p alias for $7; + p_package_id alias for $8; + p_creation_user alias for $9; + p_creation_ip alias for $10; + v_source_id integer; +begin + v_source_id := acs_object__new ( + p_source_id, + ''na_source'', + current_timestamp, + p_creation_user, + p_creation_ip, + p_package_id + ); + + insert into na_sources ( + source_id, + feed_url, + link, + title, + description, + last_scanned, + last_modified, + listed_p + ) values ( + v_source_id, + p_feed_url, + p_link, + p_title, + p_description, + current_timestamp, + p_last_modified, + p_listed_p + ); + + PERFORM acs_permission__grant_permission( + v_source_id, + p_creation_user, + ''admin'' + ); + + return v_source_id; + +end;' language 'plpgsql'; + + +create or replace function na_source__delete ( + integer -- source_id +) +returns integer as ' +declare + p_source_id alias for $1; +begin + + delete from acs_permissions + where object_id = p_source_id; + + delete from na_purges + where (top in (select item_id + from na_items + where source_id = p_source_id) + or bottom in (select item_id + from na_items + where source_id = p_source_id)); + + delete from na_items + where source_id = p_source_id; + + delete from na_subscriptions + where source_id = p_source_id; + + delete from na_sources + where source_id = p_source_id; + + PERFORM acs_object__delete(p_source_id); + + return 0; + +end;' language 'plpgsql'; + + +create or replace function na_source__name (integer) +returns varchar as ' +declare + p_source_id alias for $1; + v_source_name na_sources.title%TYPE; +begin + select title + into v_source_name + from na_sources + where source_id = p_source_id; + + return v_source_name; +end; +' language 'plpgsql'; + + +---------------- +-- +-- Items +-- +---------------- + +create or replace function na_item__new ( + integer, -- source_id + varchar, -- link + varchar, -- guid + varchar, -- original_guid + boolean, -- permalink_p + varchar, -- title + varchar, -- description, + varchar -- content_encoded +) returns integer as ' +declare + p_source_id alias for $1; + p_link alias for $2; + p_guid alias for $3; + p_original_guid alias for $4; + p_permalink_p alias for $5; + p_title alias for $6; + p_description alias for $7; + p_content_encoded alias for $8; +begin + + insert into na_items ( + source_id, + link, + guid, + original_guid, + permalink_p, + title, + description, + content_encoded, + creation_date + ) values ( + p_source_id, + p_link, + p_guid, + p_original_guid, + p_permalink_p, + p_title, + p_description, + p_content_encoded, + current_timestamp + ); + + return 1; + +end;' language 'plpgsql'; + + +---------------- +-- +-- Subscriptions +-- +---------------- + +create or replace function na_subscription__new ( + integer, -- aggregator_id + integer, -- source_id + timestamptz -- creation_date +) returns integer as ' +declare + p_aggregtor_id alias for $1; + p_source_id alias for $2; + p_creation_date alias for $3; +begin + + insert into na_subscriptions ( + aggregator_id, + source_id, + creation_date + ) values ( + p_aggregator_id, + p_source_id, + p_creation_date + ); + + return 1; + +end;' language 'plpgsql'; + +create or replace function na_weblog__name (integer) +returns varchar as ' +declare + p_weblog_id alias for $1; + v_name varchar; +begin + select weblog_name into v_name + from na_weblogs + where weblog_id = p_weblog_id; + return v_name; +end; +' language 'plpgsql'; + +create or replace function na_weblog__new ( + integer, -- weblog_id + integer, -- package_id + varchar, -- blog_type + varchar, -- weblog_name + varchar, -- base_url + integer, -- creation_user + varchar -- creation_ip +) returns integer as ' +declare + p_weblog_id alias for $1; + p_package_id alias for $2; + p_blog_type alias for $3; + p_weblog_name alias for $4; + p_base_url alias for $5; + p_creation_user alias for $6; + p_creation_ip alias for $7; + v_weblog_id integer; +begin + v_weblog_id := acs_object__new ( + p_weblog_id, + ''na_weblog'', + current_timestamp, + p_creation_user, + p_creation_ip, + p_package_id + ); + + insert into na_weblogs ( + weblog_id, + package_id, + blog_type, + weblog_name, + base_url, + user_id + ) values ( + v_weblog_id, + p_package_id, + p_blog_type, + p_weblog_name, + p_base_url, + p_creation_user + ); + + return v_weblog_id; +end; +' language 'plpgsql'; + +create or replace function na_weblog__delete (integer) +returns integer as ' +declare + p_weblog_id alias for $1; +begin + delete from na_weblogs + where weblog_id = p_weblog_id; + + PERFORM acs_object__delete(p_weblog_id); + return 0; +end; +' language 'plpgsql'; + Index: openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-packages-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-packages-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-packages-drop.sql 20 Mar 2004 11:04:38 -0000 1.1 @@ -0,0 +1,82 @@ +-- Drop script for the News Aggregator application +-- @author Simon Carstensen (simon@bcuni.net) +-- @creation-date 2003-05-21 + + +-- drop functions associated with weblogs +drop function na_weblog__delete(integer); +drop function na_weblog__name(integer); +drop function na_weblog__new(integer, integer, varchar, varchar, varchar, integer, varchar); +seledct acs_object_type__drop_type('na_weblog', true); + +--drop na_subscription functions +drop function na_subscription__new ( + integer, -- aggregator_id + integer, -- source_id + timestamptz -- creation_date +); + +--drop na_item functions +drop function na_item__new ( + integer, -- source_id + varchar, -- link + varchar, -- guid + varchar, -- original_guid + boolean, -- permalink_p + varchar, -- title + varchar, -- description, + varchar -- content_encoded +); + +--drop na_source functions +drop function na_source__name( + integer -- source_id +); + +drop function na_source__delete( + integer -- source_id +); + +drop function na_source__new( + integer, -- source_id + varchar, -- feed_url + varchar, -- link + varchar, -- title + varchar, -- description + varchar, -- last_modified + boolean, -- listed_p + integer, -- package_id + integer, -- creation_user + varchar -- creation_ip +); + +delete +from acs_permissions +where object_id in (select object_id + from acs_objects + where object_type = 'na_source'); + +--drop na_aggregator functions +drop function na_aggregator__name ( + integer -- aggregator_id +); + +drop function na_aggregator__delete ( + integer -- aggregator_id +); + +drop function na_aggregator__new ( + integer, -- aggregator_id + varchar, -- aggregator_name + varchar, -- description + integer, -- package_id + boolean, -- public_p + integer, -- creation_user + varchar -- creation_ip +); + +delete +from acs_permissions +where object_id in (select object_id + from acs_objects + where object_type = 'na_aggregator'); Index: openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-tables-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-tables-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-tables-create.sql 20 Mar 2004 11:04:38 -0000 1.1 @@ -0,0 +1,277 @@ +-- PostgreSQL tables for the News Aggregator package +-- +-- @author Simon Carstensen (simon@bcuni.net) +-- @creation-date 2003-06-26 + + +---------------- +-- +-- Aggregators +-- +---------------- + +create table na_aggregators ( + aggregator_id integer + constraint na_aggregators_pk + primary key + constraint na_aggregators_aid_fk + references acs_objects(object_id) + on delete cascade, + aggregator_name varchar(100) + constraint na_aggregators_name_nn + not null, + description text, + package_id integer + constraint na_aggregators_pid_fk + references apm_packages(package_id) + constraint na_aggregators_pid_nn + not null, + maintainer_id integer + constraint na_aggregators_mid_fk + references users(user_id) + constraint na_aggregators_mid_nn + not null, + public_p boolean default true, + number_shown integer + default '100', + aggregator_bottom integer +); + + +select acs_object_type__create_type ( + 'na_aggregator', -- object_type + 'Aggregator', -- pretty_name + 'Aggregators', -- pretty_plural + 'acs_object', -- supertype + 'na_aggregators', -- table_name + 'aggregator_id', -- id_column + null, -- package_name + 'f', -- abstract_p + null, -- type_extension_table + 'na_aggregator.name' -- name_method +); + + +---------------- +-- +-- Sources +-- +---------------- + +create table na_sources ( + source_id integer + constraint na_sources_pk + primary key + constraint na_sources_sid_fk + references acs_objects(object_id) + on delete cascade, + feed_url varchar(500) + constraint na_sources_fu_nn + not null, + link varchar(500), + title varchar(500), + description varchar(500), + updates integer + default '0', + last_scanned timestamptz + default current_timestamp, + last_modified varchar(100), + last_modified_stamp timestamptz, + last_scan_ok_p boolean default true, + stacktrace text, + rss_source text, + listed_p boolean default true +); + + +select acs_object_type__create_type ( + 'na_source', -- object_type + 'Sources', -- pretty_name + 'Sources', -- pretty_plural + 'acs_object', -- supertype + 'na_sources', -- table_name + 'source_id', -- id_column + null, -- package_name + 'f', -- abstract_p + null, -- type_extension_table + 'na_source.name' -- name_method +); + + +---------------- +-- +-- Items +-- +---------------- + +create table na_items ( + item_id integer + default nextval('na_items_item_id_seq') + constraint na_items_pk + primary key, + source_id integer + constraint na_items_sid_fk + references na_sources(source_id) + constraint na_items_sid_nn + not null, + link varchar(500), + guid varchar(500), + original_guid varchar(500), + permalink_p boolean + default true, + title varchar(500), + description text, + content_encoded text, + creation_date timestamptz + default current_timestamp +); + +create sequence na_items_item_id_seq cache 1; +create index na_items_guid_idx on na_items(guid); +create index na_items_source_id_idx on na_items(source_id); + +create table na_saved_items ( + item_id integer + constraint na_saved_items_iid_fk + references na_items(item_id), + aggregator_id integer + constraint na_saved_items_aid_fk + references na_aggregators(aggregator_id), + constraint na_saved_items_pk primary key(item_id, aggregator_id) +); + +create table na_purges ( + purge_id integer + constraint na_purges_pk + primary key, + top integer + constraint na_purges_top_nn + not null, + bottom integer + constraint na_purges_bottom_nn + not null, + aggregator_id integer + constraint na_purges_aid_fk + references na_aggregators(aggregator_id) + constraint na_purges_aid_nn + not null, + purge_date timestamptz + default current_timestamp +); + +create sequence na_purges_seq; + + +---------------- +-- +-- Subscriptions +-- +---------------- + +create table na_subscriptions ( + aggregator_id integer + constraint na_subscriptions_aid_fk + references na_aggregators(aggregator_id), + source_id integer + constraint na_subscriptions_sid_fk + references na_sources(source_id), + creation_date timestamptz + default current_timestamp, + constraint na_subscriptions_pk primary key (aggregator_id, source_id) +); + +create index na_subscriptions_aid_idx on na_subscriptions(aggregator_id); + +------------------- +-- +-- User Preferences +-- +------------------- + +create table na_user_preferences ( + user_id integer + constraint na_user_prefs_uid_pk + primary key + constraint na_user_prefs_uid_fk + references users(user_id), + default_aggregator integer + constraint na_user_prefs_default_fk + references na_aggregators(aggregator_id) +); + + +----------------------- +-- +-- Pre-subscribed Feeds +-- +----------------------- + +-- source_id, package_id + +create table na_presubscribed_feeds ( + source_id integer + constraint na_presubscribed_feeds_sid_fk + references na_sources(source_id) + constraint na_presubscribed_feeds_sid_nn + not null, + package_id integer + constraint na_presubscribed_feeds_pid_fk + references apm_packages(package_id) + constraint na_presubscribed_feeds_pid_nn + not null +); + +create sequence na_presubscribed_feeds_seq; + + +------------------- +-- +-- Weblogs +-- +------------------- + +select acs_object_type__create_type ( + 'na_weblog', -- object_type + 'News Aggregator Weblog', -- pretty_name + 'News Aggregator Weblogs', -- pretty_plural + 'acs_object', -- supertype + 'na_weblogs', -- table_name + 'weblog_id', -- id_column + 'news-aggregator', -- package_name + 'f', -- abstract_p + null, -- type_extension_table + 'na_weblog__name' -- name_method +); + +create table na_weblogs ( + weblog_id integer + constraint na_weblogs_weblog_id_fk + references acs_objects(object_id) + constraint na_weblogs_weblog_id_nn + not null, + package_id integer + constraint na_weblogs_pid_fk + references apm_packages(package_id) + constraint na_weblogs_pid_nn + not null, + user_id integer + constraint na_weblogs_uid_fk + references users(user_id) + constraint na_weblogs_uid_nn + not null, + weblog_name varchar(100) + constraint na_weblogs_name_nn + not null, + blog_type varchar(100) + constraint na_weblogs_blog_type_nn + not null, + base_url varchar(500) + constraint na_weblogs_base_url_nn + not null, + server varchar(500), + port integer, + path varchar(100), + blogid integer, + username varchar(200), + password varchar(200) +); Index: openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-tables-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-tables-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/sql/postgresql/news-aggregator-tables-drop.sql 20 Mar 2004 11:04:38 -0000 1.1 @@ -0,0 +1,54 @@ +-- Drop non-procedural data model of the News Aggregator application. +-- +-- @author Simon Carstensen (simon@bcuni.net) +-- @creation-date 2003-06-27 + +drop table na_weblogs; +select acs_object_type__drop_type('na_weblog', true); + +drop table na_presubscribed_feeds; +drop sequence na_presubscribed_feeds_seq; + +drop table na_user_preferences; + +drop table na_purges; +drop sequence na_purges_seq; + +--drop na_item table +drop table na_saved_items; +drop index na_items_guid_idx; +drop index na_items_source_id_idx; +drop table na_items; +drop sequence na_items_item_id_seq; + + +--drop na_source table and objects +drop table na_sources; + +delete +from acs_objects +where object_type = 'na_source'; + +select acs_object_type__drop_type( + 'na_source', + 't' + ); + + +--drop na_subscriptions table +drop index na_subscriptions_aid_idx; +drop table na_subscriptions; + + + +-- drop na_aggregators table and objects +drop table na_aggregators; + +delete +from acs_objects +where object_type = 'na_aggregator'; + +select acs_object_type__drop_type( + 'na_aggregator', + 't' + ); Index: openacs-4/packages/news-aggregator/tcl/aggregator-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/aggregator-procs-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/aggregator-procs-postgresql.xql 20 Mar 2004 11:04:38 -0000 1.1 @@ -0,0 +1,203 @@ + + + + postgresql7.1 + + + + select aggregator_name, + description as aggregator_description, + public_p + from na_aggregators + where aggregator_id = :aggregator_id + + + + + + select s.source_id, + s.link, + s.description, + s.title, + to_char(i.creation_date, 'YYYY-MM-DD HH24:MI:SS') as last_scanned, + to_char(i.creation_date, 'YYYY-MM-DD HH24') as sort_date, + s.feed_url, + i.item_id, + i.title as item_title, + i.link as item_link, + i.description as item_description, + i.content_encoded, + i.guid as item_guid, + i.original_guid as item_original_guid, + i.permalink_p as item_permalink_p, + s.last_modified + from ( + na_aggregators a join + na_subscriptions su on (a.aggregator_id = su.aggregator_id) + ) join + na_items i on (su.source_id = i.source_id) + join na_sources s on (i.source_id = s.source_id) + where a.package_id = :package_id + and a.aggregator_id = :aggregator_id + $items_purges + order by i.item_id desc + limit $sql_limit + + + + + + and ((i.item_id > coalesce(a.aggregator_bottom, 0)) or + (i.item_id in (select item_id from na_saved_items + where aggregator_id = :aggregator_id))) + + + + + + select + email, + person__name(party_id) as person_name, + to_char(o.creation_date, 'Dy, DD Mon YYYY HH24:MI:SS TZ') as creation_date, + to_char(o.creation_date, 'Dy, DD Mon YYYY HH24:MI:SS TZ') as modified_date + from + na_aggregators a, + parties p, + acs_objects o + where + a.aggregator_id = o.object_id and a.maintainer_id = p.party_id + and a.aggregator_id = :aggregator_id + + + + + + select + feed_url, + link, + title, + description + from + na_sources s, + na_subscriptions su + where + s.source_id = su.source_id + and su.aggregator_id = :aggregator_id + order by lower(title) + + + + + + select count(purge_id) + from na_purges + where aggregator_id = :aggregator_id + + + + + + select max(top) as max_top, min(bottom) as min_bottom, + nextval('na_purges_seq') as purge_id + from na_purges + where aggregator_id = :aggregator_id + + + + + + update na_aggregators + set aggregator_bottom = :aggregator_bottom + where aggregator_id = :aggregator_id + + + + + + delete from na_purges + where aggregator_id = :aggregator_id + + + + + + insert into na_purges + (purge_id, top, bottom, aggregator_id, purge_date) + values + (:purge_id, :top, :bottom, :aggregator_id, now()) + + + + + + insert into na_user_preferences + (user_id, default_aggregator) + values + (:user_id, :aggregator_id) + + + + + + update na_user_preferences + set default_aggregator = :aggregator_id + where user_id = :user_id + + + + + + select + default_aggregator + from + na_user_preferences + where + user_id = :user_id + + + + + + select min(object_id) as aggregator_id + from acs_objects + where object_type = 'na_aggregator' + and creation_user = :user_id + + + + + + select na_aggregator__delete ( + :aggregator_id + ); + + + + + + + select na_aggregator__new ( + null, + :aggregator_name, + :description, + :package_id, + :public_p, + :creation_user, + :creation_ip + ) + + + + + + update na_aggregators + set + aggregator_name = :aggregator_name, + description = :description, + public_p = :public_p + where + aggregator_id = :aggregator_id + + + + Index: openacs-4/packages/news-aggregator/tcl/aggregator-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/aggregator-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/aggregator-procs.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,391 @@ +ad_library { + Procs to manage aggregators. + + @author Simon Carstensen (simon@bcuni.net) + @author Guan Yang (guan@unicast.org) + @creation-date 2003-06-28 +} + +namespace eval news_aggregator {} +namespace eval news_aggregator::aggregator {} + +ad_proc -public news_aggregator::aggregator::aggregator_info { + {-aggregator_id:required} +} { + Returns a Tcl array-list with some aggregator information: + aggregator_name, aggregator_description and public_p. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-11-10 + @returns Tcl array-list with the information, or empty + string on error. +} { + if { ![db_0or1row aggregator_info ""] } { + return "" + } + + set info(aggregator_name) $aggregator_name + set info(aggregator_description) $aggregator_description + set info(public_p) $public_p + + return [array get info] +} + +ad_proc -public news_aggregator::aggregator::as_xml { + {-aggregator_id:required} + {-package_id:required} + {-stylesheet} + {-stylesheet_type} +} { + Generate an XML document of the contents of the aggregator as they + would be displayed in a public aggregator. The format is specific + to the news aggregator. It is intended to be processed with an XSLT + stylesheet -- that is why we don't return the raw XML string. + + @param stylesheet An URI for a stylesheet that will be inserted + into the document as the xml-stylesheet processing + instruction. + @param stylesheet_type MIME type for the stylesheet. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-10 + @returns tDOM document node +} { + set items_query [news_aggregator::aggregator::items_sql \ + -aggregator_id $aggregator_id \ + -package_id $package_id \ + -purge_p 0] + + dom setResultEncoding "utf-8" + set doc [dom createDocument "aggregator"] + + set doc_node [$doc documentElement] + $doc_node setAttribute "version" "0.9" + + # Create the xml processing instruction + set pi [$doc createProcessingInstruction "xml" {version="1.0"}] + set root [$doc_node selectNode /] + $root insertBefore $pi $doc_node + + # If applicable, create the xml-stylesheet processing instruction + if { [info exists stylesheet] && [info exists stylesheet_type] } { + set pi [$doc createProcessingInstruction "xml-stylesheet" "href=\"$stylesheet\" type=\"$stylesheet_type\""] + $root insertBefore $pi $doc_node + } + + # Create a generator comment + set comment [$doc createComment " Generated by the [ad_system_name] news aggregator. [ad_url] "] + $root insertBefore $comment $doc_node + + set head_node [$doc createElement head] + $doc_node appendChild $head_node + + array set info [news_aggregator::aggregator::aggregator_info \ + -aggregator_id $aggregator_id] + + set header_fields [list \ + [list aggregator_name name] \ + [list aggregator_description description]] + foreach header_field $header_fields { + set node [$doc createElement [lindex $header_field 1]] + set text_node [$doc createTextNode $info([lindex $header_field 0])] + $node appendChild $text_node + $head_node appendChild $node + } + + set body_node [$doc createElement "body"] + $doc_node appendChild $body_node + + set previous_source_id 0 + db_foreach items_sql $items_query { + if { $source_id != $previous_source_id } { + set source_node [$doc createElement source] + $source_node setAttribute title $title \ + link $link \ + description $description + $body_node appendChild $source_node + } + + set item_node [$doc createElement item] + + set title_node [$doc createElement title] + set text_node [$doc createTextNode $item_title] + $title_node appendChild $text_node + $item_node appendChild $title_node + + set link_node [$doc createElement link] + set text_node [$doc createTextNode $item_link] + $link_node appendChild $text_node + $item_node appendChild $link_node + + if { ![string equal $content_encoded ""] } { + set content $content_encoded + } else { + set content $item_description + } + + set content_node [$doc createElement content] + set text_node [$doc createCDATASection $content] + $content_node appendChild $text_node + $item_node appendChild $content_node + + $source_node appendChild $item_node + + set previous_source_id $source_id + } + + set xml [$doc asXML] + $doc delete + return $xml +} + +ad_proc -private news_aggregator::aggregator::items_sql { + {-aggregator_id:required} + {-package_id:required} + {-purge_p:required} + {-limit_multiple 6} +} { + Returns the SQL required to fetch items, including purges + if purge_p is true. +} { + if { $purge_p } { + set items_purges [db_map items_purges] + } else { + set items_purges "" + } + + set limit [ad_parameter -package_id $package_id "number_of_items_shown"] + set sql_limit [expr $limit_multiple*$limit] + + set sql [db_map items] + return $sql +} + +ad_proc -public news_aggregator::aggregator::as_opml { + {-aggregator_id:required} +} { + Generate OPML of the subscriptions of the aggregator in + mySubscriptions.opml format. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-10 + @returns A string containing the XML document. +} { + dom setResultEncoding "utf-8" + set doc [dom createDocument "opml"] + + set doc_node [$doc documentElement] + $doc_node setAttribute "version" "1.1" + + # Create the xml processing instruction + set pi [$doc createProcessingInstruction "xml" {version="1.0"}] + set root [$doc_node selectNode /] + $root insertBefore $pi $doc_node + + # Create a generator comment + set comment [$doc createComment " eenerated by the [ad_system_name] news aggregator. [ad_url] "] + $root insertBefore $comment $doc_node + + # Fetch the aggregator information + if { ![db_0or1row maintainer ""] } { + return "" + } + + # Create the header + set head_node [$doc createElement head] + $doc_node appendChild $head_node + set headers [list \ + [list title "mySubscriptions"] \ + [list dateCreated $creation_date] \ + [list dateModified $modified_date] \ + [list ownerName $person_name] \ + [list ownerEmail $email] \ + [list expansionState ""] \ + [list vertScrollState "1"] \ + [list windowTop 295] \ + [list windowLeft 319] \ + [list windowBottom 495] \ + [list windowRight 704]] + foreach header $headers { + set node [$doc createElement [lindex $header 0]] + set text_node [$doc createTextNode [lindex $header 1]] + $node appendChild $text_node + $head_node appendChild $node + } + + set body_node [$doc createElement "body"] + $doc_node appendChild $body_node + + db_foreach subscriptions "" { + set node [$doc createElement "outline"] + $node setAttribute text $title + $node setAttribute description $description + $node setAttribute htmlUrl $link + $node setAttribute language "unknown" + $node setAttribute title $title + $node setAttribute type "rss" + $node setAttribute version "RSS" + $node setAttribute xmlUrl $feed_url + + $body_node appendChild $node + } + + return [$doc asXML] +} + +ad_proc -private news_aggregator::aggregator::purge { + {-aggregator_id:required} + {-top:required} + {-bottom:required} +} { + Purge the aggregator. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-04 +} { + db_transaction { + # Find out how many purges the aggregator has + # and clear some if there are too many + set purge_count [db_string count_purges ""] + set max_purges [ad_parameter "max_purges"] + if { $purge_count > $max_purges } { + db_1row get_range "" + db_dml purge_all_purges "" + + # The aggregator's bottom is set to the argument + # top because aggregator_bottom is actually the + # highest-numbered item to be displayed. Yes, it + # is confusing. + set aggregator_bottom $top + db_dml aggregator_purge "" + + return + } + + set purge_id [db_nextval na_purges_seq] + db_dml insert_purge "" + } +} + +ad_proc -private news_aggregator::aggregator::set_user_default { + {-user_id:required} + {-aggregator_id:required} +} { + Sets the user's default aggregator to aggregator_id. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-04 +} { + db_dml set_default "" + if { ![db_resultrows] } { + db_dml create_pref "" + } +} + +ad_proc -private news_aggregator::aggregator::user_default { + {-user_id:required} +} { + Returns the user's default aggregator, or 0 if none exists. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-06-29 +} { + set aggregator_id [db_string find_default {} -default 0] + + if { [string equal $aggregator_id "0"] } { + set aggregator_id [db_string lowest_aggregator ""] + if { [exists_and_not_null aggregator_id] } { + news_aggregator::aggregator::set_user_default \ + -user_id $user_id \ + -aggregator_id $aggregator_id + } else { + return 0 + } + } + + return $aggregator_id +} + +ad_proc -public news_aggregator::aggregator::edit { + {-aggregator_id:required} + {-aggregator_name:required} + {-description:required} + {-public_p:required} +} { + Edit the aggregator's name or listing status. + + @author Guan Yang + @creation-date 2003-06-29 +} { + db_dml edit_aggregator {} + + if { [db_resultrows] } { + # Error + return 1 + } else { + return 0 + } +} + +ad_proc -public news_aggregator::aggregator::new { + {-aggregator_name:required} + {-description ""} + {-package_id ""} + {-public_p t} + {-creation_user ""} + {-creation_ip ""} +} { + Create a new news aggregator. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-06-29 +} { + + if { ![exists_and_not_null creation_user] } { + set creation_user [ad_conn user_id] + } + + if { ![exists_and_not_null creation_ip] } { + set creation_ip [ad_conn peeraddr] + } + + if { ![exists_and_not_null package_id] } { + set package_id [ad_conn package_id] + } + + return [db_exec_plsql new_aggregator {}] +} + +ad_proc -public news_aggregator::aggregator::delete { + {-aggregator_id:required} +} { + Delete an aggregator. + + @author Simon Carstensen (simon@bcuni.net) + @creation-date 2003-06-28 +} { + db_exec_plsql delete_aggregator {} +} + +ad_proc -public news_aggregator::aggregator::load_preinstalled_subscriptions { + -aggregator_id:required + -package_id:required +} { + + db_foreach select_feeds {} { + + news_aggregator::subscription::new \ + -aggregator_id $aggregator_id \ + -source_id $source_id + } +} + +ad_proc -public news_aggregator::aggregator::options { + -user_id:required +} { + Returns options (value label pairs) for building the news aggregator HTML select box. + + @author Simon Carstensen +} { + return [db_list_of_lists select_aggregator_options {}] +} Index: openacs-4/packages/news-aggregator/tcl/aggregator-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/Attic/aggregator-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/aggregator-procs.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,31 @@ + + + + + + + select source_id + from na_presubscribed_feeds + where package_id = :package_id + + + + + + select source_id + from na_presubscribed_feeds + where package_id = :package_id + + + + + + select a.aggregator_name, + a.aggregator_id + from na_aggregators a join + acs_objects o on (a.aggregator_id = o.object_id) + where o.creation_user = :user_id + + + + Index: openacs-4/packages/news-aggregator/tcl/install-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/install-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/install-procs.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,58 @@ +ad_library { + Procedures for initializing service contracts etc. for the + workflow package. Should only be executed once upon installation. + + @creation-date 2003-07-04 + @author Simon Carstensen (simon@bcuni.net) + @author Guan Yang (guan@unicast.org) +} + +namespace eval news_aggregator::install {} + + +############### +# +# Install procs +# +############### + +ad_proc -private news_aggregator::install::feed { + -package_id:required + -source_id:required +} { + if { ![db_0or1row feed_exists_p {}] } { + db_dml insert_feed {} + } +} + +ad_proc -private news_aggregator::install::after_install { + -package_id:required +} { + News Aggregator package install proc +} { + set package_id [db_string select_package_id {}] + set user_id [ad_conn user_id] + + set feeds { + http://www.bbc.co.uk/syndication/feeds/news/ukfs_news/front_page/rss091.xml + http://boingboing.net/rss.xml + http://caterina.net/index.rdf + http://www.csmonitor.com/rss/top.rss + http://weblog.siliconvalley.com/column/dangillmor/index.xml + http://www.dictionary.com/wordoftheday/wotd.rss + http://partners.userland.com/nytRss/nytHomepage.xml + http://www.theregister.co.uk/tonys/slashdot.rdf + http://www.wired.com/news_drop/netcenter/netcenter.rdf + } + + foreach feed_url $feeds { + set source_id [news_aggregator::source::new \ + -feed_url $feed_url \ + -user_id $user_id \ + -package_id $package_id] + + news_aggregator::install::feed \ + -package_id $package_id \ + -source_id $source_id + } +} Index: openacs-4/packages/news-aggregator/tcl/install-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/install-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/install-procs.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,33 @@ + + + + + + + select max(package_id) + from apm_packages + where package_key = 'news-aggregator' + + + + + + insert into na_presubscribed_feeds ( + source_id, + package_id + ) values ( + :source_id, + :package_id + ) + + + + + + select 1 + from na_presubscribed_feeds + where source_id = :source_id + + + + Index: openacs-4/packages/news-aggregator/tcl/news-aggregator-init.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/news-aggregator-init.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/news-aggregator-init.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1 @@ +ad_schedule_proc -thread t 900 news_aggregator::source::update_all Index: openacs-4/packages/news-aggregator/tcl/opml-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/opml-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/opml-procs.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,77 @@ +ad_library { + Some random procs to parse (not generate) OPML. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-17 +} + +namespace eval news_aggregator::opml {} + +ad_proc -public news_aggregator::opml::parse { + {-xml:required} +} { + Parse the OPML and return a wonderful special data structure. + This is Guan's Ultra Liberal OPML Parser (GULOP). + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-17 +} { + if { [catch { + set doc [dom parse $xml] + + set doc_node [$doc documentElement] + if { ![string equal [$doc_node nodeName] "opml"] } { + error "Document element is not opml" + } + + set opml(status) "success" + + set head_nodes [$doc_node selectNodes {/opml/*[local-name()='head']}] + if { [llength $head_nodes] != 1 } { + error "There is not exactly one head element" + } + set head_node [lindex $head_nodes 0] + set title_texts [$head_node selectNodes {*[local-name()='title']/text()}] + if { [llength $title_texts] != 1 } { + error "There is not exactly one title element in head: $title_texts" + } + set title_text [[lindex $title_texts 0] nodeValue] + if { ![string equal $title_text "mySubscriptions"] } { + error "OPML title is not 'mySubscriptions'. This does not appear to be an OPML file in mySubscriptions format." + } + + set body_nodes [$doc_node selectNodes {/opml/*[local-name()='body']}] + if { [llength $body_nodes] == 0 } { + # No body node + error "Document element has no body child" + } + # If there is more than one body child, we take the first one + set body_node [lindex $body_nodes 0] + + set elements [list] + + foreach node [$body_node getElementsByTagName "outline"] { + set title [$node getAttribute title ""] + set url [$node getAttribute xmlUrl ""] + set html_url [$node getAttribute htmlUrl ""] + + if { ![string equal $title ""] && ![string equal url ""] && + ![string equal $html_url ""] && + [util_url_valid_p $url] } { + set feed(title) $title + set feed(url) $url + set feed(html_url) $html_url + lappend elements [array get feed] + } + } + + set opml(elements) $elements + } errmsg] } { + set error(status) "failure" + set error(errmsg) $errmsg + + return [array get error] + } + + return [array get opml] +} Index: openacs-4/packages/news-aggregator/tcl/source-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/source-procs-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/source-procs-postgresql.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,117 @@ + + + + postgresql7.1 + + + + update na_sources + set last_scanned = now(), + title = :title, + link = :link, + description = :description + where source_id = :source_id + + + + + + select count(*) + from na_sources + + + + + + select source_id, + feed_url, + last_modified + from na_sources + where last_scanned < (now() - '00:48:00'::time) + order by last_scanned asc + limit $limit + + + + + + + select guid, original_guid, i.title, i.description + from na_items i join + na_sources s on (i.source_id = s.source_id) + where s.feed_url = :feed_url + and guid in ($guids) + order by i.item_id asc + + + + + + select na_source__new ( + :source_id, + :feed_url, + :link, + :title, + :description, + :last_modified, + '1', + :package_id, + :user_id, + :creation_ip + ) + + + + + + select na_item__new ( + :source_id, + :link, + :guid, + boolean :permalink_p, + :title, + :description, + :content_encoded + ); + + + + + + update na_sources + set link = :link, + title = :title, + description = :description, + updates = (updates + 1), + last_scanned = now(), + last_modified = now(), + last_modified_stamp = now() + where source_id = :source_id + + + + + + select na_item__new ( + :source_id, + :link, + :guid, + :original_guid, + boolean :permalink_p, + :title, + :description, + :content_encoded + ); + + + + + + select na_source__delete( + :source_id + ); + + + + + Index: openacs-4/packages/news-aggregator/tcl/source-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/source-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/source-procs.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,282 @@ +ad_library { + Procs to manage sources. + + @author Simon Carstensen (simon@bcuni.net) + @author Guan Yang (guan@unicast.org) + @creation-date 2003-06-28 +} + +namespace eval news_aggregator {} +namespace eval news_aggregator::source {} + +ad_proc -public news_aggregator::source::new { + -feed_url:required + -user_id:required + -package_id:required + {-aggregator_id ""} +} { + @author Simon Carstensen + + Parse feed_url for link, title, and description. Then insert the source if it does not excist already. +} { + + set source_id [db_string source {} -default ""] + + if { [exists_and_not_null source_id] } { + if { [exists_and_not_null aggregator_id] } { + news_aggregator::subscription::new \ + -aggregator_id $aggregator_id \ + -source_id $source_id + + return $source_id + } + return 0 + } + + array set f [ad_httpget -url $feed_url -depth 4] + + if { ![string equal 200 $f(status)] || [catch { array set result [news_aggregator::parse -xml $f(page)] }] } { + return 0 + } + + array set channel $result(channel) + set title [string_truncate -len 500 -no_format -- $channel(title)] + set link [string_truncate -len 500 -no_format -- $channel(link)] + set description [string_truncate -len 500 -no_format -- $channel(description)] + + set source_id [db_nextval "acs_object_id_seq"] + set creation_ip [ad_conn peeraddr] + set last_modified $f(modified) + + db_exec_plsql add_source {} + + if { [exists_and_not_null aggregator_id] } { + news_aggregator::subscription::new \ + -aggregator_id $aggregator_id \ + -source_id $source_id + } + + set items $result(items) + + foreach array $items { + array set item $array + set title [string_truncate -len 500 -no_format -- $item(title)] + set link [string_truncate -len 500 -no_format -- $item(link)] + set guid [string_truncate -len 500 -no_format -- $item(guid)] + set permalink_p $item(permalink_p) + set description $item(description) + set content_encoded $item(content_encoded) + } + + return $source_id +} + + +ad_proc -public news_aggregator::source::get_identifier { + {-guid:required} + {-link:required} + {-domain:required} + {-description:required} +} { + if { [exists_and_not_null guid] } { + return guid + } elseif { [exists_and_not_null link] && [news_aggregator::check_link \ + -link $link \ + -domain $domain] } { + return link + } elseif { [exists_and_not_null description] } { + return description + } +} + +ad_proc -public news_aggregator::source::update { + {-source_id:required} + {-feed_url:required} + {-modified:required} +} { + Parse source and then update the source if it has changed. + + @author Simon Carstensen + @author Guan Yang (guan@unicast.org) +} { + ns_log Debug "source::update: updating $feed_url (source_id=$source_id)" + + set headers [ns_set create] + ns_set put $headers "If-Modified-Since" $modified + ns_set put $headers "Referer" [ad_parameter "referer"] + + if { [catch { array set f [ad_httpget \ + -url $feed_url \ + -headers $headers] }] } { + ns_log Debug "source::update: httpget failed" + return + } + + if { ![string equal 200 $f(status)] } { + ns_log Debug "source::update: httpget didn't return 200 but $f(status)" + return + } + + if { [catch { + set parse_result [news_aggregator::parse \ + -xml $f(page)] + array set result $parse_result + } err] } { + ns_log Debug "source::update: parse failed, error = $err" + return + } + + array set channel $result(channel) + set items $result(items) + + set no_items 0 + set updated_p 0 + set guid_list [list] + + if { [llength $items] == 0 } { + # No items + return + } + + # First we assemble a list of arrays of: + # feed_url, guid + # Then we fetch the guids that we want to deal with + # Finally, we insert those. + foreach array $items { + array set item $array + set guid [news_aggregator::source::generate_guid \ + -link $item(link) \ + -feed_url $feed_url \ + -title $item(title) \ + -description $item(description) \ + -guid $item(guid)] + + lappend guid_list "'$guid'" + } + + set guids [join $guid_list ", "] + set existing_guids [list] + + db_foreach items "" { + lappend existing_guids $guid + set existing_items($guid) [list $title $description] + ns_log Debug "source::update: existing guid $guid\n\ttitle = $title" + } + + ns_log Debug "source::update: existing_guids = $existing_guids" + + foreach array $items { + array set item $array + + set title [string_truncate -len 500 -format html -no_format -- $item(title)] + set link [string_truncate -len 500 -no_format -- $item(link)] + set original_guid [string_truncate -len 500 -no_format -- $item(guid)] + set permalink_p $item(permalink_p) + set content_encoded $item(content_encoded) + set description $item(description) + + set guid [news_aggregator::source::generate_guid \ + -link $item(link) \ + -feed_url $feed_url \ + -title $item(title) \ + -description $item(description) \ + -guid $item(guid)] + + if { [lsearch -exact $existing_guids $guid] == -1 } { + set new_p 1 + ns_log Debug "source::update: guid $guid marked as new" + } else { + set new_p 0 + set db_title [lindex $existing_items($guid) 0] + set db_description [lindex $existing_items($guid) 1] + + ns_log Debug "source::update: guid $guid marked as existing\ttitle = $db_title\tdescription = $db_description" + } + + if { (!$new_p + && (![string equal $db_title $title] || + ![string equal $db_description $description])) + || + $new_p } { + set updated_p 1 + ns_log Debug "source::update: guid $guid marked as existing but updated; title=!$title! description=!$description!" + if { [info exists db_title] && [info exists db_description] } { + ns_log Debug "source::update:\tdb_title=!$db_title! db_description=!$db_description!" + ns_log Debug "source::update:\tfirst_equal=[string equal $db_title $title] second_equal=[string equal $db_description $description] new_p=$new_p item_title=[string length $title] chars db_title=[string length $db_title] chars" + } elseif { $new_p } { + ns_log Debug "source::update: guid $guid is new and will be inserted; title=$title description=$description" + } + +# set title $item(title) +# set description $item(description) +# set content_encoded $item(content_encoded) +# set original_guid $item(guid) +# set permalink_p $item(permalink_p) +# set link $item(link) + + db_exec_plsql add_item {} + incr no_items + } else { + ns_log Debug "source::update: guid $guid marked as existing and not updated" + } + } + + set link $channel(link) + set title $channel(title) + set description $channel(description) + if { $updated_p } { + db_dml update_source "" + } else { + db_dml update_source_no_new "" + } +} + +ad_proc -private news_aggregator::source::generate_guid { + {-link:required} + {-feed_url:required} + {-title:required} + {-description:required} + {-guid} +} { + Generate a private GUID for an entry that is used only + by news-aggregator. +} { + if { ![exists_and_not_null guid] } { + set message [list $title $link $description] + set guid [ns_sha1 $message] + } + + return "$guid@$feed_url" +} + +ad_proc -public news_aggregator::source::delete { + {-source_id:required} +} { + db_exec_plsql delete_source {} +} + +ad_proc -public news_aggregator::source::update_all {} { + @author Simon Carstensen + + Update sources by a one hour interval. +} { + ns_log Notice "Updating news aggregator sources" + + db_transaction { + set source_count [db_string source_count ""] + if { $source_count >= 1 } { + set limit [expr int($source_count/4)] + set sources [db_list_of_lists sources ""] + foreach source $sources { + set source_id [lindex $source 0] + set feed_url [lindex $source 1] + set last_modified [lindex $source 2] + + news_aggregator::source::update \ + -source_id $source_id \ + -feed_url $feed_url \ + -modified $last_modified + } + } + } +} Index: openacs-4/packages/news-aggregator/tcl/source-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/Attic/source-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/source-procs.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,13 @@ + + + + + + + select source_id + from na_sources + where feed_url = :feed_url + + + + Index: openacs-4/packages/news-aggregator/tcl/subscription-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/subscription-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/subscription-procs.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,51 @@ +ad_library { + Procs to manage subscriptions. + + @author Simon Carstensen (simon@bcuni.net) + @author Guan Yang (guan@unicast.org) + @creation-date 2003-06-28 +} + +namespace eval news_aggregator {} +namespace eval news_aggregator::subscription {} + +ad_proc -public news_aggregator::subscription::new { + {-aggregator_id:required} + {-source_id:required} +} { + if { ![db_string subscription_exists_p {} -default "0"] } { + db_dml insert_subscription {} + } +} + +ad_proc -public news_aggregator::subscription::delete { + {-source_id:required} + {-aggregator_id:required} +} { + db_dml delete_subscription {} +} + +ad_proc -public news_aggregator::subscription::move { + {-source_id:required} + {-move_from:required} + {-move_to:required} +} { + Move subscription to another aggregator + + @author Simon Carstensen + @creation_date 2003-08-23 +} { + db_dml move_subscription {} +} + +ad_proc -public news_aggregator::subscription::copy { + {-source_id:required} + {-copy_to:required} +} { + Copy subscription to another aggregator + + @author Simon Carstensen + @creation_date 2003-08-23 +} { + db_dml copy_subscription {} +} Index: openacs-4/packages/news-aggregator/tcl/subscription-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/Attic/subscription-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/subscription-procs.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,59 @@ + + + + + + + insert into na_subscriptions ( + aggregator_id, + source_id, + creation_date + ) values ( + :aggregator_id, + :source_id, + now() + ) + + + + + + select 1 + from na_subscriptions + where aggregator_id =:aggregator_id + and source_id = :source_id + + + + + + delete from na_subscriptions + where source_id = :source_id + and aggregator_id =:aggregator_id + + + + + + update na_subscriptions + set aggregator_id = :move_to + where source_id = :source_id + and aggregator_id = :move_from + + + + + + insert into na_subscriptions ( + aggregator_id, + source_id, + creation_date + ) values ( + :copy_to, + :source_id, + now() + ) + + + + Index: openacs-4/packages/news-aggregator/tcl/weblog-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/weblog-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/weblog-procs.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,181 @@ +ad_library { + Procs to manage aggregators. + + @author Simon Carstensen (simon@bcuni.net) + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-09 +} + +namespace eval news_aggregator {} +namespace eval news_aggregator::weblog {} +namespace eval news_aggregator::weblog::impl {} + +ad_proc -public news_aggregator::weblog::new { + {-package_id ""} + {-user_id ""} + -blog_type:required + -weblog_name:required + -base_url:required + {-ip ""} +} { + Creates a new weblog and returns weblog_id. + @author Simon Carstensen (simon@bcuni.net) + @creation-date 2003-07-14 +} { + if { [empty_string_p $package_id]} { + set package_id [ad_conn package_id] + } + if { [empty_string_p $user_id]} { + set user_id [ad_conn user_id] + } + if { [empty_string_p $ip]} { + set ip [ns_conn peeraddr] + } + + set weblog_id [db_string new_weblog {}] + + return $weblog_id +} + +ad_proc -public news_aggregator::weblog::edit { + -weblog_id:required + -blog_type:required + -weblog_name:required + -base_url:required +} { + Edit weblog. + + @author Simon Carstensen (simon@bcuni.net) + @creation-date 2003-07-14 +} { + db_dml edit_weblog {} +} + +ad_proc -public news_aggregator::weblog::validate_base_url { + -blog_type:required + -base_url:required +} { + Attempt to validate the specified base URL against the + specified blog type. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-12-15 + + @return 1 if the base URL successfully validates, or 0 if + it does not appear to be valid, or if the blog type + could not be found. +} { + return [news_aggregator::weblog::impl::${blog_type}_validate_url \ + -base_url $base_url] +} + +ad_proc -private news_aggregator::weblog::impl::movabletype_validate_url { + -base_url:required +} { + Validates a Movable Type base URL. +} { + set valid_p 1 + + if { ![util_url_valid_p $base_url] } { + # Not a valid URL at all + return 0 + } + + # MT base urls will start with http or https + if { ![regexp {^https?://} $base_url] } { + return 0 + } + + # At some point we expect to see "app?" or "mt.cgi?" + # Is this too strict? + if { ![regexp {/app\?__mode=[a-z]+&blog_id=(\d+)} $base_url match blog_id] && + ![regexp {/mt.cgi\?__mode=[a-z]+&blog_id=(\d+)} $base_url match blog_id] } { + return 0 + } + + return 1 +} + +ad_proc -private news_aggregator::weblog::impl::movabletype_get_post_url { + -base_url:required + -title:required + -link:required + -text:required +} { + Returns the post URL for a Movable Type weblog. Will barf bigtime + if the URL is not valid. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-12-15 +} { + if { ![news_aggregator::weblog::impl::movabletype_validate_url \ + -base_url $base_url] } { + return "" + } + + if { [regexp {^(.+/app\?)__mode=[a-z]+&blog_id=(\d+)} $base_url match first_part blog_id] || + [regexp {^(.+/mt.cgi\?)__mode=[a-z]+&blog_id=(\d+)} $base_url match first_part blog_id] } { + # do nothing + } + + set post_url $first_part + append post_url [export_vars -url [list \ + [list "is_bm" 1] \ + [list "bm_show" "trackback,category,allow_comments,allow_pings,convert_breaks,excerpt,text_more#,keywords"] \ + [list "__mode" "view"] \ + [list "_type" "entry"] \ + [list "blog_id" $blog_id] \ + [list "link_title" $title] \ + [list "link_href" $link] \ + [list "text" $text]]] + + + return $post_url +} + +ad_proc -public news_aggregator::weblog::get_post_url { + -blog_type:required + -base_url:required + -title:required + -link:required + -text:required +} { + Attempt to return an URL which will bring the user to a page + where he can post a weblog entry. If we don't succeed, throw + an error. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-12-15 +} { + return [news_aggregator::weblog::impl::${blog_type}_get_post_url \ + -base_url $base_url \ + -title $title \ + -link $link \ + -text $text] +} + +ad_proc -public news_aggregator::weblog::options { + -user_id:required +} { + Returns options (value label pairs) for building the weblog HTML select box. + + @author Simon Carstensen +} { + return [db_list_of_lists select_weblog_options {}] +} + +ad_proc -public news_aggregator::weblog::blog_type_options {} { + Returns options (value label pairs) for building the blog type HTML select box. + + @author Simon Carstensen +} { + return { + {"Select Blog Type" {}} + {"Blogger" blogger} + {"Manila" manila} + {"Movable Type" movabletype} + {"Radio Userland" radio} + {"TypePad" typepad} + } +} + Index: openacs-4/packages/news-aggregator/tcl/weblog-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/tcl/weblog-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/tcl/weblog-procs.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,48 @@ + + + + + + + select weblog_name, + weblog_id + from na_weblogs + where user_id = :user_id + + + + + + select na_weblog__new ( + null, + :package_id, + :blog_type, + :weblog_name, + :base_url, + :user_id, + :ip + ) + + + + + + update na_weblogs set blog_type = :blog_type, + base_url = :base_url, + weblog_name = :weblog_name + where weblog_id = :weblog_id + + + + + + select weblog_name, + blog_type, + base_url + from na_weblogs + where weblog_id = :weblog_id + + + + + Index: openacs-4/packages/news-aggregator/www/aggregator-delete.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/aggregator-delete.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/aggregator-delete.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,30 @@ +ad_page_contract { + Delete an aggregator + + @author Simon Carstensen +} { + delete_aggregator_id:integer +} + +permission::require_permission \ + -object_id $delete_aggregator_id \ + -privilege write + +set user_id [ad_conn user_id] +set default_aggregator [db_string find_default {}] + +if { [string equal $delete_aggregator_id $default_aggregator] } { + # We are deleting the user's default aggregator + # Set user's oldest aggregator as new default + set new_default_aggregator [db_string select_oldest_aggregator {} -default ""] + if { [exists_and_not_null $new_default_aggregator] } { + news_aggregator::aggregator::set_user_default \ + -user_id $user_id \ + -aggregator_id $new_default_aggregator + } +} + +news_aggregator::aggregator::delete \ + -aggregator_id $delete_aggregator_id + +ad_returnredirect [ad_conn package_url]settings Index: openacs-4/packages/news-aggregator/www/aggregator-delete.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/Attic/aggregator-delete.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/aggregator-delete.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,26 @@ + + + + + + + select default_aggregator + from na_user_preferences + where user_id = :user_id + + + + + + select aggregator_id + from na_aggregators a, + acs_objects o + where a.aggregator_id = o.object_id + and creation_user = :user_id + and aggregator_id != :delete_aggregator_id + order by creation_date + limit 1 + + + + Index: openacs-4/packages/news-aggregator/www/aggregator.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/aggregator.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/aggregator.adp 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,7 @@ + + @page_title@ + @context@ + aggregator.aggregator_name + + + Index: openacs-4/packages/news-aggregator/www/aggregator.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/aggregator.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/aggregator.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,58 @@ +ad_page_contract { + Create a new aggregator. + + @author Simon Carstensen +} { + aggregator_id:integer,notnull,optional + {return_url ""} +} + +set page_title "Create aggregator" +set context [list $page_title] + +set user_id [ad_maybe_redirect_for_registration] + +ad_form -name aggregator -select_query_name select_aggregator -form { + {aggregator_id:integer(hidden),key} + {aggregator_name:text + {label "Name"} + } + {description:text(textarea),optional + {label "Description"} + {html {cols 60 rows 10}} + } + {public_p:text(radio) + {label "Public?"} + {options {{"Yes" t} {"No" f}}} + {help_text "A public aggregator is intended to be used by a group of people and will not have a Purge button. Instead, the most recent 100 items will be displayed."} + } + {return_url:text(hidden) + {value $return_url} + } +} -edit_data { + news_aggregator::aggregator::edit \ + -aggregator_id $aggregator_id \ + -aggregator_name $aggregator_name \ + -description $description \ + -public_p $public_p + + if { [exists_and_not_null return_url] } { + ad_returnredirect $return_url + } else { + ad_returnredirect settings + } + ad_script_abort + +} -new_data { + set new_aggregator_id [news_aggregator::aggregator::new \ + -aggregator_name $aggregator_name \ + -description $description \ + -public_p $public_p] + + if { [exists_and_not_null return_url] } { + ad_returnredirect $return_url + } else { + ad_returnredirect "[ad_conn package_url]$new_aggregator_id" + } + ad_script_abort +} Index: openacs-4/packages/news-aggregator/www/aggregator.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/aggregator.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/aggregator.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,16 @@ + + + + + + + select aggregator_id, + aggregator_name, + description, + public_p + from na_aggregators + where aggregator_id = :aggregator_id + + + + Index: openacs-4/packages/news-aggregator/www/index.vuh =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/index.vuh,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/index.vuh 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,13 @@ +set path_info_list [split [ad_conn path_info] "/"] + +set aggregator_id [lindex $path_info_list 0] +set form [rp_getform] +if { [string equal [ns_set iget $form aggregator_id] ""] } { + rp_form_put aggregator_id $aggregator_id +} + +if { [llength $path_info_list] == 2 } { + rp_internal_redirect "/packages/news-aggregator/www/[lindex $path_info_list 1]" +} else { + rp_internal_redirect "/packages/news-aggregator/www/index" +} Index: openacs-4/packages/news-aggregator/www/item-blog.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/item-blog.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/item-blog.adp 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,17 @@ + + @page_title@ + @context@ + +

+ Source: @title@; @last_scanned@. +

+ +

+ @content@ +

+ + + +

+ Note: You will not usually come back to the aggregator. +

\ No newline at end of file Index: openacs-4/packages/news-aggregator/www/item-blog.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/item-blog.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/item-blog.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,67 @@ +ad_page_contract { + Post this item to user's weblog through Blogger API. + + @author Simon Carstensen + @creation-date 2003-07-08 +} { + item_id:integer +} + +set page_title "Post this item to your weblog" +set context [list $page_title] + +db_1row select_item {} + +if { [exists_and_not_null content_encoded] } { + set content $content_encoded +} else { + set text_only [util_remove_html_tags $item_description] + + if {[exists_and_not_null item_title] && ![string equal -nocase $item_title $text_only] } { + set content "$item_title. $item_description" + } else { + set content $item_description + } +} + +set user_id [ad_conn user_id] +set weblog_options [news_aggregator::weblog::options \ + -user_id $user_id] + +ad_form -name blog_item -form { + {item_id:integer(hidden) + {value $item_id} + } + {content:text(hidden) + {value $content} + } + {weblog_id:integer(select) + {options $weblog_options} + {label "Select weblog:"} + } +} -on_submit { + + set user_id [ad_conn user_id] + + permission::require_permission \ + -object_id $weblog_id \ + -privilege read + + db_1row select_weblog "" + + if { [exists_and_not_null content_encoded] } { + set text $content_encoded + } else { + set text $item_description + } + + set post_url [news_aggregator::weblog::get_post_url \ + -blog_type $blog_type \ + -base_url $base_url \ + -title $item_title \ + -text $text \ + -link $link] + + ad_returnredirect $post_url + ad_script_abort +} Index: openacs-4/packages/news-aggregator/www/item-blog.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/item-blog.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/item-blog.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,32 @@ + + + + + + + select i.title as item_title, + i.description as item_description, + i.content_encoded, + i.link as item_link, + s.title, + s.link, + to_char(s.last_scanned, 'YYYY-MM-DD; HH24:MI:SS') as last_scanned + from na_items i join + na_sources s on (i.source_id = s.source_id) + where item_id = :item_id + + + + + + select + blog_type, + base_url + from + na_weblogs + where + weblog_id = :weblog_id + + + + Index: openacs-4/packages/news-aggregator/www/item-save-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/item-save-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/item-save-postgresql.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,25 @@ + + + + + + + select aggregator_id + from na_aggregators + where aggregator_id = :aggregator_id + + + + + + insert into na_saved_items ( + item_id, + aggregator_id + ) values ( + :item_id, + :aggregator_id + ) + + + + Index: openacs-4/packages/news-aggregator/www/item-save.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/item-save.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/item-save.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,22 @@ +ad_page_contract { + Save an item. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-07 +} { + item_id:naturalnum,notnull + aggregator_id:naturalnum,notnull +} + +set user_id [ad_maybe_redirect_for_registration] + +db_1row aggregator_info "" + +permission::require_permission \ + -party_id $user_id \ + -object_id $aggregator_id \ + -privilege write + +catch { db_dml save_item "" } errmsg + +ad_returnredirect "[ad_conn package_url]$aggregator_id/\#$item_id" Index: openacs-4/packages/news-aggregator/www/item-unsave-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/item-unsave-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/item-unsave-postgresql.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,21 @@ + + + + + + + select aggregator_id + from na_aggregators + where aggregator_id = :aggregator_id + + + + + + delete from na_saved_items + where item_id = :item_id + and aggregator_id = :aggregator_id + + + + Index: openacs-4/packages/news-aggregator/www/item-unsave.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/item-unsave.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/item-unsave.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,22 @@ +ad_page_contract { + Unsave an item. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-07 +} { + item_id:naturalnum,notnull + aggregator_id:naturalnum,notnull +} + +set user_id [ad_maybe_redirect_for_registration] + +db_1row aggregator_info "" + +permission::require_permission \ + -party_id $user_id \ + -object_id $aggregator_id \ + -privilege write + +catch {db_dml unsave_item ""} errmsg + +ad_returnredirect "[ad_conn package_url]$aggregator_id/\#$item_id" Index: openacs-4/packages/news-aggregator/www/opml-import-2.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/opml-import-2.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/opml-import-2.adp 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,9 @@ + +@page_title@ +@context@ + +

+ The following feeds were found in the OPML file at @opml_url@: +

+ + \ No newline at end of file Index: openacs-4/packages/news-aggregator/www/opml-import-2.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/opml-import-2.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/opml-import-2.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,73 @@ +ad_page_contract { + The -2 page for OPML import. + + @author Guan Yang (guan@unicast.org) + @cvs-id $Id: opml-import-2.tcl,v 1.1 2004/03/20 11:04:39 gyang Exp $ + @creation-date 2003-08-14 +} { + aggregator_id:naturalnum,notnull + url:notnull +} -validate { + url_is_valid -requires { url:notnull } { + if { ![util_url_valid_p $url] } { + ad_complain "The URL you have entered is not valid." + } + } +} + +set opml_url $url + +set user_id [ad_maybe_redirect_for_registration] +permission::require_permission \ + -object_id $aggregator_id \ + -party_id $user_id \ + -privilege write + +set page_title "OPML Import" +set context [list $page_title] + +if { [catch { + array set f [ad_httpget -url $url] + if { $f(status) != 200 } { + error "Could not fetch document via HTTP." + } + + array set opml [news_aggregator::opml::parse -xml $f(page)] + + if { $opml(status) == "failure" } { + error "OPML parse error: $opml(errmsg)" + } + + set sources $opml(elements) + if { [llength $sources] == 0 } { + error "OPML file did not contain any valid sources" + } + + list::create \ + -name opml_feeds \ + -multirow opml_feeds \ + -key url \ + -row_pretty_plural "sources" \ + -bulk_actions { + Subscribe opml-import-3 + } -elements { + title { + label "Name" + display_template { + @opml_feeds.title@ + } + } + } + + multirow create opml_feeds title html_url url + foreach source $sources { + array set s $source + multirow append opml_feeds $s(title) $s(html_url) $s(url) + } + +} errmsg] } { + ad_return_complaint 1 "OPML import error: $errmsg" + ad_script_abort +} Index: openacs-4/packages/news-aggregator/www/opml-import-3.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/opml-import-3.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/opml-import-3.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,35 @@ +ad_page_contract { + Import the final OPML urls. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-08-23 + @cvs-id $Id: opml-import-3.tcl,v 1.1 2004/03/20 11:04:39 gyang Exp $ +} { + aggregator_id:naturalnum,notnull + url:multiple,notnull +} + +set package_id [ad_conn package_id] +set user_id [ad_maybe_redirect_for_registration] +permission::require_permission \ + -object_id $aggregator_id \ + -party_id $user_id \ + -privilege write + +catch { + foreach feed_url $url { + set source_id [news_aggregator::source::new \ + -feed_url $feed_url \ + -user_id $user_id \ + -package_id $package_id \ + -aggregator_id $aggregator_id] + + if { $source_id } { + news_aggregator::subscription::new \ + -aggregator_id $aggregator_id \ + -source_id $source_id + } + } +} + +ad_returnredirect subscriptions \ No newline at end of file Index: openacs-4/packages/news-aggregator/www/opml-import-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/opml-import-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/opml-import-postgresql.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,21 @@ + + + + + postgresql + 7.1 + + + + + select + feed_url + from + na_sources f, + na_subscriptions u + where + u.aggregator_id = :aggregator_id + and u.source_id = f.source_id + + + Index: openacs-4/packages/news-aggregator/www/opml-import.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/opml-import.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/opml-import.adp 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,14 @@ + + +@page_title@ + +

+ » Back to subscriptions +

+ +

+ You can import OPML either from an URL, or by uploading a file. +

+ + + Index: openacs-4/packages/news-aggregator/www/opml-import.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/opml-import.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/opml-import.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,29 @@ +ad_page_contract { + Page to load a file or URL with OPML for import. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-18 + @cvs-id $Id: opml-import.tcl,v 1.1 2004/03/20 11:04:39 gyang Exp $ +} { + aggregator_id:naturalnum,notnull + opml_id:naturalnum,optional + {format "opml"} +} + +set user_id [ad_maybe_redirect_for_registration] +set page_title "OPML Import" + +permission::require_permission \ + -object_id $aggregator_id \ + -party_id $user_id \ + -privilege write + +ad_form -name opml -action opml-import-2 -form { + {url:text,optional + {label "URL"} + {help_text "The URL of an OPML file in mySubscriptions format."} + {html {size 50}}} + {opml_file:file,optional + {label "File"} + {help_text "This feature is not currently implemented."}} +} \ No newline at end of file Index: openacs-4/packages/news-aggregator/www/opml.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/opml.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/opml.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,15 @@ +ad_page_contract { + Export aggregator as OPML. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-10 +} { + {aggregator_id:naturalnum,notnull} +} + +if { [catch {set opml [news_aggregator::aggregator::as_opml \ + -aggregator_id $aggregator_id]} errmsg] } { + doc_return 200 text/html "" +} else { + doc_return 200 application/xml $opml +} Index: openacs-4/packages/news-aggregator/www/opml.vuh =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/opml.vuh,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/opml.vuh 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,5 @@ +set path_info_list [split [ad_conn path_info] "/"] + +set aggregator_id [lindex $path_info_list 1] +rp_form_put aggregator_id $aggregator_id +rp_internal_redirect "/packages/news-aggregator/www/opml" Index: openacs-4/packages/news-aggregator/www/purge-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/purge-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/purge-postgresql.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,12 @@ + + + + + + + select public_p from na_aggregators + where aggregator_id = :aggregator_id + + + + Index: openacs-4/packages/news-aggregator/www/purge.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/purge.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/purge.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,29 @@ +ad_page_contract { + Effect a purge. + + @author Guan Yang (guan@unicast.org) + @creation-date 2003-07-07 +} { + aggregator_id:naturalnum,notnull + purge_top:naturalnum,notnull + purge_bottom:naturalnum,notnull +} + +set user_id [ad_maybe_redirect_for_registration] + +db_1row aggregator_info "" + +permission::require_permission \ + -party_id $user_id \ + -object_id $aggregator_id \ + -privilege write + +if { $public_p == "f" } { + # Only purge if the aggregator is not public + news_aggregator::aggregator::purge \ + -aggregator_id $aggregator_id \ + -top $purge_top \ + -bottom $purge_bottom +} + +ad_returnredirect "[ad_conn package_url]$aggregator_id" Index: openacs-4/packages/news-aggregator/www/settings-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/settings-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/settings-postgresql.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,7 @@ + + + + postgresql7.1 + + + Index: openacs-4/packages/news-aggregator/www/settings.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/settings.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/settings.adp 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,28 @@ + + @page_title@ + @context@ + +

+

Your News Aggregators

+ +

+

+ » Create new aggregator +

+ + +

Default News Aggregator

+ + Select default aggregator:
+ + +
+
+ +

+

Your Weblogs

+ +

+

+ » Add new weblog +

Index: openacs-4/packages/news-aggregator/www/settings.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/settings.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/settings.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,142 @@ +ad_page_contract { + Settings. + + @author Simon Carstensen + @creation-date 2003-07-01 +} { + aggregator_id:integer,optional +} + +set page_title "Your Settings" +set context [list $page_title] + +set user_id [ad_conn user_id] +set package_id [ad_conn package_id] +set package_url [ad_conn package_url] + +set aggregator_options [news_aggregator::aggregator::options -user_id $user_id] +set default_aggregator_id [news_aggregator::aggregator::user_default -user_id $user_id] + +ad_form -name aggregators -form { + {default_aggregator_id:integer(select) + {options $aggregator_options} + {value $default_aggregator_id} + } + {submit:text(submit) + {label "Go"} + } +} -on_submit { + news_aggregator::aggregator::set_user_default \ + -user_id $user_id \ + -aggregator_id $default_aggregator_id + + ad_returnredirect settings + ad_script_abort +} + +set return_url settings +set aggregator_link [export_vars -base "${package_url}aggregator" {return_url}] + +template::list::create \ + -name "aggregators" \ + -multirow "aggregators" \ + -key aggregator_id \ + -row_pretty_plural "aggregators" \ + -elements { + edit { + label {} + display_template { + Edit this aggregator + } + } + aggregator_name { + label "Name" + display_template { + @aggregators.aggregator_name@ + + (default) + + } + link_url_eval {} + link_html { title "" } + } + public_p { + label "Public?" + } + delete { + label {} + display_template { + Delete this aggregator + } + } + } + +db_multirow -extend { + url + edit_url + delete_url + delete_onclick + default_p +} aggregators select_aggregators {} { + if { [string equal $public_p t] } { + set public_p "Yes" + } else { + set public_p "No" + } + + set url $package_url + set edit_url [export_vars -base "${url}aggregator" {aggregator_id}] + set delete_url [export_vars -base aggregator-delete {{delete_aggregator_id $aggregator_id}}] + set delete_onclick "return confirm('Are you sure you want to delete this news aggregator?');" + + if { [string equal $aggregator_id $default_aggregator] } { + set default_p 1 + } else { + set default_p 0 + } +} + +template::list::create \ + -name "weblogs" \ + -multirow "weblogs" \ + -key weblog_id \ + -row_pretty_plural "weblogs" \ + -elements { + edit { + label {} + display_template { + Edit this weblog + } + } + weblog_name { + label "Name" + } + delete { + label {} + display_template { + Delete this weblog + } + } + } + +db_multirow -extend { url edit_url delete_url delete_onclick } weblogs select_weblogs { + select weblog_id, + weblog_name + from na_weblogs + where user_id = :user_id + order by server +} { + set url $package_url + set edit_url [export_vars -base "${url}weblog" {weblog_id}] + set delete_url [export_vars -base weblog-delete {weblog_id}] + set delete_onclick "return confirm('Are you sure you want to delete this weblog?');" +} Index: openacs-4/packages/news-aggregator/www/settings.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/settings.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/settings.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,20 @@ + + + + + + + select a.aggregator_id, + a.aggregator_name, + a.public_p, + u.default_aggregator + from na_aggregators a join + acs_objects o on (o.object_id = a.aggregator_id) join + na_user_preferences u on (o.creation_user = u.user_id) + where a.package_id = :package_id + and u.user_id = :user_id + order by a.aggregator_name + + + + Index: openacs-4/packages/news-aggregator/www/source.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/source.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/source.adp 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,3 @@ + + @page_title@ + @context@ Index: openacs-4/packages/news-aggregator/www/source.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/source.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/source.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,16 @@ +ad_page_contract { + View source. + + @author Simon Carstensen +} { + source_id:integer +} + +set write_p [permission::permission_p \ + -object_id $source_id \ + -privilege write] + +db_1row source_info {} + +set page_title $title +set context [list $page_title] Index: openacs-4/packages/news-aggregator/www/source.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/source.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/source.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,16 @@ + + + + + + + select title, + link, + description, + last_scanned + from na_sources + where source_id = :source_id + + + + Index: openacs-4/packages/news-aggregator/www/subscription-copy.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/subscription-copy.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/subscription-copy.adp 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,5 @@ + + @page_title@ + @context@ + + Index: openacs-4/packages/news-aggregator/www/subscription-copy.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/subscription-copy.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/subscription-copy.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,67 @@ +ad_page_contract { + Copy subscription from one aggregator to another. + + @author Simon Carstensen (simon@bcuni.net) + @creation-date 2003-08-23 +} { + aggregator_id:integer + {source_id:integer,multiple ""} + {source_ids ""} + {copy_to:integer ""} +} + +permission::require_permission \ + -object_id $aggregator_id \ + -privilege write + +set user_id [ad_conn user_id] +set package_id [ad_conn package_id] +set package_url [ad_conn package_url] + +if { [exists_and_not_null copy_to] } { + + foreach source_id $source_ids { + news_aggregator::subscription::copy \ + -source_id $source_id \ + -copy_to $copy_to + } + + ad_returnredirect "${package_url}$copy_to/subscriptions" + ad_script_abort +} + +set aggregator_count [db_string count_aggregators {}] + +if { [string equal $aggregator_count "2"] } { + set copy_to [db_string select_aggregator_id {}] + + foreach source $source_id { + news_aggregator::subscription::copy \ + -source_id $source \ + -copy_from $aggregator_id \ + -copy_to $copy_to + } + + ad_returnredirect "${package_url}$copy_to/subscriptions" + ad_script_abort +} + +set page_title "Copy subscription" +set context [list $page_title] + +set package_id [ad_conn package_id] +set list_of_aggregators [db_list_of_lists select_aggregators {}] + +ad_form -name copy_subscription -form { + {aggregator_id:integer(hidden) + {value $aggregator_id} + } + {source_ids:integer(hidden) + {value $source_id} + } + {copy_to:integer(select) + {label "Copy to:"} + {value $copy_to} + {options $list_of_aggregators} + } +} Index: openacs-4/packages/news-aggregator/www/subscription-copy.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/subscription-copy.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/subscription-copy.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,42 @@ + + + + + + + select a.aggregator_name, + a.aggregator_id + from na_aggregators a join + acs_objects o on (o.object_id = a.aggregator_id) join + na_user_preferences u on (o.creation_user = u.user_id) + where a.package_id = :package_id + and u.user_id = :user_id + and a.aggregator_id != :aggregator_id + order by aggregator_name + + + + + + select count(*) + from na_aggregators a, + acs_objects o + where a.aggregator_id = o.object_id + and o.creation_user = :user_id + + + + + + select a.aggregator_id + from na_aggregators a join + acs_objects o on (o.object_id = a.aggregator_id) join + na_user_preferences u on (o.creation_user = u.user_id) + where a.package_id = :package_id + and u.user_id = :user_id + and a.aggregator_id != :aggregator_id + order by o.creation_date + + + + Index: openacs-4/packages/news-aggregator/www/subscription-move.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/subscription-move.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/subscription-move.adp 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,5 @@ + + @page_title@ + @context@ + + Index: openacs-4/packages/news-aggregator/www/subscription-move.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/subscription-move.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/subscription-move.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,68 @@ +ad_page_contract { + Move subscription from one aggregator to another. + + @author Simon Carstensen (simon@bcuni.net) + @creation-date 2003-08-23 +} { + aggregator_id:integer + {source_id:integer,multiple ""} + {source_ids ""} + {move_to:integer ""} +} + +permission::require_permission \ + -object_id $aggregator_id \ + -privilege write + +set user_id [ad_conn user_id] +set package_id [ad_conn package_id] +set package_url [ad_conn package_url] + +if { [exists_and_not_null move_to] } { + + foreach source_id $source_ids { + news_aggregator::subscription::move \ + -source_id $source_id \ + -move_from $aggregator_id \ + -move_to $move_to + } + + ad_returnredirect "${package_url}$move_to/subscriptions" + ad_script_abort +} + +set aggregator_count [db_string count_aggregators {}] + +if { [string equal $aggregator_count "2"] } { + set move_to [db_string select_aggregator_id {}] + + foreach source $source_id { + news_aggregator::subscription::move \ + -source_id $source \ + -move_from $aggregator_id \ + -move_to $move_to + } + + ad_returnredirect "${package_url}$move_to/subscriptions" + ad_script_abort +} + +set page_title "Move subscription" +set context [list $page_title] + +set package_id [ad_conn package_id] +set list_of_aggregators [db_list_of_lists select_aggregators {}] + +ad_form -name move_subscription -form { + {aggregator_id:integer(hidden) + {value $aggregator_id} + } + {source_ids:integer(hidden) + {value $source_id} + } + {move_to:integer(select) + {label "Move to:"} + {value $move_to} + {options $list_of_aggregators} + } +} Index: openacs-4/packages/news-aggregator/www/subscription-move.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/subscription-move.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/subscription-move.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,42 @@ + + + + + + + select a.aggregator_name, + a.aggregator_id + from na_aggregators a join + acs_objects o on (o.object_id = a.aggregator_id) join + na_user_preferences u on (o.creation_user = u.user_id) + where a.package_id = :package_id + and u.user_id = :user_id + and a.aggregator_id != :aggregator_id + order by aggregator_name + + + + + + select count(*) + from na_aggregators a, + acs_objects o + where a.aggregator_id = o.object_id + and o.creation_user = :user_id + + + + + + select a.aggregator_id + from na_aggregators a join + acs_objects o on (o.object_id = a.aggregator_id) join + na_user_preferences u on (o.creation_user = u.user_id) + where a.package_id = :package_id + and u.user_id = :user_id + and a.aggregator_id != :aggregator_id + order by o.creation_date + + + + Index: openacs-4/packages/news-aggregator/www/weblog-delete.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/weblog-delete.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/weblog-delete.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,16 @@ +ad_page_contract { + Delete a weblog. + + @author Simon Carstensen (simon@bcuni.net) + @creation-date 2003-07-16 +} { + weblog_id:integer +} + +set user_id [ad_conn user_id] +set package_id [ad_conn package_id] + +db_dml delete_weblog {} + +ad_returnredirect settings +ad_script_abort Index: openacs-4/packages/news-aggregator/www/weblog-delete.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/weblog-delete.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/weblog-delete.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,14 @@ + + + + + + + delete from na_weblogs + where weblog_id = :weblog_id + and user_id = :user_id + and package_id = :package_id + + + + Index: openacs-4/packages/news-aggregator/www/weblog.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/weblog.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/weblog.adp 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,7 @@ + + @page_title@ + @context@ + weblog.weblog_name + + + Index: openacs-4/packages/news-aggregator/www/weblog.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/weblog.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/weblog.tcl 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,54 @@ +ad_page_contract { + Create new weblog. + + @author Simon Carstensen +} { + weblog_id:integer,optional +} + +set page_title "New Weblog" +set context [list $page_title] + +set blog_type_options [news_aggregator::weblog::blog_type_options] + +ad_form -name weblog -select_query_name select_weblog -form { + {weblog_id:integer(hidden),key} + {blog_type:text(select) + {label "Blog Type"} + {options $blog_type_options} + } + {weblog_name:text + {label "Name"} + {html {size 40}} + } + {base_url:text + {label "Base URL"} + {html {size 40}} + } +} -validate { + {base_url + {[util_url_valid_p $base_url]} + "The base URL must be a valid URL for your weblog tool." + } +} -edit_data { + news_aggregator::weblog::edit \ + -weblog_id $weblog_id \ + -blog_type $blog_type \ + -base_url $base_url \ + -weblog_name $weblog_name + + ad_returnredirect settings + ad_script_abort +} -new_data { + set ip [ns_conn peeraddr] + + set new_weblog_id [news_aggregator::weblog::new \ + -blog_type $blog_type \ + -weblog_name $weblog_name \ + -base_url $base_url \ + -ip $ip] + + ad_returnredirect settings + ad_script_abort +} -select_query_name weblog_select + Index: openacs-4/packages/news-aggregator/www/weblog.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/weblog.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/news-aggregator/www/weblog.xql 20 Mar 2004 11:04:39 -0000 1.1 @@ -0,0 +1,16 @@ + + + + + + + select weblog_id, + weblog_name, + blog_type, + base_url + from na_weblogs + where weblog_id = :weblog_id + + + + Index: openacs-4/packages/news-aggregator/www/graphics/delete.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/graphics/delete.gif,v diff -u Binary files differ Index: openacs-4/packages/news-aggregator/www/graphics/edit.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/graphics/edit.gif,v diff -u Binary files differ Index: openacs-4/packages/news-aggregator/www/graphics/post.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/graphics/post.gif,v diff -u Binary files differ Index: openacs-4/packages/news-aggregator/www/graphics/save.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/graphics/save.gif,v diff -u Binary files differ Index: openacs-4/packages/news-aggregator/www/graphics/technorati.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/graphics/technorati.png,v diff -u Binary files differ Index: openacs-4/packages/news-aggregator/www/graphics/update.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/graphics/update.gif,v diff -u Binary files differ Index: openacs-4/packages/news-aggregator/www/graphics/view.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/graphics/view.gif,v diff -u Binary files differ Index: openacs-4/packages/news-aggregator/www/graphics/xml.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/news-aggregator/www/graphics/xml.gif,v diff -u Binary files differ