root/HTTP/WikiDateService.lua

Revision 1419 (checked in by rsz, 6 months ago)

cleanup

Line 
1 --------------------------------------------------------------------------------
2 -- Title:               WikiDateService.lua
3 -- Description:         Like a square peg in a round hole
4 -- Author:              Raphaël Szwarc http://alt.textdrive.com/lua/
5 -- Creation Date:       January 30, 2007
6 -- Legal:               Copyright (C) 2007 Raphaël Szwarc
7 --                      Under the terms of the MIT License
8 --                      http://www.opensource.org/licenses/mit-license.html
9 --------------------------------------------------------------------------------
10
11 -- import dependencies
12 local HTTP = require( 'HTTP' )
13 local HTTPExtra = require( 'HTTPExtra' )
14 local Template = require( 'Template' )
15 local URL = require( 'URL' )
16 local URLPath = require( 'URLPath' )
17 local WikiDate = require( 'WikiDate' )
18 local WikiService = require( 'WikiService' )
19
20 local BaseLink = WikiService.BaseLink
21 local DateLink = WikiService.DateLink
22 local FeedLink = WikiService.FeedLink
23 local IndexLink = WikiService.IndexLink
24
25 local ContentIterator = WikiService.ContentIterator
26 local Description = WikiService.Description
27 local Encode = WikiService.Encode
28 local FormatDate = WikiService.FormatDate
29 local GetType = WikiService.GetType
30 local HTML = WikiService.HTML
31 local Path = WikiService.Path
32 local Tag = WikiService.Tag
33
34 local os = require( 'os' )
35
36 local getmetatable = getmetatable
37 local setmetatable = setmetatable
38 local require = require
39 local tonumber = tonumber
40 local tostring = tostring
41
42 --------------------------------------------------------------------------------
43 -- WikiDateService
44 --------------------------------------------------------------------------------
45
46 module( 'WikiDateService' )
47 _VERSION = '1.0'
48
49 local self = setmetatable( _M, {} )
50 local meta = getmetatable( self )
51
52 --------------------------------------------------------------------------------
53 -- Utilities
54 --------------------------------------------------------------------------------
55
56 local function Title( aYear, aMonth, aDay )
57     local aTime = os.time( { year = aYear or 1, month = aMonth or 1, day = aDay or 1 } )
58     local aFormat = nil
59    
60     if aDay then
61         return FormatDate( aTime )
62     elseif aMonth then
63         aFormat = '!%B %Y'
64     else
65         aFormat = '!%Y'
66     end
67    
68     return os.date( aFormat, aTime )
69 end
70
71 local function PathArgument( self )
72     if self.day then
73         local WikiDateService = require( 'WikiDateService' )
74         local aMonthService = WikiDateService( self.year, self.month )
75         local aYearService = WikiDateService( self.year )
76        
77         aMonthService.path = self.path()
78         aYearService.path = aMonthService.path()
79        
80         return self, aMonthService, aYearService
81     end
82
83     if self.month then
84         local WikiDateService = require( 'WikiDateService' )
85         local aYearService = WikiDateService( self.year )
86        
87         aYearService.path = self.path()
88        
89         return self, aYearService
90     end
91    
92     return self
93 end
94
95 --------------------------------------------------------------------------------
96 -- DAV Utilities
97 --------------------------------------------------------------------------------
98
99 local function DAVYearIterator( aCurrentYear )
100     local anIterator = WikiDate()
101    
102     return function()
103         local aYear, aFile = anIterator()
104        
105         while aCurrentYear and aCurrentYear ~= aYear and aYear do
106             aYear, aFile = anIterator()
107         end
108        
109         if aYear then
110             local aName = ( '%04d' ):format( aYear )
111             local aModification = aFile.modification
112             local aResource = { name = aName, mode = 'directory', modification = aModification, size = 0 }
113            
114             return aResource
115         end
116     end
117 end
118
119 local function DAVMonthIterator( aYear )
120     local aDate = { year = aYear }
121     local anIterator = WikiDate( aDate )
122    
123     return function()
124         local aMonth, aFile = anIterator()
125        
126         if aMonth then
127             local aName = ( '%02d' ):format( aMonth )
128             local aModification = aFile.modification
129             local aResource = { name = aName, mode = 'directory', modification = aModification, size = 0 }
130            
131             return aResource
132         end
133     end
134 end
135
136 local function DAVDayIterator( aYear, aMonth )
137     local aDate = { year = aYear, month = aMonth }
138     local anIterator = WikiDate( aDate )
139    
140     return function()
141         local aDay, aFile = anIterator()
142        
143         if aDay then
144             local aName = ( '%02d' ):format( aDay )
145             local aModification = aFile.modification
146             local aResource = { name = aName, mode = 'directory', modification = aModification, size = 0 }
147            
148             return aResource
149         end
150     end
151 end
152
153 local function DAVDateIterator( aYear, aMonth, aDay )
154     local WikiContent = require( 'WikiContent' )
155     local aDate = { year = aYear, month = aMonth, day = aDay }
156     local anIterator = WikiDate[ aDate ]
157    
158     return function()
159         local aName = anIterator()
160        
161         if aName then
162             local aContent = WikiContent( aName )
163             local aModification = aContent.modification
164             local aResource = { name = aName, mode = 'directory', modification = aModification, size = 0 }
165            
166             return aResource
167         end
168     end
169 end
170
171 local function DAVIterator( aDate )
172     local aType = aDate.type
173    
174     if aType == 'year' then
175         return DAVMonthIterator( aDate.year )
176     elseif aType == 'month' then
177         return DAVDayIterator( aDate.year, aDate.month )
178     elseif aType == 'day' then
179         return DAVDateIterator( aDate.year, aDate.month, aDate.day )
180     end
181    
182     return DAVYearIterator()
183 end
184
185 local function DAVResource( aDate )
186     local anIterator = DAVIterator( aDate )
187     local aModification = WikiDate[ 'modification' ]
188     local aResource = { iterator = anIterator, mode = 'directory', modification = aModification, size = 0 }
189    
190     return aResource
191 end
192
193 --------------------------------------------------------------------------------
194 -- Service methods
195 --------------------------------------------------------------------------------
196
197 self.toURL = function( aService, anObject )
198     local aPath = URLPath()
199    
200     aPath.absolute = true
201
202     if anObject.year then
203         aPath[ #aPath + 1 ] = ( '%04d' ):format( anObject.year )
204     end
205    
206     if anObject.month then
207         aPath[ #aPath + 1 ] = ( '%02d' ):format( anObject.month )
208     end
209    
210     if anObject.day then
211         aPath[ #aPath + 1 ] = ( '%02d' ):format( anObject.day )
212     end
213    
214     return URL( aService.prefix .. aPath )
215 end
216
217 self.toObject = function( aService, aURL )
218     local aPath = aURL.path
219     local aYear = tonumber( aPath[ 2 ] )
220     local aMonth = tonumber( aPath[ 3 ] )
221     local aDay = tonumber( aPath[ 4 ] )
222     local WikiDateService = require( 'WikiDateService' )
223     local aService = WikiDateService( aYear, aMonth, aDay )   
224
225     return aService
226 end
227
228 function self:getHtml()
229     local WikiDateNavigation = require( 'WikiDateNavigation' )
230     local aLayoutTemplate = Template[ 'WikiLayout.txt' ]
231     local aTemplate = Template[ 'WikiDateService.txt' ]
232     local aNameTemplate = aTemplate[ 'names' ]
233     local anIterator, aCount, hasMore = ContentIterator( WikiDate[ self ] )
234     local aTitle = Title( self.year, self.month, self.day )
235    
236     aTemplate[ 'names' ] = nil
237     aTemplate[ 'description' ] = Encode( Description( aCount, hasMore ) )
238     aTemplate[ 'navigation' ] = WikiDateNavigation( self )
239    
240     if aCount == 0 then
241         HTTP.response.status.code = 404
242         HTTP.response.status.description = 'Not Found'
243     end
244    
245     for aContent, aURL in anIterator do
246         local aNameTemplate = aTemplate[ 'names' ]
247        
248         aNameTemplate[ 'href' ] = Encode( aURL.path )
249         aNameTemplate[ 'name' ] = Encode( aContent.title )
250         aNameTemplate[ 'tag' ] = Tag( aContent.modification, true )
251        
252         aTemplate[ 'names' ] = aNameTemplate
253     end
254
255     aTemplate[ 'title' ] = Encode( aTitle )
256    
257     aLayoutTemplate[ 'baseLink' ] = Encode( BaseLink() )
258     aLayoutTemplate[ 'indexLink' ] = Encode( IndexLink() )
259     aLayoutTemplate[ 'dateLink' ] = Encode( DateLink( self.year, self.month, self.day ) )
260     aLayoutTemplate[ 'feedLink' ] = FeedLink( self, aCount )
261     aLayoutTemplate[ 'path' ] = Path( PathArgument( self ) )
262     aLayoutTemplate[ 'query' ] = nil
263     aLayoutTemplate[ 'robot' ] = 'noindex'
264     aLayoutTemplate[ 'title' ] = Encode( aTitle .. ' — Date' )
265     aLayoutTemplate[ 'content' ] = aTemplate
266    
267     return tostring( aLayoutTemplate )
268 end
269
270 function self:getXml()
271     local WikiFeed = require( 'WikiFeed' )
272     local WikiIndex = require( 'WikiIndex' )
273     local anIterator = ContentIterator( WikiDate[ self ] )
274     local aGenerator = HTML
275     local aTitle = Title( self.year, self.month, self.day ) .. ' — Date'
276     local aContext = { title = aTitle, link = HTTP.request.url, creation = WikiIndex[ 'creation' ] }
277            
278     HTTP.response.header[ 'content-type' ] = 'application/atom+xml; charset=utf-8'
279
280     return tostring( WikiFeed( anIterator, aGenerator, aContext ) )
281 end
282
283 function self:get( aType )
284     if self.year then
285         return GetType( self, aType )
286     end
287    
288     return nil, HTTP.request.url.path( os.date( '!*t' ).year )
289 end
290
291 --------------------------------------------------------------------------------
292 -- DAV service methods
293 --------------------------------------------------------------------------------
294
295 function self:options()
296     HTTP.response.header[ 'allow' ] = 'GET, HEAD, OPTIONS, PROPFIND'
297     HTTP.response.header[ 'content-type' ] = 'text/plain'
298    
299     return HTTP.response.header[ 'allow' ]
300 end
301
302 function self:propfind()
303     local WikiDAV = require( 'WikiDAV' )
304     local aResource = DAVResource( self )
305
306     return WikiDAV( aResource ):propfind()
307 end
308
309 --------------------------------------------------------------------------------
310 -- Metamethods
311 --------------------------------------------------------------------------------
312
313 function meta:__call( aYear, aMonth, aDay )
314     local aService = { year = aYear, month = aMonth, day = aDay }
315    
316     if aYear then
317         aService.type = 'year'
318     end
319
320     if aMonth then
321         aService.type = 'month'
322     end
323
324     if aDay then
325         aService.type = 'day'
326     end
327
328     if aYear then
329         local aTime = os.time( { year = aYear, month = aMonth or 1, day = aDay or 1 } )
330         local aDate = os.date( '!*t', aTime )
331        
332         if aYear and aYear ~= aDate.year then
333             aService.year = aDate.year
334         end
335        
336         if aMonth and aMonth ~= aDate.month then
337             aService.month = aDate.month
338         end
339        
340         if aDay and aDay ~= aDate.day then
341             aService.day = aDate.day
342         end
343     end
344    
345     setmetatable( aService, self )
346    
347     return aService
348 end
349
350 function meta:__concat( aValue )
351     return tostring( self ) .. tostring( aValue )
352 end
353
354 function meta:__tostring()
355     return ( '%s/%s' ):format( self._NAME, self._VERSION )
356 end
357
358 function self:__index( aKey )
359     local aValue = getmetatable( self )[ aKey ]
360
361     if not aValue and aKey:find( '^get.+' ) then
362         local WikiContent = require( 'WikiContent' )
363         local aName = aKey:match( '^get(.+)$' )
364         local aContent = WikiContent( aName )
365        
366         if aContent and aContent.exists then
367             local WikiContentService = require( 'WikiContentService' )
368             local aService = WikiContentService( aContent )
369                
370             return function()           
371                 return aService
372             end
373         end
374     end
375
376     self[ aKey ] = aValue
377    
378     return aValue
379 end
380
381 function self:__concat( aValue )
382     return tostring( self ) .. tostring( aValue )
383 end
384
385 function self:__tostring()
386     return Title( self.year, self.month, self.day )
387 end
Note: See TracBrowser for help on using the browser.