Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 501 lines (436 sloc) 17.275 kb
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
1 %%%----------------------------------------------------------------------
2 %%% File : yaws_rss.erl
3 %%% Created : 15 Dec 2004 by Torbjorn Tornkvist <tobbe@tornkvist.org>
4 %%%
5 %%% @doc A Yaws RSS feed interface.
6 %%%
7 %%% @author Torbjörn Törnkvist <tobbe@tornkvist.org>
8 %%% @end
9 %%%
10 %%% $Id$
11 %%%----------------------------------------------------------------------
12 -module(yaws_rss).
13
14 -behaviour(gen_server).
15
16 %% External exports
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
17 -export([start/0, start_link/0, open/1, open/2, close/0, close/2,
18 insert/5, insert/6, insert/7, retrieve/2]).
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
19
20 -export([t_setup/0, t_exp/0, t_xopen/0]).
21
22 %% gen_server callbacks
23 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
24
25 -record(s, {
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
26 open_apps = [], % activated applications
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
27 expire = false, % false | days
28 rm_exp = false, % remove expired items
29 max=infinite, % maximum number of elements in DB
30 days=7, % maximum number of days in DB
fbf6580 Yaws is now RSS capable, see doc/README.rss
Tobbe Tornquist authored
31 counter}). % item counter
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
32
33 -define(SERVER, ?MODULE).
34 -define(DB, ?MODULE).
35 -define(DB_FNAME, "yaws_rss.dets").
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
36 -define(ITEM(App, Tag, Counter, Item), {{App, Tag, Counter}, Item}).
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
37
38 %%%----------------------------------------------------------------------
39 %%% API
40 %%%----------------------------------------------------------------------
41 start_link() ->
42 gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
43
44 start() ->
45 gen_server:start({local, ?SERVER}, ?MODULE, [], []).
46
47 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
48 %%% @spec open(App::atom(), Dir::string()) ->
49 %%% {ok, DB::db()} | {error, string()}
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
50 %%%
51 %%% @type db(). An opaque handle leading to an RSS database.
52 %%%
53 %%% @doc See {@open/2}
54 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
55 open(App) ->
56 open(App, []).
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
57
58 %%%
8af1e99 Fixing the yaws-rss functionality. Adding configure parameter rss_dir…
Tobbe Tornquist authored
59 %%% @spec open(App::atom(), Opts::list()) ->
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
60 %%% {ok, DB::db()} | {error, string()}
61 %%%
8af1e99 Fixing the yaws-rss functionality. Adding configure parameter rss_dir…
Tobbe Tornquist authored
62 %%% @doc Open a RSS database.
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
63 %%% Per default <em>dets</em> is used as database,
64 %%% but by using the <em>db_mod</em> option it is
65 %%% possible to use your own database.</br>
66 %%% These are the options:
67 %%% <p><dl>
68 %%%
69 %%% <dt>{db_mod, Module}</dt>
70 %%% <dd>If specified, the following functions will be
71 %%% called:<ul>
72 %%% <li>Module:open(Opts)</li>
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
73 %%% <li>Module:insert(App,Tag,Title,Link,Desc,Creator,GregSec)</li>
74 %%% <li>Module:retrieve(App,Tag) -&gt; {Title, Link, Desc, Creator, GregSecs}</li>
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
75 %%% <li>Module:close(DbName)</li></ul>
76 %%% This means that the default DB won't be used, and
77 %%% no expiration handling will be done. Only the producing of
78 %%% XML will thus be done. Also, the whole <em>Opts</em> will be
79 %%% passed un-interpreted to the other DB module.</dd>
80 %%%
8af1e99 Fixing the yaws-rss functionality. Adding configure parameter rss_dir…
Tobbe Tornquist authored
81 %%% <dt>{db_dir, Dir}</dt>
82 %%% <dd>Specifies the directory where the database will be created.
83 %%% Default is: /tmp</dd>
84 %%%
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
85 %%% <dt>{expire, Expire}</dt>
86 %%% <dd>Specifies what method to use to expire items. Possible values
87 %%% are: <em>false</em>, <em>days</em>, meaning
88 %%% never expire, expire after a number of days.
89 %%% Default is to never expire items.</dd>
90 %%%
91 %%% <dt>{days, Number}</dt>
92 %%% <dd>Specifies the number of days befor an item is expired.
93 %%% Default is 7 days.</dd>
94 %%%
95 %%% <dt>{rm_exp, Bool}</dt>
96 %%% <dd>Specifies if expired items should be removed from
97 %%% the database. Default is to not remove any items.</dd>
98 %%%
99 %%% <dt>{max, Number}</dt>
100 %%% <dd>Specifies the maximum number of items that should
101 %%% be stored in the database. The default in <em>infinite</em></dd>
102 %%% </dl></p>
103 %%% <p>If no database exist, a new will be created.
104 %%% The returned database handle is to be used with {@link close/1}.
105 %%% @end
106 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
107 open(App, Opts) ->
108 gen_server:call(?SERVER, {open, App, Opts}, infinity).
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
109
110 %%%
111 %%% @spec close() -> ok | {error, string()}
112 %%%
113 %%% @doc Close the RSS database.
114 %%%
115 close() ->
116 gen_server:call(?SERVER, {close, ?DB}, infinity).
117
118 %%%
119 %%% @spec close(DbMod::atom(), DbName::atom()) ->
120 %%% ok | {error, string()}
121 %%%
122 %%% @doc Close the user provided RSS database.
123 %%% A call to; <em>DbMod:close(DbName)</em> will be made.
124 %%%
125 close(DBmod, DBname) ->
126 gen_server:call(?SERVER, {close, DBmod, DBname}, infinity).
127
128 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
129 %%% @spec insert(App::atom(), Tag::atom(), Title::string(),
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
130 %%% Link::string(), Desc::string()) ->
131 %%% ok | {error, string()}
132 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
133 %%% @doc Insert an RSS item into the <em>{App,Tag}</em> RSS feed.
134 %%% An application (App) can maintain several feeds each
135 %%% one refered to with a symbolic name (Tag).
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
136 %%% <em>Link</em> should be a URL pointing to the item.
137 %%% <p>In case another database backend is used, the
138 %%% <em>Tag</em> has the format: <em>{DbModule, OpaqueTag}</em>
139 %%% where <em>DbModule</em> is the database backend module
140 %%% to be called, and <em>OpaqueTag</em> the Tag that is
141 %%% used in <em>DbModule:insert(Tag, ...)</em></p>
142 %%% @end
143 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
144 insert(App, Tag, Title, Link, Desc) ->
145 insert(App, Tag, Title, Link, Desc, "").
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
146
147 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
148 %%% @spec insert(App::atom(), Tag::atom(), Title::string(),
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
149 %%% Link::string(), Desc::string(),
150 %%% Creator::string()) ->
151 %%% ok | {error, string()}
152 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
153 %%% @doc Works as {@link insert/5} but takes an extra argument
154 %%% <em>Creator</em> which may contains an identification
155 %%% of who created the item.
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
156 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
157 insert(App, Tag, Title, Link, Desc, Creator) ->
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
158 GregSecs = calendar:datetime_to_gregorian_seconds({date(),time()}),
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
159 insert(App, Tag, Title, Link, Desc, Creator, GregSecs).
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
160
161 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
162 %%% @spec insert(App::atom(), Tag::atom(), Title::string(),
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
163 %%% Link::string(), Desc::string(),
164 %%% Creator::string(), GregSecs::integer()) ->
165 %%% ok | {error, string()}
166 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
167 %%% @doc Works as {@link insert/6} but takes an extra argument
168 %%% <em>GregSecs</em> which is the creation time of the item
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
169 %%% in Gregorian Seconds.
170 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
171 insert(App, Tag, Title, Link, Desc, Creator, GregSecs) ->
172 Args = {App, Tag, Title, Link, Desc, Creator, GregSecs},
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
173 gen_server:call(?SERVER, {insert, Args}, infinity).
174
175
176 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
177 %%% @spec retrieve(App::atom(), Tag::atom()) ->
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
178 %%% {ok, RSScontent::IoList()} | {error, string()}
179 %%%
180 %%% @type IoList. A deep list of strings and/or binaries.
181 %%%
182 %%% @doc Retrieve the <em>RSScontent</em> (in XML and all...)
183 %%% to be delivered to a RSS client.
184 %%% <p>In case another database backend is used, the
185 %%% <em>Tag</em> has the format: <em>{DbModule, OpaqueTag}</em>
186 %%% where <em>DbModule</em> is the database backend module
187 %%% to be called, and <em>OpaqueTag</em> the Tag that is
188 %%% used in <em>DbModule:retrieve(Tag)</em> which must return
189 %%% a list of tuples: <em>{Title, Link, Desc, Creator, GregSecs}</em></p>
190 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
191 retrieve(App, Tag) ->
192 gen_server:call(?SERVER, {retrieve, App, Tag}, infinity).
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
193
194 %%%----------------------------------------------------------------------
195 %%% Callback functions from gen_server
196 %%%----------------------------------------------------------------------
197
198 %%----------------------------------------------------------------------
199 %% Func: init/1
200 %% Returns: {ok, State} |
201 %% {ok, State, Timeout} |
202 %% ignore |
203 %% {stop, Reason}
204 %%----------------------------------------------------------------------
205 init([]) ->
206 {ok, #s{}}.
207
208 %%----------------------------------------------------------------------
209 %% Func: handle_call/3
210 %% Returns: {reply, Reply, State} |
211 %% {reply, Reply, State, Timeout} |
212 %% {noreply, State} |
213 %% {noreply, State, Timeout} |
214 %% {stop, Reason, Reply, State} | (terminate/2 is called)
215 %% {stop, Reason, State} (terminate/2 is called)
216 %%----------------------------------------------------------------------
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
217 handle_call({open, App, Opts}, _From, State) ->
218 {NewState, Res} = do_open_dir(State, App, Opts),
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
219 {reply, Res, NewState};
220 %%
221 handle_call({close, DB}, _From, State) ->
222 dets:close(DB),
223 {reply, ok, State};
224 %%
225 handle_call({close, DBMod, DBname}, _From, State) ->
226 catch apply(DBMod, close, [DBname]),
227 {reply, ok, State};
228 %%
229 handle_call({insert, Args}, _From, State) ->
230 {NewState, Res} = do_insert(State, Args),
231 {reply, Res, NewState};
232 %%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
233 handle_call({retrieve, App, Tag}, _From, State) ->
234 {NewState, Res} = do_retrieve(State, App, Tag),
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
235 {reply, Res, NewState}.
236
237 %%----------------------------------------------------------------------
238 %% Func: handle_cast/2
239 %% Returns: {noreply, State} |
240 %% {noreply, State, Timeout} |
241 %% {stop, Reason, State} (terminate/2 is called)
242 %%----------------------------------------------------------------------
243 handle_cast(_Msg, State) ->
244 {noreply, State}.
245
246 %%----------------------------------------------------------------------
247 %% Func: handle_info/2
248 %% Returns: {noreply, State} |
249 %% {noreply, State, Timeout} |
250 %% {stop, Reason, State} (terminate/2 is called)
251 %%----------------------------------------------------------------------
252 handle_info(_Info, State) ->
253 {noreply, State}.
254
255 %%----------------------------------------------------------------------
256 %% Func: terminate/2
257 %% Purpose: Shutdown the server
258 %% Returns: any (ignored by gen_server)
259 %%----------------------------------------------------------------------
260 terminate(_Reason, _State) ->
261 ok.
262
263 %%%----------------------------------------------------------------------
264 %%% Internal functions
265 %%%----------------------------------------------------------------------
266
267 %%%
268 %%% Check what database store that should be used.
269 %%% Per default 'dets' is used.
270 %%%
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
271 do_open_dir(State, App, Opts) ->
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
272 case get_db_mod(Opts, dets) of
273 dets ->
8af1e99 Fixing the yaws-rss functionality. Adding configure parameter rss_dir…
Tobbe Tornquist authored
274 File = get_db_file(Opts),
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
275 Expire = get_expire(Opts, #s.expire),
276 Max = get_max(Opts, #s.max),
277 Days = get_days(Opts, #s.days),
278 RmExp = get_rm_exp(Opts, #s.rm_exp),
279 case dets:is_dets_file(File) of
280 false ->
281 {State, {error, "not a proper dets file"}};
282 _ ->
283 case catch dets:open_file(?DB, [{file, File}]) of
fbf6580 Yaws is now RSS capable, see doc/README.rss
Tobbe Tornquist authored
284 {ok,DB} = Res ->
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
285 {State#s{
286 open_apps = u_insert(App, State#s.open_apps),
287 expire = Expire,
288 days = Days,
289 rm_exp = RmExp,
fbf6580 Yaws is now RSS capable, see doc/README.rss
Tobbe Tornquist authored
290 max = Max,
291 counter = init_counter(DB)},
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
292 Res};
293 {error, _Reason} ->
294 {State, {error, "open dets file"}}
295 end
296 end;
297 DBmod ->
298 {State, catch apply(DBmod, open, Opts)}
299 end.
300
8af1e99 Fixing the yaws-rss functionality. Adding configure parameter rss_dir…
Tobbe Tornquist authored
301 get_db_file(Opts) ->
302 Dir = get_db_dir(Opts, "/tmp"),
303 Dir ++ "/" ++ a2l(?DB) ++ ".dets".
304
fbf6580 Yaws is now RSS capable, see doc/README.rss
Tobbe Tornquist authored
305 init_counter(DB) ->
306 case dets:lookup(DB, counter) of
307 [] -> dets:insert(DB, {counter, 0}), 0;
308 [{counter,N}] -> N
309 end.
310
311 set_counter(DB, N) ->
312 dets:insert(DB, {counter, N}).
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
313
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
314 do_insert(State, {App, {DbMod,Tag}, Title, Link, Desc, Creator, GregSecs}) ->
315 {State, catch apply(DbMod, insert, [App, Tag,Title,Link,Desc,Creator,GregSecs])};
316 do_insert(State, {App, Tag, Title, Link, Desc, Creator, GregSecs}) ->
317 case lists:member(App, State#s.open_apps) of
318 true ->
319 Counter = if (State#s.max > 0) ->
320 (State#s.counter + 1) rem State#s.max;
321 true ->
322 State#s.counter + 1
323 end,
324 Item = {Title, Link, Desc, Creator, GregSecs},
325 Res = dets:insert(?DB, ?ITEM(App, Tag, Counter, Item)),
fbf6580 Yaws is now RSS capable, see doc/README.rss
Tobbe Tornquist authored
326 set_counter(?DB, Counter),
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
327 {State#s{counter = Counter}, Res};
328 false ->
329 {State, {error, "no open DB"}}
330 end.
331
332
333 do_retrieve(State, App, {DbMod,Tag}) ->
334 {State, catch apply(DbMod, retrieve, [App, Tag])};
335 do_retrieve(State, App, Tag) ->
336 case lists:member(App, State#s.open_apps) of
337 true ->
338 F = fun(?ITEM(Xa, Xt, _Counter, Item), Acc) when Xa == App, Xt == Tag ->
339 [Item|Acc];
340 (_, Acc) ->
341 Acc
342 end,
343 Items = sort_items(expired(State, dets:foldl(F, [], ?DB))),
344 Xml = to_xml(Items),
345 {State, {ok, Xml}};
346 false ->
347 {State, {error, "no open DB"}}
348 end.
349
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
350
351
352 -define(ONE_DAY, 86400). % 24*60*60 seconds
353 -define(X(GregSecs), {Title, Link, Desc, Creator, GregSecs}).
354
355 %%% Filter away expired items !!
356 expired(State, List) when State#s.expire == days ->
357 Gs = calendar:datetime_to_gregorian_seconds({date(),time()}),
358 Old = Gs - (?ONE_DAY * State#s.days),
359 F = fun(?X(GregSecs), Acc) when GregSecs > Old ->
360 [?X(GregSecs) | Acc];
361 (_, Acc) ->
362 Acc
363 end,
364 lists:foldl(F, [], List);
365 expired(_State, List) ->
366 List.
367
368 -undef(X).
369
370
371
372 %%%
373 %%% Sort on creation date !!
374 %%% Item = {Title, Link, Desc, Creator, GregSecs},
375 %%%
376 sort_items(Is) ->
377 lists:keysort(5,Is).
378
379
380 to_xml([{Title, Link, Desc, Creator, GregSecs}|Tail]) ->
b6717e7 Fixed the RSS date format, as suggested by Daniel Kaminski.
Tobbe Tornquist authored
381 Date = w3cdtf(GregSecs),
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
382 [["<item>\n",
6938f5c The generated content was not valid RSS 2.0 content. This is fixed now.
Tobbe Tornquist authored
383 "<title>", yaws_api:htmlize(Title), "</title>\n",
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
384 "<link>", Link, "</link>\n",
6938f5c The generated content was not valid RSS 2.0 content. This is fixed now.
Tobbe Tornquist authored
385 "<guid>", Link, "</guid>\n",
386 "<description>", yaws_api:htmlize(Desc), "</description>\n",
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
387 "<dc:creator>", Creator, "</dc:creator>\n",
388 "<dc:date>", Date, "</dc:date>\n",
389 "</item>\n"] |
390 to_xml(Tail)];
391 to_xml([]) ->
392 [].
393
9ea2690 Cleaned up w3cdtf-date function by Daniel Kaminski.
Tobbe Tornquist authored
394 %%%
395 %%% Create W3CDTF (http://www.w3.org/TR/NOTE-datetime) formatted date
396 %%% w3cdtf(GregSecs) -> "YYYY-MM-DDThh:mm:ssTZD"
397 %%%
398 w3cdtf(GregSecs) -> Date = calendar:gregorian_seconds_to_datetime(GregSecs),
399 {{Y, Mo, D},{H, Mi, S}} = Date,
400 [UDate|_] = calendar:local_time_to_universal_time_dst(Date),
401 {DiffD,{DiffH,DiffMi,_}}=calendar:time_difference(UDate,Date),
402 w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi).
403
404 %%% w3cdtf's helper function
405 w3cdtf_diff(Y, Mo, D, H, Mi, S, _DiffD, DiffH, DiffMi) when DiffH < 12, DiffH /= 0 ->
406 i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
407 add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
408 add_zero(S) ++ "+" ++ add_zero(DiffH) ++ ":" ++ add_zero(DiffMi);
409
410 w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi) when DiffH > 12, DiffD == 0 ->
411 i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
412 add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
413 add_zero(S) ++ "+" ++ add_zero(DiffH) ++ ":" ++
414 add_zero(DiffMi);
415
416 w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi) when DiffH > 12, DiffD /= 0, DiffMi /= 0 ->
417 i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
418 add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
419 add_zero(S) ++ "-" ++ add_zero(23-DiffH) ++
420 ":" ++ add_zero(60-DiffMi);
421
422 w3cdtf_diff(Y, Mo, D, H, Mi, S, DiffD, DiffH, DiffMi) when DiffH > 12, DiffD /= 0, DiffMi == 0 ->
423 i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
424 add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
425 add_zero(S) ++ "-" ++ add_zero(24-DiffH) ++
426 ":" ++ add_zero(DiffMi);
427
428 w3cdtf_diff(Y, Mo, D, H, Mi, S, _DiffD, DiffH, _DiffMi) when DiffH == 0 ->
429 i2l(Y) ++ "-" ++ add_zero(Mo) ++ "-" ++ add_zero(D) ++ "T" ++
430 add_zero(H) ++ ":" ++ add_zero(Mi) ++ ":" ++
431 add_zero(S) ++ "Z".
432
433 add_zero(I) when integer(I) -> add_zero(i2l(I));
434 add_zero([A]) -> [$0,A];
435 add_zero(L) when list(L) -> L.
081c135 Updated the RSS date format, as suggested by Daniel Kaminski.
Tobbe Tornquist authored
436
b6717e7 Fixed the RSS date format, as suggested by Daniel Kaminski.
Tobbe Tornquist authored
437
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
438
439 get_db_mod(Opts, Def) -> lkup(db_mod, Opts, Def).
8af1e99 Fixing the yaws-rss functionality. Adding configure parameter rss_dir…
Tobbe Tornquist authored
440 get_db_dir(Opts, Def) -> lkup(db_dir, Opts, Def).
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
441 get_expire(Opts, Def) -> lkup(expire, Opts, Def).
442 get_max(Opts, Def) -> lkup(max, Opts, Def).
443 get_days(Opts, Def) -> lkup(days, Opts, Def).
444 get_rm_exp(Opts, Def ) -> lkup(rm_exp, Opts, Def).
445
446 lkup(Key, List, Def) ->
447 case lists:keysearch(Key, 1, List) of
448 {value,{_,Value}} -> Value;
449 _ -> Def
450 end.
451
452
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
453 u_insert(H, [H|T]) -> T;
454 u_insert(E, [H|T]) -> [H|u_insert(E,T)];
455 u_insert(E, []) -> [E].
456
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
457
458 i2l(I) when integer(I) -> integer_to_list(I);
459 i2l(L) when list(L) -> L.
460
461 a2l(A) when atom(A) -> atom_to_list(A);
462 a2l(L) when list(L) -> L.
463
464
465
466
467 t_setup() ->
fbf6580 Yaws is now RSS capable, see doc/README.rss
Tobbe Tornquist authored
468 %%open([{db_file, "yaws_rss.dets"}, {max,7}]),
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
469 insert(test,xml,"Normalizing XML, Part 2",
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
470 "http://www.xml.com/pub/a/2002/12/04/normalizing.html",
471 "In this second and final look at applying relational "
472 "normalization techniques to W3C XML Schema data modeling, "
473 "Will Provost discusses when not to normalize, the scope "
474 "of uniqueness and the fourth and fifth normal forms."),
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
475 insert(test,xml,"The .NET Schema Object Model",
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
476 "http://www.xml.com/pub/a/2002/12/04/som.html",
477 "Priya Lakshminarayanan describes in detail the use of "
478 "the .NET Schema Object Model for programmatic manipulation "
479 "of W3C XML Schemas."),
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
480 insert(test,xml,"SVG's Past and Promising Future",
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
481 "http://www.xml.com/pub/a/2002/12/04/svg.html",
482 "In this month's SVG column, Antoine Quint looks back at "
483 "SVG's journey through 2002 and looks forward to 2003.").
484
485
486 t_exp() ->
487 %%open([{db_file, "yaws_rss.dets"}, {expire,days}]),
30d2427 Added RSS config parameters ro config parser and some more documentat…
Tobbe Tornquist authored
488 insert(test,xml,"Expired article",
6e45786 Added RSS store/interface.
Tobbe Tornquist authored
489 "http://www.xml.com/pub/a/2002/12/04/normalizing.html",
490 "In this second and final look at applying relational "
491 "normalization techniques to W3C XML Schema data modeling, "
492 "Will Provost discusses when not to normalize, the scope "
493 "of uniqueness and the fourth and fifth normal forms.",
494 "tobbe",
495 63269561882). % 6/12-2004
496
497 t_xopen() ->
498 open([{db_file, "yaws_rss.dets"},
499 {expire,days},
500 {days, 20}]).
Something went wrong with that request. Please try again.