source: HTTP/WikiService.lua @ 1797

Revision 1593, 13.0 KB checked in by rsz, 2 years ago (diff)

cleanup

Line 
1--------------------------------------------------------------------------------
2-- Title:               WikiService.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
12local HTTP = require( 'HTTP' )
13
14local os = require( 'os' )
15local table = require( 'table' )
16
17local getmetatable = getmetatable
18local next = next
19local pairs = pairs
20local require = require
21local select = select
22local setmetatable = setmetatable
23local tonumber = tonumber
24local tostring = tostring
25local type = type
26
27--------------------------------------------------------------------------------
28-- WikiService
29--------------------------------------------------------------------------------
30
31module( 'WikiService' )
32_VERSION = '1.0'
33
34local self = setmetatable( _M, {} )
35local meta = getmetatable( self )
36
37--------------------------------------------------------------------------------
38-- Utilities
39--------------------------------------------------------------------------------
40
41function Capitalize( aValue )
42    return ( tostring( aValue or '' ):lower():gsub( '(%l)([%w_\']*)', function( first, second ) return first:upper() .. second end ) )
43end
44
45function Encode( aValue )
46    local anEncoder = function( aValue ) 
47        return ( '&#%02d;' ):format( aValue:byte() ) 
48    end
49   
50    return ( tostring( aValue or '' ):gsub( '([<>&\'"])', anEncoder ) )
51end
52
53function Trim( aValue )
54    return ( tostring( aValue or '' ):gsub( '^[%c%s]+', '' ):gsub( '[%s%c]+$', '' ) )
55end
56
57--------------------------------------------------------------------------------
58-- Name utilities
59--------------------------------------------------------------------------------
60
61function Names( anIterator )
62    local NaturalComparator = require( 'NaturalComparator' )
63    local WikiContent = require( 'WikiContent' )
64    local aMap = {}
65    local aList = {}
66    local anIndex = 1
67    local hasMore = false
68   
69    for aName in anIterator do
70        aMap[ aName ] = true
71   
72        anIndex = anIndex + 1
73
74        if anIndex == 1000 then
75            hasMore = true
76            break
77        end
78    end
79   
80    anIndex = 1
81   
82    for aName, aValue in pairs( aMap ) do
83        aList[ anIndex ] = aName
84        anIndex = anIndex + 1
85    end
86   
87    table.sort( aList, NaturalComparator() )
88   
89    return aList, hasMore
90end
91
92function NameIterator( someNames )
93    local HTTPExtra = require( 'HTTPExtra' )
94    local HTTPService = require( 'HTTPService' )
95    local WikiContent = require( 'WikiContent' )
96    local WikiContentService = require( 'WikiContentService' )
97    local aCount = #someNames
98    local anIndex = 1
99   
100    return function()
101        if anIndex <= aCount then
102            local aName = someNames[ anIndex ]
103            local aContent = WikiContent( aName )
104            local aService = WikiContentService( aContent )
105            local aURL = HTTPService[ aService ]
106           
107            anIndex = anIndex + 1
108           
109            return aContent, aURL
110        end
111    end
112end
113
114function ContentIterator( anIterator )
115    local someNames, hasMore = Names( anIterator )
116   
117    return NameIterator( someNames ), #someNames, hasMore
118end
119
120function Description( aCount, hasMore )
121    aCount = aCount or 0
122   
123    if aCount == 0 then
124        return 'no item'
125    elseif aCount == 1 then
126        return '1 item'
127    else
128        local aDescription = ( '%d items' ):format( aCount )
129       
130        if hasMore then
131            aDescription = 'over ' .. aDescription
132        end
133       
134        return aDescription
135    end
136end
137
138--------------------------------------------------------------------------------
139-- Format utilities
140--------------------------------------------------------------------------------
141
142local suffixes = { 'st', 'nd', 'rd' }
143
144local function Suffix( aNumber )
145    local aSuffix = 'th'
146   
147    if aNumber ~= 11 and aNumber ~= 12 and aNumber ~= 13 then
148        if aNumber > 9 then
149            aNumber = aNumber % 10   
150        end
151       
152        aSuffix = suffixes[ aNumber ] or aSuffix
153    end
154   
155    return aSuffix
156end
157
158local function FormatDay( aDay )
159    local aDay = tonumber( aDay )
160    local aSuffix = Suffix( aDay )
161   
162    return ' ' .. aDay .. aSuffix .. ' '
163end
164
165function FormatDate( aTime )
166    return os.date( '!%A, %B %d %Y', aTime ):gsub( '%s(%d%d)%s', FormatDay )
167end
168
169function FormatTime( aTime )
170    return os.date( '!%I:%M %p', aTime ):gsub( '^0(%d)', '%1' )
171end
172
173function FormatDateTime( aTime )
174    return ( '%s at %s' ):format( FormatDate( aTime), FormatTime( aTime ) )
175end
176
177function Today( aModification )
178    local aModification = aModification or 0
179    local aDate = os.date( '!*t' )
180    local aStartDate = { year = aDate.year, month = aDate.month, day = aDate.day, hour = 0, min = 0, sec = 0, isdst = aDate.isdst }
181    local aStartTime = os.time( aStartDate )
182    local anEndDate = { year = aDate.year, month = aDate.month, day = aDate.day, hour = 23, min = 59, sec = 59, isdst = aDate.isdst }
183    local anEndTime = os.time( anEndDate )
184    local isToday = aModification >= aStartTime and aModification <= anEndTime
185
186    return isToday, aStartTime, anEndTime
187end
188
189function Yesterday( aModification )
190    local aModification = aModification or 0
191    local _, aStartTime, anEndTime = Today( aModification )
192    local aStartTime = aStartTime - 86400
193    local anEndTime = anEndTime - 86400
194    local isYesterday = aModification >= aStartTime and aModification <= anEndTime
195
196    return isYesterday, aStartTime, anEndTime
197end
198
199function ThisWeek( aModification )
200    local aModification = aModification or 0
201    local _, aStartTime, anEndTime = Today( aModification )
202    local aStartTime = aStartTime - ( 7 * 86400 )
203    local isThisWeek = aModification >= aStartTime and aModification <= anEndTime
204   
205    return isThisWeek, aStartTime, anEndTime
206end
207
208--------------------------------------------------------------------------------
209-- Content utilities
210--------------------------------------------------------------------------------
211
212function BaseLink()
213    return HTTP.request.url + '/'
214end
215
216function FeedLink( aService, aCount )
217    if aService and aCount and aCount > 0 then
218        local aQuery = HTTP.request.url.query
219        local aLink = tostring( aService.path )
220       
221        if not aLink:find( '%.xml$' ) then
222            aLink = aLink .. '.xml'
223        end
224       
225        aLink = Encode( aLink )
226       
227        if aQuery and next( aQuery ) then
228            aLink = aLink .. '?' .. aQuery
229        end
230       
231        return ( '<link rel=\'alternate\' type=\'application/atom+xml\' href=\'%s\'/>' ):format( aLink )
232    end
233end
234
235function IndexLink( aPrefix )
236    local HTTPExtra = require( 'HTTPExtra' )
237    local HTTPService = require( 'HTTPService' )
238    local WikiIndexService = require( 'WikiIndexService' )
239    local aFirst, aSecond = ( aPrefix or '' ):match( '^(%w)(%w?)' )
240    local aService = WikiIndexService( aFirst, aSecond )
241    local aURL = HTTPService[ aService ]
242   
243    return aURL.path
244end
245
246function DateLink( aYear, aMonth, aDay )
247    local HTTPExtra = require( 'HTTPExtra' )
248    local HTTPService = require( 'HTTPService' )
249    local WikiDateService = require( 'WikiDateService' )
250    local aService = WikiDateService( aYear, aMonth, aDay )
251    local aURL = HTTPService[ aService ]
252   
253    return aURL.path
254end
255
256function Path( aService, ... )
257    local WikiPath = require( 'WikiPath' )
258    local aPath = WikiPath()
259    local aList = {}
260   
261    aList[ #aList + 1 ] = { href = aService.path, title = tostring( aService ) }
262    aService = aService.parent
263   
264    for anIndex = 1, select( '#', ... ) do
265        local aService = select( anIndex, ... )
266       
267        if aService then
268            aList[ #aList + 1 ] = { href = aService.path, title = tostring( aService ) }
269        end
270    end
271
272    while aService do
273        aList[ #aList + 1 ] = { href = aService.path, title = tostring( aService ) }
274        aService = aService.parent
275    end
276
277    for anIndex = #aList, 1, -1 do
278        aPath[ #aPath + 1 ] = aList[ anIndex ]
279    end
280   
281    return aPath
282end
283
284function Render( aText )
285    if aText then
286        local markdown = require( 'markdown' )
287
288        aText = aText:gsub( '(`?)(<.->)(`?)', '`%2`' )
289        aText = markdown( aText )
290        aText = aText:gsub( '(`)(&lt;.-&gt;)(`)', '%2' )
291       
292        return aText
293    end
294end
295
296function HTML( aContent )
297    --local Cache = require( 'Cache' )
298    --local File = require( 'File' )
299    --local aTime = aContent.modification
300    --local aPath = aContent.directory.path
301    --local aFile = File( aPath, 'data.html' )
302    --local aContent = function()
303    --    return Render( aContent.text )
304    --end
305    --
306    --return Cache( aFile.path, aContent, aTime )
307   
308    return Render( aContent.text )
309end
310
311function Text( aContent )
312    local aText = HTML( aContent )
313   
314    if aText then
315        aText = aText:gsub( '(<.->)', '' )
316    end
317   
318    return aText
319end
320
321function GetType( self, aType )
322    local aMethod = 'get' .. Capitalize( aType or 'html' )
323   
324    if type( self[ aMethod ] ) == 'function' then
325        return self[ aMethod ]( self )
326    end
327end
328
329function Tag( aModification, isSmall )
330    local aDay = os.date( '!%A', aModification )
331    local anHour = tonumber( os.date( '!%I', aModification ) )
332    local aMeridian = os.date( '!%p', aModification )
333    local aTag = nil
334    local aLabel = nil
335   
336    if Today( aModification ) then
337        aLabel = ( 'Edited today around %d %s' ):format( anHour, aMeridian )
338        aTag = 1
339    elseif Yesterday( aModification ) then
340        aLabel = ( 'Edited yesterday around %d %s' ):format( anHour, aMeridian )
341        aTag = 2
342    elseif ThisWeek( aModification ) then
343        aLabel = ( 'Edited last %s around %d %s' ):format( aDay, anHour, aMeridian )
344        aTag = 3
345    end
346   
347    if aTag and aLabel then
348        local aType = 'tag'
349       
350        if isSmall then
351            aType = 'bullet'
352        end
353   
354        return ( '<img src=\'/etc/%s%d.png\' alt=\'tag\' title=\'%s\' class=\'navigation\' style=\'vertical-align: text-bottom;\' height=\'16\' width=\'16\'/>' ):format( aType, aTag, aLabel )
355    end
356end
357
358local function Name( aName, anAddress )
359    local WikiContent = require( 'WikiContent' )
360    local aName = aName or ''
361   
362    if aName == 'anonymous' then
363        local IPMnemonic = require( 'IPMnemonic' )
364       
365        aName = IPMnemonic[ anAddress ] or aName
366    end
367   
368    aName = WikiContent[ aName ] or ''
369    aName = aName:gsub( '%W', ' ' )
370    aName = Capitalize( aName )
371   
372    return aName
373end
374
375local function Location( aContent, anAddress )
376    local aLocation = aContent.location
377
378    if not aLocation then
379        local IPLocation = require( 'IPLocation' )
380       
381        aLocation = IPLocation[ anAddress ]
382        aContent.location = aLocation
383    end
384
385    if aLocation then
386        local aBuffer = {}
387       
388        if aLocation.city and aLocation.city ~= '-' then
389            aBuffer[ #aBuffer + 1 ] = aLocation.city
390        elseif aLocation.region and aLocation.region ~= '-' then
391            aBuffer[ #aBuffer + 1 ] = aLocation.region
392        end
393       
394        if aLocation.country and aLocation.country ~= '-' then
395            aBuffer[ #aBuffer + 1 ] = aLocation.country
396        end
397       
398        aLocation = table.concat( aBuffer, ', ' )
399    end
400
401    return aLocation
402end 
403
404function By( aContent, hasTitle )
405    local URL = require( 'URL' )
406    local HTTPService = require( 'HTTPService' )
407    local WikiContent = require( 'WikiContent' )
408    local WikiContentService = require( 'WikiContentService' )
409    local aURL = URL( aContent.by )
410    local anUser = aURL.user
411    local anAddress = aURL.password
412    local aHost = aURL.host
413    local aName = Name( anUser, anAddress )
414    local aNameContent = WikiContent( aName )
415    local aNameService = WikiContentService( aNameContent )
416    local aNameURL = HTTPService[ aNameService ]
417    local aLocation = Location( aContent, anAddress )
418    local aBuffer = {}
419   
420    if hasTitle then
421        aBuffer[ #aBuffer + 1 ] = ( '<a href=\'%s\' title=\'%s\'>%s</a>' ):format( Encode( aNameURL ), Encode( anAddress or '?' ), Encode( aName ) )
422    else
423        aBuffer[ #aBuffer + 1 ] = Encode( aName )
424    end
425   
426    if hasTitle and aLocation then
427        aBuffer[ #aBuffer + 1 ] = ( ', <span title=\'%s\'>%s</span>' ):format( Encode( aHost or '?' ), Encode( aLocation ) )
428    elseif aLocation then
429        aBuffer[ #aBuffer + 1 ] = ( ', %s' ):format( aLocation )
430    end
431   
432    return table.concat( aBuffer )
433end
434
435--------------------------------------------------------------------------------
436-- Metamethods
437--------------------------------------------------------------------------------
438
439function meta:__concat( aValue )
440    return tostring( self ) .. tostring( aValue )
441end
442
443function meta:__tostring()
444    return ( '%s/%s' ):format( self._NAME, self._VERSION )
445end
Note: See TracBrowser for help on using the repository browser.