Version 129

This commit is contained in:
Hydrus 2014-09-10 17:37:38 -05:00
parent 48056815ca
commit 29eb631859
17 changed files with 429 additions and 912 deletions

View File

@ -8,6 +8,18 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 128</h3></li>
<ul>
<li>fixed a typo in launching the ratings dialog</li>
<li>did some important code cleanup re a common ambigious variable name</li>
<li>improved serverside account tracking in a way that will help future user management clientside too</li>
<li>improved serverside session code a bit more</li>
<li>improved general serverside login</li>
<li>improved serverside access key verification</li>
<li>aligned server db update code with the client's only-update-up-to-50-versions rule</li>
<li>fixed some buggy repository test code</li>
<li>fixed some buggy local booru test code</li>
</ul>
<li><h3>version 128</h3></li>
<ul>
<li>fixed right click on thumbnail error</li>

View File

@ -1144,7 +1144,7 @@ class DialogInputCustomFilterAction( Dialog ):
class DialogInputFileSystemPredicate( Dialog ):
def __init__( self, parent, type ):
def __init__( self, parent, predicate_type ):
def Age():
@ -1919,7 +1919,7 @@ class DialogInputFileSystemPredicate( Dialog ):
system_predicates = HC.options[ 'file_system_predicates' ]
self._type = type
self._type = predicate_type
if self._type == HC.SYSTEM_PREDICATE_TYPE_AGE: Age()
elif self._type == HC.SYSTEM_PREDICATE_TYPE_DURATION: Duration()
@ -2791,7 +2791,7 @@ class DialogInputLocalFiles( Dialog ):
class DialogInputMessageSystemPredicate( Dialog ):
def __init__( self, parent, type ):
def __init__( self, parent, predicate_type ):
def Age():
@ -3020,7 +3020,7 @@ class DialogInputMessageSystemPredicate( Dialog ):
wx.CallAfter( self._ok.SetFocus )
self._type = type
self._type = predicate_type
if self._type == 'system:age': Age()
elif self._type == 'system:started_by': StartedBy()
@ -3288,7 +3288,7 @@ class DialogInputNewFormField( Dialog ):
self._name.SetValue( name )
for temp_type in CC.FIELDS: self._type.Append( CC.field_string_lookup[ temp_type ], temp_type )
self._type.Select( type )
self._type.Select( field_type )
self._default.SetValue( default )
@ -3332,8 +3332,8 @@ class DialogInputNewFormField( Dialog ):
Dialog.__init__( self, parent, 'configure form field' )
if form_field is None: ( name, type, default, editable ) = ( '', CC.FIELD_TEXT, '', True )
else: ( name, type, default, editable ) = form_field
if form_field is None: ( name, field_type, default, editable ) = ( '', CC.FIELD_TEXT, '', True )
else: ( name, field_type, default, editable ) = form_field
InitialiseControls()
@ -3348,13 +3348,13 @@ class DialogInputNewFormField( Dialog ):
name = self._name.GetValue()
type = self._type.GetClientData( self._type.GetSelection() )
field_type = self._type.GetClientData( self._type.GetSelection() )
default = self._default.GetValue()
editable = self._editable.GetValue()
return ( name, type, default, editable )
return ( name, field_type, default, editable )
class DialogInputShortcut( Dialog ):
@ -3929,10 +3929,10 @@ class DialogPageChooser( Dialog ):
elif entry_type == 'page_import_booru': button.SetLabel( 'booru' )
elif entry_type == 'page_import_gallery':
( name, type ) = obj
( name, gallery_type ) = obj
if type is None: button.SetLabel( name )
else: button.SetLabel( name + ' by ' + type )
if gallery_type is None: button.SetLabel( name )
else: button.SetLabel( name + ' by ' + gallery_type )
elif entry_type == 'page_import_thread_watcher': button.SetLabel( 'thread watcher' )
elif entry_type == 'page_import_url': button.SetLabel( 'url' )

View File

@ -2198,9 +2198,9 @@ class DialogManageImageboards( ClientGUIDialogs.Dialog ):
#
for ( name, type, default, editable ) in form_fields:
for ( name, field_type, default, editable ) in form_fields:
self._form_fields.Append( ( name, CC.field_string_lookup[ type ], HC.u( default ), HC.u( editable ) ), ( name, type, default, editable ) )
self._form_fields.Append( ( name, CC.field_string_lookup[ field_type ], HC.u( default ), HC.u( editable ) ), ( name, field_type, default, editable ) )
#
@ -2326,7 +2326,7 @@ class DialogManageImageboards( ClientGUIDialogs.Dialog ):
if dlg.ShowModal() == wx.ID_OK:
( name, type, default, editable ) = dlg.GetFormField()
( name, field_type, default, editable ) = dlg.GetFormField()
if name in [ form_field[0] for form_field in self._form_fields.GetClientData() ]:
@ -2337,7 +2337,7 @@ class DialogManageImageboards( ClientGUIDialogs.Dialog ):
return
self._form_fields.Append( ( name, CC.field_string_lookup[ type ], HC.u( default ), HC.u( editable ) ), ( name, type, default, editable ) )
self._form_fields.Append( ( name, CC.field_string_lookup[ field_type ], HC.u( default ), HC.u( editable ) ), ( name, field_type, default, editable ) )
@ -2371,9 +2371,9 @@ class DialogManageImageboards( ClientGUIDialogs.Dialog ):
for index in indices:
( name, type, default, editable ) = self._form_fields.GetClientData( index )
( name, field_type, default, editable ) = self._form_fields.GetClientData( index )
form_field = ( name, type, default, editable )
form_field = ( name, field_type, default, editable )
with ClientGUIDialogs.DialogInputNewFormField( self, form_field ) as dlg:
@ -2381,14 +2381,14 @@ class DialogManageImageboards( ClientGUIDialogs.Dialog ):
old_name = name
( name, type, default, editable ) = dlg.GetFormField()
( name, field_type, default, editable ) = dlg.GetFormField()
if old_name != name:
if name in [ form_field[0] for form_field in self._form_fields.GetClientData() ]: raise Exception( 'You already have a form field called ' + name + '; delete or edit that one first' )
self._form_fields.UpdateRow( index, ( name, CC.field_string_lookup[ type ], HC.u( default ), HC.u( editable ) ), ( name, type, default, editable ) )
self._form_fields.UpdateRow( index, ( name, CC.field_string_lookup[ field_type ], HC.u( default ), HC.u( editable ) ), ( name, field_type, default, editable ) )
@ -2434,9 +2434,9 @@ class DialogManageImageboards( ClientGUIDialogs.Dialog ):
self._form_fields.setResizeColumn( 3 ) # default
for ( name, type, default, editable ) in form_fields:
for ( name, field_type, default, editable ) in form_fields:
self._form_fields.Append( ( name, CC.field_string_lookup[ type ], HC.u( default ), HC.u( editable ) ), ( name, type, default, editable ) )
self._form_fields.Append( ( name, CC.field_string_lookup[ field_type ], HC.u( default ), HC.u( editable ) ), ( name, field_type, default, editable ) )
if CC.RESTRICTION_MIN_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MIN_RESOLUTION ]
@ -2497,13 +2497,13 @@ class DialogManageImportFolders( ClientGUIDialogs.Dialog ):
for ( path, details ) in self._original_paths_to_details.items():
type = details[ 'type' ]
import_type = details[ 'type' ]
check_period = details[ 'check_period' ]
local_tag = details[ 'local_tag' ]
( pretty_type, pretty_check_period, pretty_local_tag ) = self._GetPrettyVariables( type, check_period, local_tag )
( pretty_type, pretty_check_period, pretty_local_tag ) = self._GetPrettyVariables( import_type, check_period, local_tag )
self._import_folders.Append( ( path, pretty_type, pretty_check_period, pretty_local_tag ), ( path, type, check_period, local_tag ) )
self._import_folders.Append( ( path, pretty_type, pretty_check_period, pretty_local_tag ), ( path, import_type, check_period, local_tag ) )
@ -2553,21 +2553,21 @@ class DialogManageImportFolders( ClientGUIDialogs.Dialog ):
all_existing_client_data = self._import_folders.GetClientData()
if path not in ( existing_path for ( existing_path, type, check_period, local_tag ) in all_existing_client_data ):
if path not in ( existing_path for ( existing_path, import_type, check_period, local_tag ) in all_existing_client_data ):
type = HC.IMPORT_FOLDER_TYPE_SYNCHRONISE
import_type = HC.IMPORT_FOLDER_TYPE_SYNCHRONISE
check_period = 15 * 60
local_tag = None
with DialogManageImportFoldersEdit( self, path, type, check_period, local_tag ) as dlg:
with DialogManageImportFoldersEdit( self, path, import_type, check_period, local_tag ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
( path, type, check_period, local_tag ) = dlg.GetInfo()
( path, import_type, check_period, local_tag ) = dlg.GetInfo()
( pretty_type, pretty_check_period, pretty_local_tag ) = self._GetPrettyVariables( type, check_period, local_tag )
( pretty_type, pretty_check_period, pretty_local_tag ) = self._GetPrettyVariables( import_type, check_period, local_tag )
self._import_folders.Append( ( path, pretty_type, pretty_check_period, pretty_local_tag ), ( path, type, check_period, local_tag ) )
self._import_folders.Append( ( path, pretty_type, pretty_check_period, pretty_local_tag ), ( path, import_type, check_period, local_tag ) )
@ -2581,10 +2581,10 @@ class DialogManageImportFolders( ClientGUIDialogs.Dialog ):
def _GetPrettyVariables( self, type, check_period, local_tag ):
def _GetPrettyVariables( self, import_type, check_period, local_tag ):
if type == HC.IMPORT_FOLDER_TYPE_DELETE: pretty_type = 'delete'
elif type == HC.IMPORT_FOLDER_TYPE_SYNCHRONISE: pretty_type = 'synchronise'
if import_type == HC.IMPORT_FOLDER_TYPE_DELETE: pretty_type = 'delete'
elif import_type == HC.IMPORT_FOLDER_TYPE_SYNCHRONISE: pretty_type = 'synchronise'
pretty_check_period = HC.u( check_period / 60 ) + ' minutes'
@ -2615,17 +2615,17 @@ class DialogManageImportFolders( ClientGUIDialogs.Dialog ):
for index in indices:
( path, type, check_period, local_tag ) = self._import_folders.GetClientData( index )
( path, import_type, check_period, local_tag ) = self._import_folders.GetClientData( index )
with DialogManageImportFoldersEdit( self, path, type, check_period, local_tag ) as dlg:
with DialogManageImportFoldersEdit( self, path, import_type, check_period, local_tag ) as dlg:
if dlg.ShowModal() == wx.ID_OK:
( path, type, check_period, local_tag ) = dlg.GetInfo()
( path, import_type, check_period, local_tag ) = dlg.GetInfo()
( pretty_type, pretty_check_period, pretty_local_tag ) = self._GetPrettyVariables( type, check_period, local_tag )
( pretty_type, pretty_check_period, pretty_local_tag ) = self._GetPrettyVariables( import_type, check_period, local_tag )
self._import_folders.UpdateRow( index, ( path, pretty_type, pretty_check_period, pretty_local_tag ), ( path, type, check_period, local_tag ) )
self._import_folders.UpdateRow( index, ( path, pretty_type, pretty_check_period, pretty_local_tag ), ( path, import_type, check_period, local_tag ) )
@ -2639,12 +2639,12 @@ class DialogManageImportFolders( ClientGUIDialogs.Dialog ):
paths = set()
for ( path, type, check_period, local_tag ) in client_data:
for ( path, import_type, check_period, local_tag ) in client_data:
if path in self._original_paths_to_details: details = self._original_paths_to_details[ path ]
else: details = { 'last_checked' : 0, 'cached_imported_paths' : set(), 'failed_imported_paths' : set() }
details[ 'type' ] = type
details[ 'type' ] = import_type
details[ 'check_period' ] = check_period
details[ 'local_tag' ] = local_tag
@ -2664,7 +2664,7 @@ class DialogManageImportFolders( ClientGUIDialogs.Dialog ):
class DialogManageImportFoldersEdit( ClientGUIDialogs.Dialog ):
def __init__( self, parent, path, type, check_period, local_tag ):
def __init__( self, parent, path, import_type, check_period, local_tag ):
def InitialiseControls():
@ -2710,7 +2710,7 @@ synchronise - try to import all new files in folder'''
self._path.SetPath( path )
self._type.Select( type )
self._type.Select( import_type )
self._check_period.SetRange( 3, 180 )
@ -2764,13 +2764,13 @@ synchronise - try to import all new files in folder'''
path = self._path.GetPath()
type = self._type.GetChoice()
import_type = self._type.GetChoice()
check_period = self._check_period.GetValue() * 60
local_tag = self._local_tag.GetValue()
return ( path, type, check_period, local_tag )
return ( path, import_type, check_period, local_tag )
class DialogManageOptions( ClientGUIDialogs.Dialog ):
@ -4092,7 +4092,7 @@ class DialogManageRatings( ClientGUIDialogs.Dialog ):
self._media = media
service_type = service.GetType()
service_type = self._service.GetType()
def InitialiseControls():

View File

@ -49,7 +49,7 @@ FLAGS_MIXED = wx.SizerFlags( 0 ).Border( wx.ALL, 2 ).Align( wx.ALIGN_CENTER_VERT
class CaptchaControl( wx.Panel ):
def __init__( self, parent, type, default ):
def __init__( self, parent, captcha_type, default ):
wx.Panel.__init__( self, parent )
@ -461,13 +461,13 @@ class ManagementPanelDumper( ManagementPanel ):
gridbox.AddGrowableCol( 1, 1 )
for ( name, type, default, editable ) in self._form_fields:
for ( name, field_type, default, editable ) in self._form_fields:
if type in ( CC.FIELD_TEXT, CC.FIELD_THREAD_ID ): field = wx.TextCtrl( self._thread_panel, value = default )
elif type == CC.FIELD_PASSWORD: field = wx.TextCtrl( self._thread_panel, value = default, style = wx.TE_PASSWORD )
if field_type in ( CC.FIELD_TEXT, CC.FIELD_THREAD_ID ): field = wx.TextCtrl( self._thread_panel, value = default )
elif field_type == CC.FIELD_PASSWORD: field = wx.TextCtrl( self._thread_panel, value = default, style = wx.TE_PASSWORD )
else: continue
self._thread_fields[ name ] = ( type, field )
self._thread_fields[ name ] = ( field_type, field )
if editable:
@ -489,19 +489,19 @@ class ManagementPanelDumper( ManagementPanel ):
self._post_info = wx.StaticText( self._post_panel, label = 'no file selected', style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
for ( name, type, default, editable ) in self._form_fields:
for ( name, field_type, default, editable ) in self._form_fields:
if type == CC.FIELD_VERIFICATION_RECAPTCHA:
if field_type == CC.FIELD_VERIFICATION_RECAPTCHA:
if self._have_4chan_pass: continue
field = CaptchaControl( self._post_panel, type, default )
field = CaptchaControl( self._post_panel, field_type, default )
field.Bind( CAPTCHA_FETCH_EVENT, self.EventCaptchaRefresh )
elif type == CC.FIELD_COMMENT: field = Comment( self._post_panel )
elif field_type == CC.FIELD_COMMENT: field = Comment( self._post_panel )
else: continue
self._post_fields[ name ] = ( type, field, default )
self._post_fields[ name ] = ( field_type, field, default )
postbox.AddF( field, FLAGS_EXPAND_PERPENDICULAR )
@ -510,9 +510,9 @@ class ManagementPanelDumper( ManagementPanel ):
gridbox.AddGrowableCol( 1, 1 )
for ( name, type, default, editable ) in self._form_fields:
for ( name, field_type, default, editable ) in self._form_fields:
if type == CC.FIELD_CHECKBOX:
if field_type == CC.FIELD_CHECKBOX:
field = wx.CheckBox( self._post_panel )
@ -520,15 +520,15 @@ class ManagementPanelDumper( ManagementPanel ):
else: continue
self._post_fields[ name ] = ( type, field, default )
self._post_fields[ name ] = ( field_type, field, default )
gridbox.AddF( wx.StaticText( self._post_panel, label = name + ':' ), FLAGS_MIXED )
gridbox.AddF( field, FLAGS_EXPAND_BOTH_WAYS )
for ( name, type, default, editable ) in self._form_fields:
for ( name, field_type, default, editable ) in self._form_fields:
if type == CC.FIELD_FILE: self._file_post_name = name
if field_type == CC.FIELD_FILE: self._file_post_name = name
self._post_panel.AddF( self._post_info, FLAGS_EXPAND_PERPENDICULAR )
@ -571,14 +571,14 @@ class ManagementPanelDumper( ManagementPanel ):
post_field_info = []
for ( name, ( type, field, default ) ) in self._post_fields.items():
for ( name, ( field_type, field, default ) ) in self._post_fields.items():
if type == CC.FIELD_COMMENT:
if field_type == CC.FIELD_COMMENT:
post_field_info.append( ( name, type, ( self._GetInitialComment( media ), '' ) ) )
post_field_info.append( ( name, field_type, ( self._GetInitialComment( media ), '' ) ) )
elif type == CC.FIELD_CHECKBOX: post_field_info.append( ( name, type, default == 'True' ) )
elif type == CC.FIELD_VERIFICATION_RECAPTCHA: post_field_info.append( ( name, type, None ) )
elif field_type == CC.FIELD_CHECKBOX: post_field_info.append( ( name, field_type, default == 'True' ) )
elif field_type == CC.FIELD_VERIFICATION_RECAPTCHA: post_field_info.append( ( name, field_type, None ) )
self._hashes_to_dump_info[ hash ] = ( dump_status_enum, dump_status_string, post_field_info )
@ -608,11 +608,11 @@ class ManagementPanelDumper( ManagementPanel ):
post_field_info = []
for ( name, ( type, field, default ) ) in self._post_fields.items():
for ( name, ( field_type, field, default ) ) in self._post_fields.items():
if type == CC.FIELD_COMMENT: post_field_info.append( ( name, type, field.GetValues() ) )
elif type == CC.FIELD_CHECKBOX: post_field_info.append( ( name, type, field.GetValue() ) )
elif type == CC.FIELD_VERIFICATION_RECAPTCHA: post_field_info.append( ( name, type, field.GetValues() ) )
if field_type == CC.FIELD_COMMENT: post_field_info.append( ( name, field_type, field.GetValues() ) )
elif field_type == CC.FIELD_CHECKBOX: post_field_info.append( ( name, field_type, field.GetValue() ) )
elif field_type == CC.FIELD_VERIFICATION_RECAPTCHA: post_field_info.append( ( name, field_type, field.GetValues() ) )
self._hashes_to_dump_info[ self._current_hash ] = ( dump_status_enum, dump_status_string, post_field_info )
@ -673,9 +673,9 @@ class ManagementPanelDumper( ManagementPanel ):
self._post_info.SetLabel( 'no file selected' )
for ( name, ( type, field, default ) ) in self._post_fields.items():
for ( name, ( field_type, field, default ) ) in self._post_fields.items():
if type == CC.FIELD_CHECKBOX: field.SetValue( False )
if field_type == CC.FIELD_CHECKBOX: field.SetValue( False )
field.Disable()
@ -690,22 +690,22 @@ class ManagementPanelDumper( ManagementPanel ):
self._post_info.SetLabel( HC.u( index + 1 ) + '/' + HC.u( num_files ) + ': ' + dump_status_string )
for ( name, type, value ) in post_field_info:
for ( name, field_type, value ) in post_field_info:
( type, field, default ) = self._post_fields[ name ]
( field_type, field, default ) = self._post_fields[ name ]
if type == CC.FIELD_COMMENT:
if field_type == CC.FIELD_COMMENT:
( initial, append ) = value
field.EnableWithValues( initial, append )
elif type == CC.FIELD_CHECKBOX:
elif field_type == CC.FIELD_CHECKBOX:
field.SetValue( value )
field.Enable()
elif type == CC.FIELD_VERIFICATION_RECAPTCHA:
elif field_type == CC.FIELD_VERIFICATION_RECAPTCHA:
if value is None: field.Enable()
else:
@ -719,9 +719,9 @@ class ManagementPanelDumper( ManagementPanel ):
if dump_status_enum in ( CC.DUMPER_DUMPED_OK, CC.DUMPER_UNRECOVERABLE_ERROR ):
for ( name, ( type, field, default ) ) in self._post_fields.items():
for ( name, ( field_type, field, default ) ) in self._post_fields.items():
if type == CC.FIELD_CHECKBOX: field.SetValue( False )
if field_type == CC.FIELD_CHECKBOX: field.SetValue( False )
field.Disable()
@ -741,9 +741,9 @@ class ManagementPanelDumper( ManagementPanel ):
new_post_field_info = []
for ( name, type, value ) in post_field_info:
for ( name, field_type, value ) in post_field_info:
if type == CC.FIELD_COMMENT:
if field_type == CC.FIELD_COMMENT:
( initial, append ) = value
@ -751,9 +751,9 @@ class ManagementPanelDumper( ManagementPanel ):
initial = self._GetInitialComment( media )
new_post_field_info.append( ( name, type, ( initial, append ) ) )
new_post_field_info.append( ( name, field_type, ( initial, append ) ) )
else: new_post_field_info.append( ( name, type, value ) )
else: new_post_field_info.append( ( name, field_type, value ) )
self._hashes_to_dump_info[ hash ] = ( dump_status_enum, dump_status_string, new_post_field_info )
@ -796,14 +796,14 @@ class ManagementPanelDumper( ManagementPanel ):
new_post_field_info = []
for ( name, type, value ) in post_field_info:
for ( name, field_type, value ) in post_field_info:
if type == CC.FIELD_VERIFICATION_RECAPTCHA: new_post_field_info.append( ( name, type, None ) )
else: new_post_field_info.append( ( name, type, value ) )
if field_type == CC.FIELD_VERIFICATION_RECAPTCHA: new_post_field_info.append( ( name, field_type, None ) )
else: new_post_field_info.append( ( name, field_type, value ) )
if hash == self._current_hash:
( type, field, default ) = self._post_fields[ name ]
( field_type, field, default ) = self._post_fields[ name ]
field.Enable()
@ -900,9 +900,9 @@ class ManagementPanelDumper( ManagementPanel ):
if self._start_button.GetLabel() in ( 'start', 'continue' ):
for ( name, ( type, field ) ) in self._thread_fields.items():
for ( name, ( field_type, field ) ) in self._thread_fields.items():
if type == CC.FIELD_THREAD_ID:
if field_type == CC.FIELD_THREAD_ID:
try: int( field.GetValue() )
except:
@ -926,7 +926,7 @@ class ManagementPanelDumper( ManagementPanel ):
for ( type, field ) in self._thread_fields.values(): field.Disable()
for ( field_type, field ) in self._thread_fields.values(): field.Disable()
self._dumping = True
self._start_button.SetLabel( 'pause' )
@ -937,7 +937,7 @@ class ManagementPanelDumper( ManagementPanel ):
else:
for ( type, field ) in self._thread_fields.values(): field.Enable()
for ( field_type, field ) in self._thread_fields.values(): field.Enable()
self._dumping = False
@ -982,9 +982,9 @@ class ManagementPanelDumper( ManagementPanel ):
new_post_field_info = []
for ( name, type, value ) in post_field_info:
for ( name, field_type, value ) in post_field_info:
if type == CC.FIELD_COMMENT:
if field_type == CC.FIELD_COMMENT:
( initial, append ) = value
@ -995,7 +995,7 @@ class ManagementPanelDumper( ManagementPanel ):
value = ( initial, append )
new_post_field_info.append( ( name, type, value ) )
new_post_field_info.append( ( name, field_type, value ) )
new_hashes_to_dump_info[ hash ] = ( dump_status_enum, dump_status_string, new_post_field_info )
@ -1049,9 +1049,9 @@ class ManagementPanelDumper( ManagementPanel ):
( dump_status_enum, dump_status_string, post_field_info ) = self._hashes_to_dump_info[ hash ]
for ( name, type, value ) in post_field_info:
for ( name, field_type, value ) in post_field_info:
if type == CC.FIELD_VERIFICATION_RECAPTCHA:
if field_type == CC.FIELD_VERIFICATION_RECAPTCHA:
if value is None:
@ -1080,21 +1080,21 @@ class ManagementPanelDumper( ManagementPanel ):
post_fields = []
for ( name, ( type, field ) ) in self._thread_fields.items():
for ( name, ( field_type, field ) ) in self._thread_fields.items():
post_fields.append( ( name, type, field.GetValue() ) )
post_fields.append( ( name, field_type, field.GetValue() ) )
for ( name, type, value ) in post_field_info:
for ( name, field_type, value ) in post_field_info:
if type == CC.FIELD_VERIFICATION_RECAPTCHA:
if field_type == CC.FIELD_VERIFICATION_RECAPTCHA:
( challenge, bitmap, captcha_runs_out, entry, ready ) = value
post_fields.append( ( 'recaptcha_challenge_field', type, challenge ) )
post_fields.append( ( 'recaptcha_response_field', type, entry ) )
post_fields.append( ( 'recaptcha_challenge_field', field_type, challenge ) )
post_fields.append( ( 'recaptcha_response_field', field_type, entry ) )
elif type == CC.FIELD_COMMENT:
elif field_type == CC.FIELD_COMMENT:
( initial, append ) = value
@ -1102,9 +1102,9 @@ class ManagementPanelDumper( ManagementPanel ):
if len( append ) > 0: comment += os.linesep + os.linesep + append
post_fields.append( ( name, type, comment ) )
post_fields.append( ( name, field_type, comment ) )
else: post_fields.append( ( name, type, value ) )
else: post_fields.append( ( name, field_type, value ) )
media = self._hashes_to_media[ hash ]

View File

@ -1346,7 +1346,7 @@ class MessageHTML( wx.html.HtmlWindow ):
def OnLinkClicked( self, link ): webbrowser.open( link.GetHref() )
def OnOpeningURL( self, type, url, redirect ): return wx.html.HTML_BLOCK
def OnOpeningURL( self, url_type, url, redirect ): return wx.html.HTML_BLOCK
class MessagePanel( wx.Panel ):

View File

@ -64,7 +64,7 @@ options = {}
# Misc
NETWORK_VERSION = 14
SOFTWARE_VERSION = 128
SOFTWARE_VERSION = 129
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
@ -1536,12 +1536,12 @@ class ClientServiceIdentifier( HydrusYAMLBase ):
yaml_tag = u'!ClientServiceIdentifier'
def __init__( self, service_key, type, name ):
def __init__( self, service_key, service_type, name ):
HydrusYAMLBase.__init__( self )
self._service_key = service_key
self._type = type
self._type = service_type
self._name = name
@ -1724,10 +1724,10 @@ class JobDatabase( object ):
yaml_tag = u'!JobDatabase'
def __init__( self, action, type, synchronous, *args, **kwargs ):
def __init__( self, action, job_type, synchronous, *args, **kwargs ):
self._action = action
self._type = type
self._type = job_type
self._synchronous = synchronous
self._args = args
self._kwargs = kwargs
@ -1986,7 +1986,7 @@ class Predicate( HydrusYAMLBase ):
self._counts[ CURRENT ] = 0
self._counts[ PENDING ] = 0
for ( type, count ) in counts.items(): self.AddToCount( type, count )
for ( current_or_pending, count ) in counts.items(): self.AddToCount( current_or_pending, count )
def __eq__( self, other ): return self.__hash__() == other.__hash__()
@ -1997,16 +1997,16 @@ class Predicate( HydrusYAMLBase ):
def __repr__( self ): return 'Predicate: ' + u( ( self._predicate_type, self._value, self._counts ) )
def AddToCount( self, type, count ): self._counts[ type ] += count
def AddToCount( self, current_or_pending, count ): self._counts[ current_or_pending ] += count
def GetCopy( self ): return Predicate( self._predicate_type, self._value, self._counts )
def GetCountlessCopy( self ): return Predicate( self._predicate_type, self._value )
def GetCount( self, type = None ):
def GetCount( self, current_or_pending = None ):
if type is None: return sum( self._counts.values() )
else: return self._counts[ type ]
if current_or_pending is None: return sum( self._counts.values() )
else: return self._counts[ current_or_pending ]
def GetInfo( self ): return ( self._predicate_type, self._value )
@ -2146,14 +2146,14 @@ class Predicate( HydrusYAMLBase ):
if info is not None:
( operator, type, service_key ) = info
( operator, current_or_pending, service_key ) = info
base += u':'
if operator == True: base += u' is'
else: base += u' is not'
if type == PENDING: base += u' pending to '
if current_or_pending == PENDING: base += u' pending to '
else: base += u' currently in '
service = app.GetManager( 'services' ).GetService( service_key )
@ -2264,12 +2264,12 @@ class ServerServiceIdentifier( HydrusYAMLBase ):
yaml_tag = u'!ServerServiceIdentifier'
def __init__( self, service_key, type ):
def __init__( self, service_key, service_type ):
HydrusYAMLBase.__init__( self )
self._service_key = service_key
self._type = type
self._type = service_type
def __eq__( self, other ): return self.__hash__() == other.__hash__()

View File

@ -1326,11 +1326,11 @@ class ImportController( object ):
self._lock = threading.Lock()
def _GetNewJobKey( self, type ):
def _GetNewJobKey( self, job_type ):
job_key = HC.JobKey()
if type == 'controller':
if job_type == 'controller':
job_key.SetVariable( 'num_successful', 0 )
job_key.SetVariable( 'num_failed', 0 )
@ -1341,17 +1341,17 @@ class ImportController( object ):
job_key.SetVariable( 'status', '' )
if type == 'import':
if job_type == 'import':
job_key.SetVariable( 'page_key', self._page_key )
job_key.SetVariable( 'range', 1 )
job_key.SetVariable( 'value', 0 )
elif type == 'import_queue_position':
elif job_type == 'import_queue_position':
job_key.SetVariable( 'queue_position', 0 )
elif type == 'import_queue':
elif job_type == 'import_queue':
job_key.SetVariable( 'queue', [] )
@ -1362,14 +1362,14 @@ class ImportController( object ):
def CleanBeforeDestroy( self ): self._controller_job_key.Cancel()
def GetJobKey( self, type ):
def GetJobKey( self, job_type ):
with self._lock:
if type == 'controller': return self._controller_job_key
elif type == 'import': return self._import_job_key
elif type == 'import_queue_position': return self._import_queue_position_job_key
elif type == 'import_queue': return self._import_queue_job_key
if job_type == 'controller': return self._controller_job_key
elif job_type == 'import': return self._import_job_key
elif job_type == 'import_queue_position': return self._import_queue_position_job_key
elif job_type == 'import_queue': return self._import_queue_job_key

View File

@ -386,9 +386,9 @@ class IMMessageText( IMMessage ):
yaml_tag = u'!IMMessageText'
def __init__( self, type, text ):
def __init__( self, message_type, text ):
self._type = type
self._type = message_type
self._text = text

View File

@ -18,7 +18,7 @@ def AddHydrusCredentialsToHeaders( credentials, request_headers ):
else: raise Exception( 'No access key!' )
def AddHydrusSessionKeyToHeaders( service_key, request_headers ):
session_manager = HC.app.GetManager( 'hydrus_sessions' )
session_key = session_manager.GetSessionKey( service_key )

View File

@ -28,189 +28,6 @@ from twisted.web.resource import Resource
from twisted.web.static import File as FileResource, NoRangeStaticProducer
from twisted.python import log
eris = '''<html><head><title>hydrus</title></head><body><pre>
<font color="red">8888 8888888</font>
<font color="red">888888888888888888888888</font>
<font color="red">8888</font>:::<font color="red">8888888888888888888888888</font>
<font color="red">8888</font>::::::<font color="red">8888888888888888888888888888</font>
<font color="red">88</font>::::::::<font color="red">888</font>:::<font color="red">8888888888888888888888888</font>
<font color="red">88888888</font>::::<font color="red">8</font>:::::::::::<font color="red">88888888888888888888</font>
<font color="red">888 8</font>::<font color="red">888888</font>::::::::::::::::::<font color="red">88888888888 888</font>
<font color="red">88</font>::::<font color="red">88888888</font>::::<font color="gray">m</font>::::::::::<font color="red">88888888888 8</font>
<font color="red">888888888888888888</font>:<font color="gray">M</font>:::::::::::<font color="red">8888888888888</font>
<font color="red">88888888888888888888</font>::::::::::::<font color="gray">M</font><font color="red">88888888888888</font>
<font color="red">8888888888888888888888</font>:::::::::<font color="gray">M</font><font color="red">8888888888888888</font>
<font color="red">8888888888888888888888</font>:::::::<font color="gray">M</font><font color="red">888888888888888888</font>
<font color="red">8888888888888888</font>::<font color="red">88888</font>::::::<font color="gray">M</font><font color="red">88888888888888888888</font>
<font color="red">88888888888888888</font>:::<font color="red">88888</font>:::::<font color="gray">M</font><font color="red">888888888888888 8888</font>
<font color="red">88888888888888888</font>:::<font color="red">88888</font>::::<font color="gray">M</font>::<font color="black">;o</font><font color="maroon">*</font><font color="green">M</font><font color="maroon">*</font><font color="black">o;</font><font color="red">888888888 88</font>
<font color="red">88888888888888888</font>:::<font color="red">8888</font>:::::<font color="gray">M</font>:::::::::::<font color="red">88888888 8</font>
<font color="red">88888888888888888</font>::::<font color="red">88</font>::::::<font color="gray">M</font>:<font color="gray">;</font>:::::::::::<font color="red">888888888</font>
<font color="red">8888888888888888888</font>:::<font color="red">8</font>::::::<font color="gray">M</font>::<font color="gray">aAa</font>::::::::<font color="gray">M</font><font color="red">8888888888 8</font>
<font color="red">88 8888888888</font>::<font color="red">88</font>::::<font color="red">8</font>::::<font color="gray">M</font>:::::::::::::<font color="red">888888888888888 8888</font>
<font color="red">88 88888888888</font>:::<font color="red">8</font>:::::::::<font color="gray">M</font>::::::::::;::<font color="red">88</font><font color="black">:</font><font color="red">88888888888888888</font>
<font color="red">8 8888888888888</font>:::::::::::<font color="gray">M</font>::<font color="violet">&quot;@@@@@@@&quot;</font>::::<font color="red">8</font><font color="gray">w</font><font color="red">8888888888888888</font>
<font color="red">88888888888</font>:<font color="red">888</font>::::::::::<font color="gray">M</font>:::::<font color="violet">&quot;@a@&quot;</font>:::::<font color="gray">M</font><font color="red">8</font><font color="gray">i</font><font color="red">888888888888888</font>
<font color="red">8888888888</font>::::<font color="red">88</font>:::::::::<font color="gray">M</font><font color="red">88</font>:::::::::::::<font color="gray">M</font><font color="red">88</font><font color="gray">z</font><font color="red">88888888888888888</font>
<font color="red">8888888888</font>:::::<font color="red">8</font>:::::::::<font color="gray">M</font><font color="red">88888</font>:::::::::<font color="gray">MM</font><font color="red">888</font><font color="gray">!</font><font color="red">888888888888888888</font>
<font color="red">888888888</font>:::::<font color="red">8</font>:::::::::<font color="gray">M</font><font color="red">8888888</font><font color="gray">MAmmmAMVMM</font><font color="red">888</font><font color="gray">*</font><font color="red">88888888 88888888</font>
<font color="red">888888</font> <font color="gray">M</font>:::::::::::::::<font color="gray">M</font><font color="red">888888888</font>:::::::<font color="gray">MM</font><font color="red">88888888888888 8888888</font>
<font color="red">8888</font> <font color="gray">M</font>::::::::::::::<font color="gray">M</font><font color="red">88888888888</font>::::::<font color="gray">MM</font><font color="red">888888888888888 88888</font>
<font color="red">888</font> <font color="gray">M</font>:::::::::::::<font color="gray">M</font><font color="red">8888888888888</font><font color="gray">M</font>:::::<font color="gray">mM</font><font color="red">888888888888888 8888</font>
<font color="red">888</font> <font color="gray">M</font>::::::::::::<font color="gray">M</font><font color="red">8888</font>:<font color="red">888888888888</font>::::<font color="gray">m</font>::<font color="gray">Mm</font><font color="red">88888 888888 8888</font>
<font color="red">88</font> <font color="gray">M</font>::::::::::::<font color="red">8888</font>:<font color="red">88888888888888888</font>::::::<font color="gray">Mm</font><font color="red">8 88888 888</font>
<font color="red">88</font> <font color="gray">M</font>::::::::::<font color="red">8888</font><font color="gray">M</font>::<font color="red">88888</font>::<font color="red">888888888888</font>:::::::<font color="gray">Mm</font><font color="red">88888 88</font>
<font color="red">8</font> <font color="gray">MM</font>::::::::<font color="red">8888</font><font color="gray">M</font>:::<font color="red">8888</font>:::::<font color="red">888888888888</font>::::::::<font color="gray">Mm</font><font color="red">8 4</font>
<font color="red">8</font><font color="gray">M</font>:::::::<font color="red">8888</font><font color="gray">M</font>:::::<font color="red">888</font>:::::::<font color="red">88</font>:::<font color="red">8888888</font>::::::::<font color="gray">Mm</font> <font color="red">2</font>
<font color="red">88</font><font color="gray">MM</font>:::::<font color="red">8888</font><font color="gray">M</font>:::::::<font color="red">88</font>::::::::<font color="red">8</font>:::::<font color="red">888888</font>:::<font color="gray">M</font>:::::<font color="gray">M</font>
<font color="red">8888</font><font color="gray">M</font>:::::<font color="red">888</font><font color="gray">MM</font>::::::::<font color="red">8</font>:::::::::::<font color="gray">M</font>::::<font color="red">8888</font>::::<font color="gray">M</font>::::<font color="gray">M</font>
<font color="red">88888</font><font color="gray">M</font>:::::<font color="red">88</font>:<font color="gray">M</font>::::::::::<font color="red">8</font>:::::::::::<font color="gray">M</font>:::<font color="red">8888</font>::::::<font color="gray">M</font>::<font color="gray">M</font>
<font color="red">88 888</font><font color="gray">MM</font>:::<font color="red">888</font>:<font color="gray">M</font>:::::::::::::::::::::::<font color="gray">M</font>:<font color="red">8888</font>:::::::::<font color="gray">M</font>:
<font color="red">8 88888</font><font color="gray">M</font>:::<font color="red">88</font>::<font color="gray">M</font>:::::::::::::::::::::::<font color="gray">MM</font>:<font color="red">88</font>::::::::::::<font color="gray">M</font>
<font color="red">88888</font><font color="gray">M</font>:::<font color="red">88</font>::<font color="gray">M</font>::::::::::<font color="thistle">*88*</font>::::::::::<font color="gray">M</font>:<font color="red">88</font>::::::::::::::<font color="gray">M</font>
<font color="red">888888</font><font color="gray">M</font>:::<font color="red">88</font>::<font color="gray">M</font>:::::::::<font color="thistle">88@@88</font>:::::::::<font color="gray">M</font>::<font color="red">88</font>::::::::::::::<font color="gray">M</font>
<font color="red">888888</font><font color="gray">MM</font>::<font color="red">88</font>::<font color="gray">MM</font>::::::::<font color="thistle">88@@88</font>:::::::::<font color="gray">M</font>:::<font color="red">8</font>::::::::::::::<font color="thistle">*8</font>
<font color="red">88888</font> <font color="gray">M</font>:::<font color="red">8</font>::<font color="gray">MM</font>:::::::::<font color="thistle">*88*</font>::::::::::<font color="gray">M</font>:::::::::::::::::<font color="thistle">88@@</font>
<font color="red">8888</font> <font color="gray">MM</font>::::::<font color="gray">MM</font>:::::::::::::::::::::<font color="gray">MM</font>:::::::::::::::::<font color="thistle">88@@</font>
<font color="red">888</font> <font color="gray">M</font>:::::::<font color="gray">MM</font>:::::::::::::::::::<font color="gray">MM</font>::<font color="gray">M</font>::::::::::::::::<font color="thistle">*8</font>
<font color="red">888</font> <font color="gray">MM</font>:::::::<font color="gray">MMM</font>::::::::::::::::<font color="gray">MM</font>:::<font color="gray">MM</font>:::::::::::::::<font color="gray">M</font>
<font color="red">88</font> <font color="gray">M</font>::::::::<font color="gray">MMMM</font>:::::::::::<font color="gray">MMMM</font>:::::<font color="gray">MM</font>::::::::::::<font color="gray">MM</font>
<font color="red">88</font> <font color="gray">MM</font>:::::::::<font color="gray">MMMMMMMMMMMMMMM</font>::::::::<font color="gray">MMM</font>::::::::<font color="gray">MMM</font>
<font color="red">88</font> <font color="gray">MM</font>::::::::::::<font color="gray">MMMMMMM</font>::::::::::::::<font color="gray">MMMMMMMMMM</font>
<font color="red">88 8</font><font color="gray">MM</font>::::::::::::::::::::::::::::::::::<font color="gray">MMMMMM</font>
<font color="red">8 88</font><font color="gray">MM</font>::::::::::::::::::::::<font color="gray">M</font>:::<font color="gray">M</font>::::::::<font color="gray">MM</font>
<font color="red">888</font><font color="gray">MM</font>::::::::::::::::::<font color="gray">MM</font>::::::<font color="gray">MM</font>::::::<font color="gray">MM</font>
<font color="red">88888</font><font color="gray">MM</font>:::::::::::::::<font color="gray">MMM</font>:::::::<font color="gray">mM</font>:::::<font color="gray">MM</font>
<font color="red">888888</font><font color="gray">MM</font>:::::::::::::<font color="gray">MMM</font>:::::::::<font color="gray">MMM</font>:::<font color="gray">M</font>
<font color="red">88888888</font><font color="gray">MM</font>:::::::::::<font color="gray">MMM</font>:::::::::::<font color="gray">MM</font>:::<font color="gray">M</font>
<font color="red">88 8888888</font><font color="gray">M</font>:::::::::<font color="gray">MMM</font>::::::::::::::<font color="gray">M</font>:::<font color="gray">M</font>
<font color="red">8 888888</font> <font color="gray">M</font>:::::::<font color="gray">MM</font>:::::::::::::::::<font color="gray">M</font>:::<font color="gray">M</font>:
<font color="red">888888</font> <font color="gray">M</font>::::::<font color="gray">M</font>:::::::::::::::::::<font color="gray">M</font>:::<font color="gray">MM</font>
<font color="red">888888</font> <font color="gray">M</font>:::::<font color="gray">M</font>::::::::::::::::::::::::<font color="gray">M</font>:<font color="gray">M</font>
<font color="red">888888</font> <font color="gray">M</font>:::::<font color="gray">M</font>:::::::::<font color="gray">@</font>::::::::::::::<font color="gray">M</font>::<font color="gray">M</font>
<font color="red">88888</font> <font color="gray">M</font>::::::::::::::<font color="gray">@@</font>:::::::::::::::<font color="gray">M</font>::<font color="gray">M</font>
<font color="red">88888</font> <font color="gray">M</font>::::::::::::::<font color="gray">@@@</font>::::::::::::::::<font color="gray">M</font>::<font color="gray">M</font>
<font color="red">88888</font> <font color="gray">M</font>:::::::::::::::<font color="gray">@@</font>::::::::::::::::::<font color="gray">M</font>::<font color="gray">M</font>
<font color="red">88888</font> <font color="gray">M</font>:::::<font color="gray">m</font>::::::::::<font color="gray">@</font>::::::::::<font color="gray">Mm</font>:::::::<font color="gray">M</font>:::<font color="gray">M</font>
<font color="red">8888</font> <font color="gray">M</font>:::::<font color="gray">M</font>:::::::::::::::::::::::<font color="gray">MM</font>:::::::<font color="gray">M</font>:::<font color="gray">M</font>
<font color="red">8888</font> <font color="gray">M</font>:::::<font color="gray">M</font>:::::::::::::::::::::::<font color="gray">MMM</font>::::::::<font color="gray">M</font>:::<font color="gray">M</font>
<font color="red">888</font> <font color="gray">M</font>:::::<font color="gray">Mm</font>::::::::::::::::::::::<font color="gray">MMM</font>:::::::::<font color="gray">M</font>::::<font color="gray">M</font>
<font color="red">8888</font> <font color="gray">MM</font>::::<font color="gray">Mm</font>:::::::::::::::::::::<font color="gray">MMMM</font>:::::::::<font color="gray">m</font>::<font color="gray">m</font>:::<font color="gray">M</font>
<font color="red">888</font> <font color="gray">M</font>:::::<font color="gray">M</font>::::::::::::::::::::<font color="gray">MMM</font>::::::::::::<font color="gray">M</font>::<font color="gray">mm</font>:::<font color="gray">M</font>
<font color="red">8888</font> <font color="gray">MM</font>:::::::::::::::::::::::::<font color="gray">MM</font>:::::::::::::<font color="gray">mM</font>::<font color="gray">MM</font>:::<font color="gray">M</font>:
<font color="gray">M</font>:::::::::::::::::::::::::<font color="gray">M</font>:::::::::::::::<font color="gray">mM</font>::<font color="gray">MM</font>:::<font color="gray">Mm</font>
<font color="gray">MM</font>::::::<font color="gray">m</font>:::::::::::::::::::::::::::::::::::<font color="gray">M</font>::<font color="gray">MM</font>:::<font color="gray">MM</font>
<font color="gray">M</font>::::::::<font color="gray">M</font>:::::::::::::::::::::::::::::::::::<font color="gray">M</font>::<font color="gray">M</font>:::<font color="gray">MM</font>
<font color="gray">MM</font>:::::::::<font color="gray">M</font>:::::::::::::<font color="gray">M</font>:::::::::::::::::::::<font color="gray">M</font>:<font color="gray">M</font>:::<font color="gray">MM</font>
<font color="gray">M</font>:::::::::::<font color="gray">M</font><font color="maroon">88</font>:::::::::<font color="gray">M</font>:::::::::::::::::::::::<font color="gray">MM</font>::<font color="gray">MMM</font>
<font color="gray">M</font>::::::::::::<font color="maroon">8888888888</font><font color="gray">M</font>::::::::::::::::::::::::<font color="gray">MM</font>::<font color="gray">MM</font>
<font color="gray">M</font>:::::::::::::<font color="maroon">88888888</font><font color="gray">M</font>:::::::::::::::::::::::::<font color="gray">M</font>::<font color="gray">MM</font>
<font color="gray">M</font>::::::::::::::<font color="maroon">888888</font><font color="gray">M</font>:::::::::::::::::::::::::<font color="gray">M</font>::<font color="gray">MM</font>
<font color="gray">M</font>:::::::::::::::<font color="maroon">88888</font><font color="gray">M</font>:::::::::::::::::::::::::<font color="gray">M</font>:<font color="gray">MM</font>
<font color="gray">M</font>:::::::::::::::::<font color="maroon">88</font><font color="gray">M</font>::::::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">M</font>:::::::::::::::::::<font color="gray">M</font>::::::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::::::::::::::::<font color="gray">M</font>::::::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">M</font>:::::::::::::::::<font color="gray">M</font>::::::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::::::::::::::<font color="gray">M</font>::::::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">M</font>:::::::::::::::<font color="gray">M</font>:::::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::::::::::::<font color="gray">M</font>:::::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">M</font>:::::::::::::<font color="gray">M</font>::::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::::::::::<font color="gray">M</font>::::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">M</font>:::::::::::<font color="gray">M</font>:::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::::::::<font color="gray">M</font>:::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">M</font>:::::::::<font color="gray">M</font>::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::::::<font color="gray">M</font>::::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>::::::<font color="gray">M</font>:::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::::<font color="gray">M</font>:::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>::::<font color="gray">M</font>::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::<font color="gray">M</font>::::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>::<font color="gray">M</font>:::::::::::::::::::<font color="gray">MMM</font> THIS IS THE HYDRUS SERVER ADMIN SERVICE, VERSION ''' + HC.u( HC.SOFTWARE_VERSION ) + '''
<font color="gray">MM</font>:<font color="gray">M</font>:::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MMM</font>::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>::::::::::::::::::<font color="gray">MMM</font>
<font color="gray">M</font>:::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>::::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>:::::::::::::::<font color="gray">MMM</font>
<font color="gray">MM</font>::::<font color="gray">M</font>:::::::::<font color="gray">MMM</font>:
<font color="gray">mMM</font>::::<font color="gray">MM</font>:::::::<font color="gray">MMMM</font>
<font color="gray">MMM</font>:::::::::::<font color="gray">MMM</font>:<font color="gray">M</font>
<font color="gray">mMM</font>:::<font color="gray">M</font>:::::::<font color="gray">M</font>:<font color="gray">M</font>:<font color="gray">M</font>
<font color="gray">MM</font>::<font color="gray">MMMM</font>:::::::<font color="gray">M</font>:<font color="gray">M</font>
<font color="gray">MM</font>::<font color="gray">MMM</font>::::::::<font color="gray">M</font>:<font color="gray">M</font>
<font color="gray">mMM</font>::<font color="gray">MM</font>::::::::<font color="gray">M</font>:<font color="gray">M</font>
<font color="gray">MM</font>::<font color="gray">MM</font>:::::::::<font color="gray">M</font>:<font color="gray">M</font>
<font color="gray">MM</font>::<font color="gray">MM</font>::::::::::<font color="gray">M</font>:<font color="gray">m</font>
<font color="gray">MM</font>:::<font color="gray">M</font>:::::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>:::::::::::::::<font color="gray">M</font>:
<font color="gray">MMM</font>:::::::::::::::<font color="gray">M</font>:
<font color="gray">MMM</font>::::::::::::::::<font color="gray">M</font>
<font color="gray">MMM</font>::::::::::::::::<font color="gray">M</font>
<font color="gray">MMM</font>::::::::::::::::<font color="gray">Mm</font>
<font color="gray">MM</font>::::::::::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>:::::::::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>:::::::::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>:::::::::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>:::::::::::::::<font color="gray">MM</font>
<font color="gray">MM</font>::::::::::::::<font color="gray">MMM</font>
<font color="gray">MMM</font>:::::::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>:::::::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>::::::::::::<font color="gray">MM</font>
<font color="gray">MM</font>::::::::::::<font color="gray">MM</font>
<font color="gray">MM</font>::::::::::::<font color="gray">MM</font>
<font color="gray">MM</font>:::::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>::::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>::::::::::<font color="gray">MM</font>
<font color="gray">MM</font>:::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>::::::::<font color="gray">MM</font>
<font color="gray">MM</font>::::::::<font color="gray">MM</font>
<font color="gray">MMM</font>::::::<font color="gray">MM</font>
<font color="gray">MMM</font>::::::<font color="gray">MM</font>
<font color="gray">MM</font>::::::<font color="gray">MM</font>
<font color="gray">MM</font>::::::<font color="gray">MM</font>
<font color="gray">MM</font>:::::<font color="gray">MM</font>
<font color="gray">MM</font>:::::<font color="gray">MM</font>:
<font color="gray">MM</font>:::::<font color="gray">M</font>:<font color="gray">M</font>
<font color="gray">MM</font>:::::<font color="gray">M</font>:<font color="gray">M</font>
:<font color="gray">M</font>::::::<font color="gray">M</font>:
<font color="gray">M</font>:<font color="gray">M</font>:::::::<font color="gray">M</font>
<font color="gray">M</font>:::<font color="gray">M</font>::::::<font color="gray">M</font>
<font color="gray">M</font>::::<font color="gray">M</font>::::::<font color="gray">M</font>
<font color="gray">M</font>:::::<font color="gray">M</font>:::::::<font color="gray">M</font>
<font color="gray">M</font>::::::<font color="gray">MM</font>:::::::<font color="gray">M</font>
<font color="gray">M</font>:::::::<font color="gray">M</font>::::::::<font color="gray">M</font>
<font color="gray">M;</font>:<font color="gray">;</font>::::<font color="gray">M</font>:::::::::<font color="gray">M</font>
<font color="gray">M</font>:<font color="gray">m</font>:<font color="gray">;</font>:::<font color="gray">M</font>::::::::::<font color="gray">M</font>
<font color="gray">MM</font>:<font color="gray">m</font>:<font color="gray">m</font>::<font color="gray">M</font>::::::::<font color="gray">;</font>:<font color="gray">M</font>
<font color="gray">MM</font>:<font color="gray">m</font>::<font color="gray">MM</font>:::::::<font color="gray">;</font>:<font color="gray">;M</font>
<font color="gray">MM</font>::<font color="gray">MMM</font>::::::<font color="gray">;</font>:<font color="gray">m</font>:<font color="gray">M</font>
<font color="gray">MMMM MM</font>::::<font color="gray">m</font>:<font color="gray">m</font>:<font color="gray">MM</font>
<font color="gray">MM</font>::::<font color="gray">m</font>:<font color="gray">MM</font>
<font color="gray">MM</font>::::<font color="gray">MM</font>
<font color="gray">MM</font>::<font color="gray">MM</font>
<font color="gray">MMMM</font>
</pre></body></html>'''
silly_responses = []
silly_responses.append( u'\ufeff\u25d5 \u203f\u203f \u25d5' )
silly_responses.append( u"The disco. We go to disco. My body's sweaty from the MDMA inside it. I like to dance with you. You grab my ponytail. It is greasy with Germanic juices that I put inside my hair. Disco, we are the disco. I have a mesh shirt. My leather pants show off my sausage inside it. I grind your body, then we eat ecstasy and have Special K inside of the bathroom. It's a men's bathroom, but no one cares that you come inside because they know that inside it we do lots of drugs. And I will share them if the bouncer lets me go into the bathroom with you, and then we go home. We have efficient sex. And then I realize you're not that hot anymore because I've blown a load and I don't have ecstasy inside of my bloodstream. So I make sandwich. It has hazelnuts, bread, and some jelly that I got from the supermarket. It tastes pretty good, but it probably tastes better because my taste buds have ecstasy inside them. And then I go up to the bathroom, and you're wearing one of my shirts; that isn't cool. You didn't even ask. I met you earlier the evening; you're not my girlfriend, you're just girl that I have sex with. We probably won't do this again because I realize that your hair is frazzled and it probably has extensions. It's not your real hair, and that's kind of gross 'cause who knows where it came from." )
silly_responses.append( u'\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\n\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2591\u2591\n\u2591\u2588\u2591\u2591\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2588\u2591\n\u2588\u2591\u2591\u2588\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2588\n\u2588\u2591\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2588\n\u2588\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2588\n\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\n\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\n\u2588\u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2588\n\u2591\u2588\u2591\u2591\u2591\u2588\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2588\u2588\u2588\u2588\u2588\u2593\u2593\u2593\u2588\u2591\u2591\u2591\u2591\u2588\u2591\n\u2591\u2588\u2591\u2591\u2591\u2591\u2588\u2593\u2593\u2593\u2593\u2593\u2588\u2588\u2591\u2591\u2591\u2591\u2588\u2588\u2593\u2588\u2588\u2591\u2591\u2591\u2591\u2588\u2591\n\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2588\u2588\u2593\u2593\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2592\u2588\u2588\u2591\u2591\u2591\u2591\u2588\u2591\u2591\n\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2592\u2588\u2588\u2591\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2588\u2588\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591' )
silly_responses.append( u' (\u25cb\u220b\u25cb)\n\u250f( \u7537 )\u251b\n \uff0f \u2513\nA mystery' )
silly_responses.append( u'\u25b2\n\u25b2 \u25b2' )
silly_responses.append( u'\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2584\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2584\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584\u2591\u2591\u2591\n\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584\u2591\u2591\n\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\n\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\n\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\n\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2580\u2580\u2580\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2591\u2591\n\u2591\u2591\u2580\u2588\u2588\u2588\u2588\u2588\u2580\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2580\u2588\u2588\u2588\u2588\u2588\u2591\u2591\u2591\n\u2591\u2591\u2591\u2580\u2580\u2588\u2588\u2588\u2591\u2591\u2588\u2591\u2591\u2591\u2588\u2591\u2591\u2588\u2588\u2588\u2580\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2580\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2584\u2588\u2588\u2584\u2591\u2591\u2580\u2580\u2591\u2584\u2588\u2580\u2584\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2584\u2580\u2591\u2580\u2584\u2580\u2580\u2588\u2588\u2588\u2580\u2580\u2584\u2580\u2591\u2580\u2584\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2580\u2584\u2580\u2591\u2580\u2584\u2580\u2591\u2584\u2591\u2591\u2588\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2588\u2591\u2588\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2588\u2591\u2591\u2588\u2591\u2591\u2588\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2588\u2591\u2588\u2591\u2591\u2591\u2591\u2580\u2584\u2580\u2580\u2580\u2580\u2588\u2591\u2591\u2588\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2588\u2591\u2588\u2591\u2591\u2591\u2591\u2591\u2584\u2591\u2591\u2584\u2588\u2588\u2584\u2584\u2580\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2588\u2591\u2588\u2591\u2591\u2591\u2591\u2591\u2584\u2591\u2591\u2588\u2588\u2588\u2588\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2584\u2591\u2591\u2591\u2584\u2584\u2584\u2591\u2591\u2591\u2584\u2580\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2580\u2580\u2588\u2580\u2580\u2580\u2591\u2584\u2591\u2580\u2580\u2580\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2584\u2584\u2584\u2584\u2588\u2584\u2584\u2584\u2584\u2588\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2588\u2588\u2588\u2588\u2588\u2588\u2584\u2584\u2584\u2584\u2580\u2591\u2591\u2591\u2591\u2591\u2591\u2591\n\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2580\u2580\u2580\u2580\u2580\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591' )
silly_responses.append( u'\u0ca0_\u0ca0' )
silly_responses.append( u'(\xb4_\u309d`)' )
silly_responses.append( u'\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000\uff0f\u2312\u30fd\n\u3000\u3000\u3000\u2282\u4e8c\u4e8c\u4e8c\uff08\u3000\uff3e\u03c9\uff3e\uff09\u4e8c\u2283\n\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000|\u3000\u3000\u3000 / \u3000\u3000\u3000\u3000\u3000\u3000BU-N\n\u3000\u3000\u3000\u3000 \u3000\u3000\u3000 \uff08\u3000\u30fd\u30ce\n\u3000\u3000\u3000\u3000\u3000\u3000\u3000\u3000 \u30ce>\u30ce\u3000\n\u3000\u3000\u3000\u3000 \u4e09\u3000\u3000\u30ec\u30ec' )
silly_responses.append( u'Gen.\n\nThis is wheat.\n\nA blue bud is put out at the cruel\nwinter, it is stepped many times, it\nexpands strongly and straight, and it becomes\nwheat that bears the fruit.' )
silly_responses.append( u'I\'m a hardcore fan with FF8, so many times I would even try to escape reality with lucid dreaming, I would be in Balamb Garden where I would often train with Zell in the training center and help Selphie with the Garden Festival, but one day as I was talking to Selphie, we went to my dormitory for a private talk. She immediately said, "You know you could live with us forever.." I gave her a confused look and she continued, "We understand that you live on earth and you REALLY wish to live here". I then said "How..How did you know?" She then giggled and said "Because we\'ve been watching you, silly!" This was a dream come true and I almost cried right there. She then said, "I talked with Headmaster Cid and he agreed that you would be PERFECT for SeeD, you just have to do...one thing". She then held my hand and looked deep into my eyes and said "...You have to kill yourself for the transfer to work correctly." I then gave her some questions, "How long do I have before the deal expires?" She then said "Cid said 3 months.." I added by saying "What\'s the most painless way?..." She giggled again, "Suicide will require pain buuut...if you want it quick...Get a gun and a nice shot to the head works, but make sure you put the gun in your mouth for better accuracy, If you can\'t afford a gun, jump off a very VERY tall building, I wouldn\'t recommend pills because it\'s not a guaranteed method of dying, you could just get really really sick and be hospitalized." I then agreed and she gave me a kiss on the forehead, "I know this will be tough but once it\'s over and done, you\'ll get to live here!" I then woke up and this was last week and purchased a gun (I\'ll even post the gun with receipt, if you want) But Friday I might actually kill myself because that dream just felt too fucking real to be fake and my life isn\'t doing so grand.' )
silly_responses.append( u'Consider this: A pack of wild Niggers.\nSavage, slavering Niggers nearing your white home. Trampling your white lawn. Raping your white daughter.\nAnd you can\'t do shit since they\'re savages. The Nigger leader grabs your wife and fucks her with his shaman stick.\nThe primal Niggers finally dominate your household. They watch barbaric shows on TV and you are forced to be their slave.\nSuch is the downfall of White Man.' )
silly_responses.append( u'\uFF37\uFF2F\uFF35\uFF2C\uFF24 \uFF39\uFF2F\uFF35 \uFF2C\uFF29\uFF2B\uFF25 \uFF34\uFF2F \uFF22\uFF25 \uFF2D\uFF21\uFF2B\uFF29\uFF2E\uFF27 \uFF26\uFF35\uFF23\uFF2B' )
silly_responses.append( u'Israelis expect that thousands http://www.canadagooses.co.uk/kensington-parka-c-15.html of missiles might be fired at their cities by Iran\u2019s http://www.monclersole.com/moncler-jackets-womens-c-3.html clients in Lebanon and the Gaza Strip, while U.S. forces might be attacked in Afghanistan, Iraq or in the Persian http://www.monclersnorge.com Gulf. But China has proven to be a continuous http://www.monclerfactoryoutlets.com complication. On trade, Mr. Obama has repeatedly pressured China to http://www.monclerstyle2011.comallow its currency to http://www.doudounemoncleralpin.com appreciate, only to be told by Beijing that China is doing enough. On national security, China http://www.canadagooseexpedition.ca is extending its claims in the region, worrying U.S. partners and allies who both depend on China for trade but fear it http://www.imonclerdoudoune.com may exercise its power in more forceful ways. Toomey acknowledged http://www.monclerfronline.com that both sides have \u201Ca ways to go\u201D in reaching an http://www.monclersole.com/ agreement, but told Fox News: \u201CI am not giving up on getting something done. I think we http://www.monclerdoudounepascher2011.com/ still can, and http://www.monclerdoudounepascher2011.com I am going to do everything to achieve that.\u201DAlso appearing on the program http://www.canadiangoosejacket.ca was Representative James Clyburn, a South Carolina http://www.canadagooseolinestore.com Democrat, who said he remained \u201Cvery hopeful\u201D that both sides will http://www.moncler2u.co.uk reach a compromise before their deadline, now http://www.monclerbransondoudoune.fr less than two weeks away.' )
silly_responses.append( u'i am a heron. i haev a long neck and i pick fish out of the water w/ my beak. if you dont repost this comment on 10 other pages i will fly into your kitchen tonight and make a mess of your pots and pans' )
silly_responses.append( u'The maritine avains lack order and are wrought with decent among their kind .\r\n to promote forms of good tidings , appeasement and fair boon . \r\n\r\n One tender note in sequence of two or \r\n a a golden coin tender in sequence of one .\r\n\r\n Forfeiting and abandoning of these are signs of the above mentioned.' )
silly_responses.append( u'It is the VIPPER beatdown!\r\n Kick that dokyun around!\r\n Bury him six feet under the ground!\r\n Ain\'t no QUALITY but VIP QUALITY in this town.' )
silly_responses.append( u'IAmA heron. i ahev a long neck and i pick fish out of the water w/ my beak. if you dont repost this comment on 10 other pages i will fly into your kitchen tonight and make a mess of your pots and pans' )
CLIENT_ROOT_MESSAGE = '''<html>
<head>
<title>hydrus client</title>
@ -701,15 +518,7 @@ class HydrusResourceCommandAccessKeyVerification( HydrusResourceCommand ):
access_key = self._parseAccessKey( request )
account_identifier = HC.AccountIdentifier( access_key = access_key )
try:
account = HC.app.Read( 'account', self._service_key, account_identifier )
verified = True
except: verified = False
verified = HC.app.Read( 'verify_access_key', self._service_key, access_key )
body = yaml.safe_dump( { 'verified' : verified } )

View File

@ -24,11 +24,11 @@ class HydrusMessagingSessionManagerServer( object ):
existing_sessions = HC.app.Read( 'messaging_sessions' )
self._sessions = collections.defaultdict( dict )
self._service_keys_to_sessions = collections.defaultdict( dict )
for ( service_key, session_tuples ) in existing_sessions:
self._sessions[ service_key ] = { session_key : ( account, identifier, name, expiry ) for ( session_Key, account, identifier, name, expiry ) in session_tuples }
self._service_keys_to_sessions[ service_key ] = { session_key : ( account, identifier, name, expiry ) for ( session_Key, account, identifier, name, expiry ) in session_tuples }
self._lock = threading.Lock()
@ -38,16 +38,16 @@ class HydrusMessagingSessionManagerServer( object ):
with self._lock:
if session_key not in self._sessions[ service_key ]: raise HydrusExceptions.SessionException( 'Did not find that session!' )
if session_key not in self._service_keys_to_sessions[ service_key ]: raise HydrusExceptions.SessionException( 'Did not find that session!' )
else:
( account, identity, name, expiry ) = self._sessions[ service_key ][ session_key ]
( account, identity, name, expiry ) = self._service_keys_to_sessions[ service_key ][ session_key ]
now = HC.GetNow()
if now > expiry:
del self._sessions[ service_key ][ session_key ]
del self._service_keys_to_sessions[ service_key ][ session_key ]
raise HydrusExceptions.SessionException( 'Session expired!' )
@ -63,9 +63,9 @@ class HydrusMessagingSessionManagerServer( object ):
account_identifier = HC.AccountIdentifier( access_key = access_key )
account = HC.app.Read( 'account', service_key, account_identifier )
account_key = HC.app.Read( 'account_key', service_key, account_identifier )
account_identifier = account.GetAccountIdentifier() # for better account_id-based identifier
account = HC.app.Read( 'account', service_key, account_key )
identity = hashlib.sha256( access_key ).digest()
@ -75,7 +75,7 @@ class HydrusMessagingSessionManagerServer( object ):
with self._lock:
self._sessions[ service_key ][ session_key ] = ( account, identity, name, expiry )
self._service_keys_to_sessions[ service_key ][ session_key ] = ( account, identity, name, expiry )
HC.app.Write( 'messaging_session', service_key, session_key, account, identity, name, expiry )
@ -89,7 +89,7 @@ class HydrusSessionManagerClient( object ):
existing_sessions = HC.app.Read( 'hydrus_sessions' )
self._sessions = { service_key : ( session_key, expiry ) for ( service_key, session_key, expiry ) in existing_sessions }
self._service_keys_to_sessions = { service_key : ( session_key, expiry ) for ( service_key, session_key, expiry ) in existing_sessions }
self._lock = threading.Lock()
@ -100,7 +100,7 @@ class HydrusSessionManagerClient( object ):
HC.app.Write( 'delete_hydrus_session_key', service_key )
if service_key in self._sessions: del self._sessions[ service_key ]
if service_key in self._service_keys_to_sessions: del self._service_keys_to_sessions[ service_key ]
@ -110,11 +110,11 @@ class HydrusSessionManagerClient( object ):
with self._lock:
if service_key in self._sessions:
if service_key in self._service_keys_to_sessions:
( session_key, expiry ) = self._sessions[ service_key ]
( session_key, expiry ) = self._service_keys_to_sessions[ service_key ]
if now + 600 > expiry: del self._sessions[ service_key ]
if now + 600 > expiry: del self._service_keys_to_sessions[ service_key ]
else: return session_key
@ -129,7 +129,7 @@ class HydrusSessionManagerClient( object ):
expiry = now + HYDRUS_SESSION_LIFETIME
self._sessions[ service_key ] = ( session_key, expiry )
self._service_keys_to_sessions[ service_key ] = ( session_key, expiry )
HC.app.Write( 'hydrus_session', service_key, session_key, expiry )
@ -154,20 +154,20 @@ class HydrusSessionManagerServer( object ):
account_identifier = HC.AccountIdentifier( access_key = access_key )
account = HC.app.Read( 'account', service_key, account_identifier )
account_key = HC.app.Read( 'account_key', service_key, account_identifier )
account_id = account.GetAccountId()
if account_id not in self._account_ids_to_accounts[ service_key ]:
if account_key not in self._account_keys_to_accounts[ service_key ]:
self._account_ids_to_accounts[ service_key ][ account_id ] = account
account = HC.app.Read( 'account', service_key, account_key )
self._account_keys_to_accounts[ service_key ][ account_key ] = account
account = self._account_ids_to_accounts[ service_key ][ account_id ]
account = self._account_keys_to_accounts[ service_key ][ account_key ]
session_key = os.urandom( 32 )
self._account_ids_to_session_keys[ service_key ][ account_id ].add( session_key )
self._account_keys_to_session_keys[ service_key ][ account_key ].add( session_key )
now = HC.GetNow()
@ -175,7 +175,7 @@ class HydrusSessionManagerServer( object ):
HC.app.Write( 'session', session_key, service_key, account, expiry )
self._sessions[ service_key ][ session_key ] = ( account, expiry )
self._service_keys_to_sessions[ service_key ][ session_key ] = ( account, expiry )
return ( session_key, expiry )
@ -187,13 +187,13 @@ class HydrusSessionManagerServer( object ):
with self._lock:
services_sessions = self._sessions[ service_key ]
service_sessions = self._service_keys_to_sessions[ service_key ]
if session_key in services_sessions:
if session_key in service_sessions:
( account, expiry ) = services_sessions[ session_key ]
( account, expiry ) = service_sessions[ session_key ]
if expiry is not None and now > expiry: del services_sessions[ session_key ]
if now > expiry: del service_sessions[ session_key ]
else: return account
@ -207,21 +207,21 @@ class HydrusSessionManagerServer( object ):
for account_identifier in account_identifiers:
account = HC.app.Read( 'account', service_key, account_identifier )
account_key = HC.app.Read( 'account_key', service_key, account_identifier )
account_id = account.GetAccountId()
account = HC.app.Read( 'account', service_key, account_key )
self._account_ids_to_accounts[ service_key ][ account_id ] = account
self._account_keys_to_accounts[ service_key ][ account_key ] = account
if account_id in self._account_ids_to_session_keys[ service_key ]:
if account_key in self._account_keys_to_session_keys[ service_key ]:
session_keys = self._account_ids_to_session_keys[ service_key ][ account_id ]
session_keys = self._account_keys_to_session_keys[ service_key ][ account_key ]
for session_key in session_keys:
( old_account, expiry ) = self._sessions[ service_key ][ session_key ]
( old_account, expiry ) = self._service_keys_to_sessions[ service_key ][ session_key ]
self._sessions[ service_key ][ session_key ] = ( account, expiry )
self._service_keys_to_sessions[ service_key ][ session_key ] = ( account, expiry )
@ -232,23 +232,23 @@ class HydrusSessionManagerServer( object ):
with self._lock:
self._service_keys_to_sessions = collections.defaultdict( dict )
self._account_keys_to_session_keys = collections.defaultdict( HC.default_dict_set )
self._account_keys_to_accounts = collections.defaultdict( dict )
#
existing_sessions = HC.app.Read( 'sessions' )
self._account_ids_to_session_keys = collections.defaultdict( HC.default_dict_set )
self._account_ids_to_accounts = collections.defaultdict( dict )
self._sessions = collections.defaultdict( dict )
for ( session_key, service_key, account, expiry ) in existing_sessions:
for ( session_key, service_key, account_key, account, expiry ) in existing_sessions:
self._sessions[ service_key ][ session_key ] = ( account, expiry )
self._service_keys_to_sessions[ service_key ][ session_key ] = ( account, expiry )
account_id = account.GetAccountId()
self._account_keys_to_session_keys[ service_key ][ account_key ].add( session_key )
self._account_ids_to_session_keys[ service_key ][ account_id ].add( session_key )
self._account_ids_to_accounts[ service_key ][ account_id ] = account
self._account_keys_to_accounts[ service_key ][ account_key ] = account
@ -259,7 +259,7 @@ class WebSessionManagerClient( object ):
existing_sessions = HC.app.Read( 'web_sessions' )
self._sessions = { name : ( cookies, expiry ) for ( name, cookies, expiry ) in existing_sessions }
self._names_to_sessions = { name : ( cookies, expiry ) for ( name, cookies, expiry ) in existing_sessions }
self._lock = threading.Lock()
@ -270,11 +270,11 @@ class WebSessionManagerClient( object ):
with self._lock:
if name in self._sessions:
if name in self._names_to_sessions:
( cookies, expiry ) = self._sessions[ name ]
( cookies, expiry ) = self._names_to_sessions[ name ]
if now + 300 > expiry: del self._sessions[ name ]
if now + 300 > expiry: del self._names_to_sessions[ name ]
else: return cookies
@ -315,7 +315,7 @@ class WebSessionManagerClient( object ):
expiry = now + 30 * 86400
self._sessions[ name ] = ( cookies, expiry )
self._names_to_sessions[ name ] = ( cookies, expiry )
HC.app.Write( 'web_session', name, cookies, expiry )

View File

@ -39,7 +39,7 @@ class Controller( wx.App ):
def EventPubSub( self, event ): HC.pubsub.WXProcessQueueItem()
def GetManager( self, type ): return self._managers[ type ]
def GetManager( self, manager_type ): return self._managers[ manager_type ]
def OnInit( self ):

View File

@ -1120,11 +1120,11 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
if lifetime is not None: expiry = now + lifetime
else: expiry = None
keys = [ ( os.urandom( HC.HYDRUS_KEY_LENGTH ), os.urandom( HC.HYDRUS_KEY_LENGTH ) ) for i in range( num ) ]
keys = [ ( os.urandom( HC.HYDRUS_KEY_LENGTH ), os.urandom( HC.HYDRUS_KEY_LENGTH ), os.urandom( HC.HYDRUS_KEY_LENGTH ) ) for i in range( num ) ]
c.executemany( 'INSERT INTO registration_keys ( registration_key, service_id, account_type_id, access_key, expiry ) VALUES ( ?, ?, ?, ?, ? );', [ ( sqlite3.Binary( hashlib.sha256( registration_key ).digest() ), service_id, account_type_id, sqlite3.Binary( access_key ), expiry ) for ( registration_key, access_key ) in keys ] )
c.executemany( 'INSERT INTO registration_keys ( registration_key, service_id, account_type_id, account_key, access_key, expiry ) VALUES ( ?, ?, ?, ?, ?, ? );', [ ( sqlite3.Binary( hashlib.sha256( registration_key ).digest() ), service_id, account_type_id, sqlite3.Binary( account_key ), sqlite3.Binary( access_key ), expiry ) for ( registration_key, account_key, access_key ) in keys ] )
return [ registration_key for ( registration_key, access_key ) in keys ]
return [ registration_key for ( registration_key, account_key, access_key ) in keys ]
def _GetAccessKey( self, c, registration_key ):
@ -1135,77 +1135,11 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
return access_key
def _GetAccount( self, c, service_key, account_identifier ):
def _GetAccount( self, c, service_key, account_key ):
service_id = self._GetServiceId( c, service_key )
if account_identifier.HasAccessKey():
access_key = account_identifier.GetData()
try: ( account_id, account_type, created, expiry, used_bytes, used_requests ) = c.execute( 'SELECT account_id, account_type, created, expires, used_bytes, used_requests FROM account_types, ( accounts, account_map USING ( account_id ) ) USING ( account_type_id ) WHERE service_id = ? AND access_key = ?;', ( service_id, sqlite3.Binary( hashlib.sha256( access_key ).digest() ) ) ).fetchone()
except:
# we do not delete the registration_key (and hence the raw access_key)
# until the first attempt to create a session to make sure the user
# has the access_key saved somewhere
try: ( account_type_id, expiry ) = c.execute( 'SELECT account_type_id, expiry FROM registration_keys WHERE access_key = ?;', ( sqlite3.Binary( access_key ), ) ).fetchone()
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that account in its database.' )
c.execute( 'DELETE FROM registration_keys WHERE access_key = ?;', ( sqlite3.Binary( access_key ), ) )
#
c.execute( 'INSERT INTO accounts ( access_key ) VALUES ( ? );', ( sqlite3.Binary( hashlib.sha256( access_key ).digest() ), ) )
account_id = c.lastrowid
now = HC.GetNow()
c.execute( 'INSERT INTO account_map ( service_id, account_id, account_type_id, created, expires, used_bytes, used_requests ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', ( service_id, account_id, account_type_id, now, expiry, 0, 0 ) )
( account_id, account_type, created, expiry, used_bytes, used_requests ) = c.execute( 'SELECT account_id, account_type, created, expires, used_bytes, used_requests FROM account_types, ( accounts, account_map USING ( account_id ) ) USING ( account_type_id ) WHERE service_id = ? AND access_key = ?;', ( service_id, sqlite3.Binary( hashlib.sha256( access_key ).digest() ) ) ).fetchone()
elif account_identifier.HasAccountId():
account_id = account_identifier.GetData()
try: ( account_id, account_type, created, expiry, used_bytes, used_requests ) = c.execute( 'SELECT account_id, account_type, created, expires, used_bytes, used_requests FROM account_types, account_map USING ( account_type_id ) WHERE service_id = ? AND account_id = ?;', ( service_id, account_id ) ).fetchone()
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that account in its database.' )
elif account_identifier.HasHash():
hash = account_identifier.GetData()
try: hash_id = self._GetHashId( c, hash )
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that hash in its database.' )
try:
result = c.execute( 'SELECT account_id, account_type, created, expires, used_bytes, used_requests FROM account_types, ( accounts, ( account_map, file_map USING ( service_id, account_id ) ) USING ( account_id ) ) USING ( account_type_id ) WHERE service_id = ? AND hash_id = ?;', ( service_id, hash_id ) ).fetchone()
if result is None: result = c.execute( 'SELECT account_id, account_type, created, expires, used_bytes, used_requests FROM account_types, ( accounts, ( account_map, file_petitions USING ( service_id, account_id ) ) USING ( account_id ) ) USING ( account_type_id ) WHERE service_id = ? AND hash_id = ? AND status = ?;', ( service_id, hash_id, HC.DELETED ) ).fetchone()
( account_id, account_type, created, expiry, used_bytes, used_requests ) = result
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that account in its database.' )
elif account_identifier.HasMapping():
try:
( hash, tag ) = account_identifier.GetData()
hash_id = self._GetHashId( c, hash )
tag_id = self._GetTagId( c, tag )
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that mapping in its database.' )
try: ( account_id, account_type, created, expiry, used_bytes, used_requests ) = c.execute( 'SELECT account_id, account_type, created, expires, used_bytes, used_requests FROM account_types, ( accounts, ( account_map, mappings USING ( service_id, account_id ) ) USING ( account_id ) ) USING ( account_type_id ) WHERE service_id = ? AND tag_id = ? AND hash_id = ?;', ( service_id, tag_id, hash_id ) ).fetchone()
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that account in its database.' )
( account_id, account_type, created, expiry, used_bytes, used_requests ) = c.execute( 'SELECT account_id, account_type, created, expires, used_bytes, used_requests FROM account_types, ( accounts, account_map USING ( account_id ) ) USING ( account_type_id ) WHERE service_id = ? AND account_key = ?;', ( service_id, sqlite3.Binary( account_key ) ) ).fetchone()
used_data = ( used_bytes, used_requests )
@ -1240,6 +1174,81 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
return account_info
def _GetAccountKey( self, c, service_key, account_identifier ):
if account_identifier.HasAccessKey():
access_key = account_identifier.GetData()
try: ( account_key, ) = c.execute( 'SELECT account_key FROM accounts WHERE access_key = ?;', ( sqlite3.Binary( hashlib.sha256( access_key ).digest() ), ) ).fetchone()
except:
# we do not delete the registration_key (and hence the raw unhashed access_key)
# until the first attempt to create a session to make sure the user
# has the access_key saved
try: ( account_type_id, account_key, expiry ) = c.execute( 'SELECT account_type_id, account_key, expiry FROM registration_keys WHERE access_key = ?;', ( sqlite3.Binary( access_key ), ) ).fetchone()
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that account in its database.' )
c.execute( 'DELETE FROM registration_keys WHERE access_key = ?;', ( sqlite3.Binary( access_key ), ) )
#
c.execute( 'INSERT INTO accounts ( account_key, access_key ) VALUES ( ?, ? );', ( sqlite3.Binary( account_key ), sqlite3.Binary( hashlib.sha256( access_key ).digest() ), ) )
account_id = c.lastrowid
now = HC.GetNow()
service_id = self._GetServiceId( c, service_key )
c.execute( 'INSERT INTO account_map ( service_id, account_id, account_type_id, created, expires, used_bytes, used_requests ) VALUES ( ?, ?, ?, ?, ?, ?, ? );', ( service_id, account_id, account_type_id, now, expiry, 0, 0 ) )
else:
if account_identifier.HasAccountId(): account_id = account_identifier.GetData()
elif account_identifier.HasHash():
service_id = self._GetServiceId( c, service_key )
try:
hash = account_identifier.GetData()
hash_id = self._GetHashId( c, hash )
result = c.execute( 'SELECT account_id FROM file_map WHERE service_id = ? AND hash_id = ?;', ( service_id, hash_id ) ).fetchone()
if result is None: result = c.execute( 'SELECT account_id FROM file_petitions WHERE service_id = ? AND hash_id = ? AND status = ?;', ( service_id, hash_id, HC.DELETED ) ).fetchone()
( account_id, ) = result
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that hash in its database.' )
elif account_identifier.HasMapping():
service_id = self._GetServiceId( c, service_key )
try:
( hash, tag ) = account_identifier.GetData()
hash_id = self._GetHashId( c, hash )
tag_id = self._GetTagId( c, tag )
( account_id, ) = c.execute( 'SELECT account_id FROM mappings WHERE service_id = ? AND tag_id = ? AND hash_id = ?;', ( service_id, tag_id, hash_id ) ).fetchone()
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that mapping in its database.' )
try: ( account_key, ) = c.execute( 'SELECT account_key FROM accounts WHERE account_id = ?;', ( account_id, ) ).fetchone()
except: raise HydrusExceptions.ForbiddenException( 'The service could not find that account in its database.' )
return account_key
def _GetAccountIdentifier( self, c, access_key ):
try: ( account_id, ) = c.execute( 'SELECT account_id FROM accounts WHERE access_key = ?;', ( sqlite3.Binary( hashlib.sha256( access_key ).digest() ), ) ).fetchone()
@ -1279,7 +1288,9 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
service_id = self._GetServiceId( c, service_key )
account = self._GetAccount( c, service_key, account_identifier )
account_key = self._GetAccountKey( c, service_key, account_identifier )
account = self._GetAccount( c, service_key, account_key )
account_id = account.GetAccountId()
@ -1372,7 +1383,9 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
account_identifier = HC.AccountIdentifier( account_id = account_id )
account = self._GetAccount( c, service_key, account_identifier )
account_key = self._GetAccountKey( c, service_key, account_identifier )
account = self._GetAccount( c, service_key, account_key )
processed_tuples.append( ( account, identifier, name, expiry ) )
@ -1514,9 +1527,11 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
account_identifier = HC.AccountIdentifier( account_id = account_id )
account = self._GetAccount( c, service_key, account_identifier )
account_key = self._GetAccountKey( c, service_key, account_identifier )
sessions.append( ( session_key, service_key, account, expiry ) )
account = self._GetAccount( c, service_key, account_key )
sessions.append( ( session_key, service_key, account_key, account, expiry ) )
return sessions
@ -1576,7 +1591,9 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
admin_account_id = admin_account.GetAccountId()
subjects = [ self._GetAccount( c, service_key, subject_identifier ) for subject_identifier in subject_identifiers ]
subject_account_keys = [ self._GetAccountKey( c, service_key, subject_identifier ) for subject_identifier in subject_identifiers ]
subjects = [ self._GetAccount( c, service_key, subject_account_key ) for subject_account_key in subject_account_keys ]
subject_account_ids = [ subject.GetAccountId() for subject in subjects ]
@ -1958,6 +1975,19 @@ class ServiceDB( FileDB, MessageDB, TagDB ):
def _UnbanKey( self, c, service_id, account_id ): c.execute( 'DELETE FROM bans WHERE service_id = ? AND account_id = ?;', ( account_id, ) )
def _VerifyAccessKey( self, c, service_key, access_key ):
try:
service_id = self._GetServiceId( c, service_key )
( account_key, ) = c.execute( 'SELECT account_key FROM accounts, account_map USING ( account_id ) WHERE service_id = ? AND access_key = ?;', ( service_id, sqlite3.Binary( hashlib.sha256( access_key ).digest() ) ) ).fetchone()
return True
except: return False
class DB( ServiceDB ):
def __init__( self ):
@ -1976,6 +2006,8 @@ class DB( ServiceDB ):
( version, ) = c.execute( 'SELECT version FROM version;' ).fetchone()
if version < HC.SOFTWARE_VERSION - 50: raise Exception( 'Your current version of hydrus ' + HC.u( version ) + ' is too old for this version ' + HC.u( HC.SOFTWARE_VERSION ) + ' to update. Please try updating with version ' + HC.u( version + 45 ) + ' or earlier first.' )
while version < HC.SOFTWARE_VERSION:
time.sleep( 1 )
@ -2050,7 +2082,8 @@ class DB( ServiceDB ):
c.execute( 'CREATE TABLE services ( service_id INTEGER PRIMARY KEY, service_key BLOB_BYTES, type INTEGER, options TEXT_YAML );' )
c.execute( 'CREATE TABLE accounts ( account_id INTEGER PRIMARY KEY, access_key BLOB_BYTES );' )
c.execute( 'CREATE TABLE accounts ( account_id INTEGER PRIMARY KEY, account_key BLOB_BYTES, access_key BLOB_BYTES );' )
c.execute( 'CREATE UNIQUE INDEX accounts_account_key_index ON accounts ( account_key );' )
c.execute( 'CREATE UNIQUE INDEX accounts_access_key_index ON accounts ( access_key );' )
c.execute( 'CREATE TABLE account_map ( service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, account_type_id INTEGER, created INTEGER, expires INTEGER, used_bytes INTEGER, used_requests INTEGER, PRIMARY KEY( service_id, account_id ) );' )
@ -2111,7 +2144,7 @@ class DB( ServiceDB ):
c.execute( 'CREATE TABLE reasons ( reason_id INTEGER PRIMARY KEY, reason TEXT );' )
c.execute( 'CREATE UNIQUE INDEX reasons_reason_index ON reasons ( reason );' )
c.execute( 'CREATE TABLE registration_keys ( registration_key BLOB_BYTES PRIMARY KEY, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_type_id INTEGER, access_key BLOB_BYTES, expiry INTEGER );' )
c.execute( 'CREATE TABLE registration_keys ( registration_key BLOB_BYTES PRIMARY KEY, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_type_id INTEGER, account_key BLOB_BYTES, access_key BLOB_BYTES, expiry INTEGER );' )
c.execute( 'CREATE UNIQUE INDEX registration_keys_access_key_index ON registration_keys ( access_key );' )
c.execute( 'CREATE TABLE sessions ( session_key BLOB_BYTES, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, expiry INTEGER );' )
@ -2193,422 +2226,6 @@ class DB( ServiceDB ):
def _UpdateDB( self, c, version ):
self._UpdateDBOld( c, version )
if version == 93:
c.execute( 'CREATE TABLE messaging_sessions ( service_id INTEGER REFERENCES services ON DELETE CASCADE, session_key BLOB_BYTES, account_id INTEGER, identifier BLOB_BYTES, name TEXT, expiry INTEGER );' )
if version == 108:
data = c.execute( 'SELECT service_id, begin, end FROM update_cache;' ).fetchall()
c.execute( 'DROP TABLE update_cache;' )
c.execute( 'CREATE TABLE update_cache ( service_id INTEGER REFERENCES services ON DELETE CASCADE, begin INTEGER, end INTEGER, dirty INTEGER_BOOLEAN, PRIMARY KEY( service_id, begin ) );' )
c.execute( 'CREATE UNIQUE INDEX update_cache_service_id_end_index ON update_cache ( service_id, end );' )
c.execute( 'CREATE INDEX update_cache_service_id_dirty_index ON update_cache ( service_id, dirty );' )
c.executemany( 'INSERT INTO update_cache ( service_id, begin, end, dirty ) VALUES ( ?, ?, ?, ? );', ( ( service_id, begin, end, True ) for ( service_id, begin, end ) in data ) )
stuff_in_updates_dir = dircache.listdir( HC.SERVER_UPDATES_DIR )
for filename in stuff_in_updates_dir:
path = HC.SERVER_UPDATES_DIR + os.path.sep + filename
if os.path.isdir( path ): shutil.rmtree( path )
else: os.remove( path )
c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )
def _UpdateDBOld( self, c, version ):
if version == 28:
files_db_path = HC.DB_DIR + os.path.sep + 'server_files.db'
c.execute( 'COMMIT' )
# can't do it inside a transaction
c.execute( 'ATTACH database "' + files_db_path + '" as files_db;' )
c.execute( 'BEGIN IMMEDIATE' )
os.mkdir( HC.SERVER_FILES_DIR )
all_local_files = [ hash_id for ( hash_id, ) in c.execute( 'SELECT hash_id FROM files;' ) ]
for i in range( 0, len( all_local_files ), 100 ):
local_files_subset = all_local_files[ i : i + 100 ]
for hash_id in local_files_subset:
hash = self._GetHash( c, hash_id )
( file, ) = c.execute( 'SELECT file FROM files WHERE hash_id = ?', ( hash_id, ) ).fetchone()
path_to = HC.SERVER_FILES_DIR + os.path.sep + hash.encode( 'hex' )
with open( path_to, 'wb' ) as f: f.write( file )
c.execute( 'DELETE FROM files WHERE hash_id IN ' + HC.SplayListForDB( local_files_subset ) + ';' )
c.execute( 'COMMIT' )
# slow truncate happens here!
c.execute( 'BEGIN IMMEDIATE' )
c.execute( 'COMMIT' )
# can't do it inside a transaction
c.execute( 'DETACH DATABASE files_db;' )
c.execute( 'BEGIN IMMEDIATE' )
os.remove( files_db_path )
if version == 29:
thumbnails_db_path = HC.DB_DIR + os.path.sep + 'server_thumbnails.db'
c.execute( 'COMMIT' )
# can't do it inside a transaction
c.execute( 'ATTACH database "' + thumbnails_db_path + '" as thumbnails_db;' )
os.mkdir( HC.SERVER_THUMBNAILS_DIR )
all_thumbnails = c.execute( 'SELECT DISTINCT hash_id, hash FROM thumbnails, hashes USING ( hash_id );' ).fetchall()
for i in range( 0, len( all_thumbnails ), 500 ):
thumbnails_subset = all_thumbnails[ i : i + 500 ]
for ( hash_id, hash ) in thumbnails_subset:
( thumbnail, ) = c.execute( 'SELECT thumbnail FROM thumbnails WHERE hash_id = ?', ( hash_id, ) ).fetchone()
path_to = HC.SERVER_THUMBNAILS_DIR + os.path.sep + hash.encode( 'hex' )
with open( path_to, 'wb' ) as f: f.write( thumbnail )
# can't do it inside a transaction
c.execute( 'DETACH DATABASE thumbnails_db;' )
c.execute( 'BEGIN IMMEDIATE' )
os.remove( thumbnails_db_path )
if version == 34:
main_db_path = HC.DB_DIR + os.path.sep + 'server_main.db'
files_info_db_path = HC.DB_DIR + os.path.sep + 'server_files_info.db'
mappings_db_path = HC.DB_DIR + os.path.sep + 'server_mappings.db'
updates_db_path = HC.DB_DIR + os.path.sep + 'server_updates.db'
if os.path.exists( main_db_path ):
c.execute( 'COMMIT' )
c.execute( 'ATTACH database "' + main_db_path + '" as main_db;' )
c.execute( 'ATTACH database "' + files_info_db_path + '" as files_info_db;' )
c.execute( 'ATTACH database "' + mappings_db_path + '" as mappings_db;' )
c.execute( 'ATTACH database "' + updates_db_path + '" as updates_db;' )
c.execute( 'BEGIN IMMEDIATE' )
c.execute( 'REPLACE INTO main.services SELECT * FROM main_db.services;' )
all_service_ids = [ service_id for ( service_id, ) in c.execute( 'SELECT service_id FROM main.services;' ) ]
c.execute( 'DELETE FROM main_db.account_map WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM main_db.account_scores WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM main_db.account_type_map WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM main_db.bans WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM main_db.news WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM mappings_db.deleted_mappings WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM mappings_db.mappings WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM mappings_db.mapping_petitions WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM files_info_db.deleted_files WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM files_info_db.file_map WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM files_info_db.ip_addresses WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM files_info_db.file_petitions WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'DELETE FROM updates_db.update_cache WHERE service_id NOT IN ' + HC.SplayListForDB( all_service_ids ) + ';' )
c.execute( 'REPLACE INTO main.accounts SELECT * FROM main_db.accounts;' )
c.execute( 'REPLACE INTO main.account_map SELECT * FROM main_db.account_map;' )
c.execute( 'REPLACE INTO main.account_scores SELECT * FROM main_db.account_scores;' )
c.execute( 'REPLACE INTO main.account_type_map SELECT * FROM main_db.account_type_map;' )
c.execute( 'REPLACE INTO main.account_types SELECT * FROM main_db.account_types;' )
c.execute( 'REPLACE INTO main.bans SELECT * FROM main_db.bans;' )
c.execute( 'REPLACE INTO main.hashes SELECT * FROM main_db.hashes;' )
c.execute( 'REPLACE INTO main.news SELECT * FROM main_db.news;' )
c.execute( 'REPLACE INTO main.reasons SELECT * FROM main_db.reasons;' )
c.execute( 'REPLACE INTO main.tags SELECT * FROM main_db.tags;' )
# don't do version, lol
c.execute( 'REPLACE INTO main.deleted_mappings SELECT * FROM mappings_db.deleted_mappings;' )
c.execute( 'REPLACE INTO main.mappings SELECT * FROM mappings_db.mappings;' )
c.execute( 'REPLACE INTO main.mapping_petitions SELECT * FROM mappings_db.mapping_petitions;' )
c.execute( 'REPLACE INTO main.deleted_files SELECT * FROM files_info_db.deleted_files;' )
c.execute( 'REPLACE INTO main.files_info SELECT * FROM files_info_db.files_info;' )
c.execute( 'REPLACE INTO main.file_map SELECT * FROM files_info_db.file_map;' )
c.execute( 'REPLACE INTO main.file_petitions SELECT * FROM files_info_db.file_petitions;' )
c.execute( 'REPLACE INTO main.ip_addresses SELECT * FROM files_info_db.ip_addresses;' )
c.execute( 'REPLACE INTO main.update_cache SELECT * FROM updates_db.update_cache;' )
c.execute( 'COMMIT' )
c.execute( 'DETACH database main_db;' )
c.execute( 'DETACH database files_info_db;' )
c.execute( 'DETACH database mappings_db;' )
c.execute( 'DETACH database updates_db;' )
os.remove( main_db_path )
os.remove( mappings_db_path )
os.remove( files_info_db_path )
os.remove( updates_db_path )
c.execute( 'BEGIN IMMEDIATE' )
if version == 36:
os.mkdir( HC.SERVER_MESSAGES_DIR )
c.execute( 'CREATE TABLE contacts ( service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, contact_key BLOB, public_key TEXT, PRIMARY KEY( service_id, account_id ) );' )
c.execute( 'CREATE UNIQUE INDEX contacts_contact_key_index ON contacts ( contact_key );' )
c.execute( 'CREATE TABLE messages ( message_key BLOB PRIMARY KEY, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, timestamp INTEGER );' )
c.execute( 'CREATE INDEX messages_service_id_account_id_index ON messages ( service_id, account_id );' )
c.execute( 'CREATE INDEX messages_timestamp_index ON messages ( timestamp );' )
if version == 37:
c.execute( 'COMMIT' )
c.execute( 'PRAGMA journal_mode=WAL;' ) # possibly didn't work last time, cause of sqlite dll issue
c.execute( 'BEGIN IMMEDIATE' )
c.execute( 'DROP TABLE messages;' ) # blob instead of blob_bytes!
c.execute( 'CREATE TABLE messages ( message_key BLOB_BYTES PRIMARY KEY, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, timestamp INTEGER );' )
c.execute( 'CREATE INDEX messages_service_id_account_id_index ON messages ( service_id, account_id );' )
c.execute( 'CREATE INDEX messages_timestamp_index ON messages ( timestamp );' )
c.execute( 'CREATE TABLE message_statuses ( status_key BLOB_BYTES PRIMARY KEY, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, status BLOB_BYTES, timestamp INTEGER );' )
c.execute( 'CREATE INDEX message_statuses_service_id_account_id_index ON message_statuses ( service_id, account_id );' )
c.execute( 'CREATE INDEX message_statuses_timestamp_index ON message_statuses ( timestamp );' )
if version == 39:
try: c.execute( 'SELECT 1 FROM message_statuses;' ).fetchone() # didn't update dbinit on 38
except:
c.execute( 'DROP TABLE messages;' ) # blob instead of blob_bytes!
c.execute( 'CREATE TABLE messages ( message_key BLOB_BYTES PRIMARY KEY, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, timestamp INTEGER );' )
c.execute( 'CREATE INDEX messages_service_id_account_id_index ON messages ( service_id, account_id );' )
c.execute( 'CREATE INDEX messages_timestamp_index ON messages ( timestamp );' )
c.execute( 'CREATE TABLE message_statuses ( status_key BLOB_BYTES PRIMARY KEY, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, status BLOB_BYTES, timestamp INTEGER );' )
c.execute( 'CREATE INDEX message_statuses_service_id_account_id_index ON message_statuses ( service_id, account_id );' )
c.execute( 'CREATE INDEX message_statuses_timestamp_index ON message_statuses ( timestamp );' )
if version == 40:
c.execute( 'CREATE TABLE ratings ( service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, hash_id INTEGER, rating REAL, PRIMARY KEY( service_id, account_id, hash_id ) );' )
c.execute( 'CREATE INDEX ratings_hash_id ON ratings ( hash_id );' )
c.execute( 'CREATE TABLE ratings_aggregates ( service_id INTEGER REFERENCES services ON DELETE CASCADE, hash_id INTEGER, score INTEGER, count INTEGER, new_timestamp INTEGER, current_timestamp INTEGER, PRIMARY KEY( service_id, hash_id ) );' )
c.execute( 'CREATE INDEX ratings_aggregates_new_timestamp ON ratings_aggregates ( new_timestamp );' )
c.execute( 'CREATE INDEX ratings_aggregates_current_timestamp ON ratings_aggregates ( current_timestamp );' )
if version == 50:
if not os.path.exists( HC.SERVER_UPDATES_DIR ): os.mkdir( HC.SERVER_UPDATES_DIR )
all_update_data = c.execute( 'SELECT * FROM update_cache;' ).fetchall()
c.execute( 'DROP TABLE update_cache;' )
c.execute( 'CREATE TABLE update_cache ( service_id INTEGER REFERENCES services ON DELETE CASCADE, begin INTEGER, end INTEGER, update_key TEXT, dirty INTEGER_BOOLEAN, PRIMARY KEY( service_id, begin ) );' )
c.execute( 'CREATE UNIQUE INDEX update_cache_service_id_end_index ON update_cache ( service_id, end );' )
c.execute( 'CREATE INDEX update_cache_service_id_dirty_index ON update_cache ( service_id, dirty );' )
for ( service_id, begin, end, update, dirty ) in all_update_data:
update_key_bytes = os.urandom( 32 )
update_key = update_key_bytes.encode( 'hex' )
with open( HC.SERVER_UPDATES_DIR + os.path.sep + update_key, 'wb' ) as f: f.write( update )
c.execute( 'INSERT INTO update_cache ( service_id, begin, end, update_key, dirty ) VALUES ( ?, ?, ?, ?, ? );', ( service_id, begin, end, update_key, dirty ) )
if version == 55:
c.execute( 'DROP INDEX mappings_service_id_account_id_index;' )
c.execute( 'DROP INDEX mappings_service_id_timestamp_index;' )
c.execute( 'CREATE INDEX mappings_account_id_index ON mappings ( account_id );' )
c.execute( 'CREATE INDEX mappings_timestamp_index ON mappings ( timestamp );' )
if version == 60:
c.execute( 'CREATE TABLE sessions ( session_key BLOB_BYTES, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, expiry INTEGER );' )
c.execute( 'CREATE TABLE registration_keys ( registration_key BLOB_BYTES PRIMARY KEY, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_type_id INTEGER, access_key BLOB_BYTES, expiry INTEGER );' )
c.execute( 'CREATE UNIQUE INDEX registration_keys_access_key_index ON registration_keys ( access_key );' )
if version == 67:
dirs = ( HC.SERVER_FILES_DIR, HC.SERVER_THUMBNAILS_DIR, HC.SERVER_UPDATES_DIR, HC.SERVER_MESSAGES_DIR )
hex_chars = '0123456789abcdef'
for dir in dirs:
for ( one, two ) in itertools.product( hex_chars, hex_chars ):
new_dir = dir + os.path.sep + one + two
if not os.path.exists( new_dir ): os.mkdir( new_dir )
filenames = dircache.listdir( dir )
for filename in filenames:
try:
source_path = dir + os.path.sep + filename
first_two_chars = filename[:2]
destination_path = dir + os.path.sep + first_two_chars + os.path.sep + filename
shutil.move( source_path, destination_path )
except: continue
if version == 70:
try: c.execute( 'CREATE INDEX mappings_account_id_index ON mappings ( account_id );' )
except: pass
try: c.execute( 'CREATE INDEX mappings_timestamp_index ON mappings ( timestamp );' )
except: pass
if version == 71:
c.execute( 'ANALYZE' )
#
now = HC.GetNow()
#
petitioned_inserts = [ ( service_id, account_id, hash_id, reason_id, now, HC.PETITIONED ) for ( service_id, account_id, hash_id, reason_id ) in c.execute( 'SELECT service_id, account_id, hash_id, reason_id FROM file_petitions;' ) ]
deleted_inserts = [ ( service_id, account_id, hash_id, reason_id, timestamp, HC.DELETED ) for ( service_id, account_id, hash_id, reason_id, timestamp ) in c.execute( 'SELECT service_id, admin_account_id, hash_id, reason_id, timestamp FROM deleted_files;' ) ]
c.execute( 'DROP TABLE file_petitions;' )
c.execute( 'DROP TABLE deleted_files;' )
c.execute( 'CREATE TABLE file_petitions ( service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, hash_id INTEGER, reason_id INTEGER, timestamp INTEGER, status INTEGER, PRIMARY KEY( service_id, account_id, hash_id, status ) );' )
c.execute( 'CREATE INDEX file_petitions_service_id_account_id_reason_id_index ON file_petitions ( service_id, account_id, reason_id );' )
c.execute( 'CREATE INDEX file_petitions_service_id_hash_id_index ON file_petitions ( service_id, hash_id );' )
c.execute( 'CREATE INDEX file_petitions_service_id_status_index ON file_petitions ( service_id, status );' )
c.execute( 'CREATE INDEX file_petitions_service_id_timestamp_index ON file_petitions ( service_id, timestamp );' )
c.executemany( 'INSERT INTO file_petitions VALUES ( ?, ?, ?, ?, ?, ? );', petitioned_inserts )
c.executemany( 'INSERT INTO file_petitions VALUES ( ?, ?, ?, ?, ?, ? );', deleted_inserts )
#
petitioned_inserts = [ ( service_id, account_id, tag_id, hash_id, reason_id, now, HC.PETITIONED ) for ( service_id, account_id, tag_id, hash_id, reason_id ) in c.execute( 'SELECT service_id, account_id, tag_id, hash_id, reason_id FROM mapping_petitions;' ) ]
deleted_inserts = [ ( service_id, account_id, tag_id, hash_id, reason_id, timestamp, HC.DELETED ) for ( service_id, account_id, tag_id, hash_id, reason_id, timestamp ) in c.execute( 'SELECT service_id, admin_account_id, tag_id, hash_id, reason_id, timestamp FROM deleted_mappings;' ) ]
c.execute( 'DROP TABLE mapping_petitions;' )
c.execute( 'DROP TABLE deleted_mappings;' )
c.execute( 'CREATE TABLE mapping_petitions ( service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, tag_id INTEGER, hash_id INTEGER, reason_id INTEGER, timestamp INTEGER, status INTEGER, PRIMARY KEY( service_id, account_id, tag_id, hash_id, status ) );' )
c.execute( 'CREATE INDEX mapping_petitions_service_id_account_id_reason_id_tag_id_index ON mapping_petitions ( service_id, account_id, reason_id, tag_id );' )
c.execute( 'CREATE INDEX mapping_petitions_service_id_tag_id_hash_id_index ON mapping_petitions ( service_id, tag_id, hash_id );' )
c.execute( 'CREATE INDEX mapping_petitions_service_id_status_index ON mapping_petitions ( service_id, status );' )
c.execute( 'CREATE INDEX mapping_petitions_service_id_timestamp_index ON mapping_petitions ( service_id, timestamp );' )
c.executemany( 'INSERT INTO mapping_petitions VALUES ( ?, ?, ?, ?, ?, ?, ? );', petitioned_inserts )
c.executemany( 'INSERT INTO mapping_petitions VALUES ( ?, ?, ?, ?, ?, ?, ? );', deleted_inserts )
#
try:
c.execute( 'DROP TABLE tag_siblings;' )
c.execute( 'DROP TABLE deleted_tag_siblings;' )
c.execute( 'DROP TABLE pending_tag_siblings;' )
c.execute( 'DROP TABLE tag_sibling_petitions;' )
except: pass
c.execute( 'CREATE TABLE tag_siblings ( service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, old_tag_id INTEGER, new_tag_id INTEGER, timestamp INTEGER, status INTEGER, reason_id INTEGER, PRIMARY KEY ( service_id, account_id, old_tag_id, status ) );' )
c.execute( 'CREATE INDEX tag_siblings_service_id_old_tag_id_index ON tag_siblings ( service_id, old_tag_id );' )
c.execute( 'CREATE INDEX tag_siblings_service_id_timestamp_index ON tag_siblings ( service_id, timestamp );' )
c.execute( 'CREATE INDEX tag_siblings_service_id_status_index ON tag_siblings ( service_id, status );' )
#
c.execute( 'CREATE TABLE tag_parents ( service_id INTEGER REFERENCES services ON DELETE CASCADE, account_id INTEGER, old_tag_id INTEGER, new_tag_id INTEGER, timestamp INTEGER, status INTEGER, reason_id INTEGER, PRIMARY KEY ( service_id, account_id, old_tag_id, new_tag_id, status ) );' )
c.execute( 'CREATE INDEX tag_parents_service_id_old_tag_id_index ON tag_parents ( service_id, old_tag_id, new_tag_id );' )
c.execute( 'CREATE INDEX tag_parents_service_id_timestamp_index ON tag_parents ( service_id, timestamp );' )
c.execute( 'CREATE INDEX tag_parents_service_id_status_index ON tag_parents ( service_id, status );' )
# update objects have changed
results = c.execute( 'SELECT service_id, begin, end FROM update_cache WHERE begin = 0;' ).fetchall()
c.execute( 'DELETE FROM update_cache;' )
update_paths = [ path for path in SC.IterateAllPaths( 'update' ) ]
for path in update_paths: os.remove( path )
for ( service_id, begin, end ) in results: self._CreateUpdate( c, service_id, begin, end )
if version == 86:
c.execute( 'COMMIT' )
@ -2650,6 +2267,86 @@ class DB( ServiceDB ):
if version == 93:
c.execute( 'CREATE TABLE messaging_sessions ( service_id INTEGER REFERENCES services ON DELETE CASCADE, session_key BLOB_BYTES, account_id INTEGER, identifier BLOB_BYTES, name TEXT, expiry INTEGER );' )
if version == 108:
data = c.execute( 'SELECT service_id, begin, end FROM update_cache;' ).fetchall()
c.execute( 'DROP TABLE update_cache;' )
c.execute( 'CREATE TABLE update_cache ( service_id INTEGER REFERENCES services ON DELETE CASCADE, begin INTEGER, end INTEGER, dirty INTEGER_BOOLEAN, PRIMARY KEY( service_id, begin ) );' )
c.execute( 'CREATE UNIQUE INDEX update_cache_service_id_end_index ON update_cache ( service_id, end );' )
c.execute( 'CREATE INDEX update_cache_service_id_dirty_index ON update_cache ( service_id, dirty );' )
c.executemany( 'INSERT INTO update_cache ( service_id, begin, end, dirty ) VALUES ( ?, ?, ?, ? );', ( ( service_id, begin, end, True ) for ( service_id, begin, end ) in data ) )
stuff_in_updates_dir = dircache.listdir( HC.SERVER_UPDATES_DIR )
for filename in stuff_in_updates_dir:
path = HC.SERVER_UPDATES_DIR + os.path.sep + filename
if os.path.isdir( path ): shutil.rmtree( path )
else: os.remove( path )
if version == 128:
c.execute( 'COMMIT' )
c.execute( 'PRAGMA foreign_keys = OFF;' )
c.execute( 'BEGIN IMMEDIATE' )
#
old_account_info = c.execute( 'SELECT * FROM accounts;' ).fetchall()
c.execute( 'DROP TABLE accounts;' )
c.execute( 'CREATE TABLE accounts ( account_id INTEGER PRIMARY KEY, account_key BLOB_BYTES, access_key BLOB_BYTES );' )
c.execute( 'CREATE UNIQUE INDEX accounts_account_key_index ON accounts ( account_key );' )
c.execute( 'CREATE UNIQUE INDEX accounts_access_key_index ON accounts ( access_key );' )
for ( account_id, access_key ) in old_account_info:
account_key = os.urandom( 32 )
c.execute( 'INSERT INTO accounts ( account_id, account_key, access_key ) VALUES ( ?, ?, ? );', ( account_id, sqlite3.Binary( account_key ), sqlite3.Binary( access_key ) ) )
#
old_r_k_info = c.execute( 'SELECT * FROM registration_keys;' ).fetchall()
c.execute( 'DROP TABLE registration_keys;' )
c.execute( 'CREATE TABLE registration_keys ( registration_key BLOB_BYTES PRIMARY KEY, service_id INTEGER REFERENCES services ON DELETE CASCADE, account_type_id INTEGER, account_key BLOB_BYTES, access_key BLOB_BYTES, expiry INTEGER );' )
c.execute( 'CREATE UNIQUE INDEX registration_keys_access_key_index ON registration_keys ( access_key );' )
for ( registration_key, service_id, account_type_id, access_key, expiry ) in old_r_k_info:
account_key = os.urandom( 32 )
c.execute( 'INSERT INTO registration_keys ( registration_key, service_id, account_type_id, account_key, access_key, expiry ) VALUES ( ?, ?, ?, ?, ?, ? );', ( sqlite3.Binary( registration_key ), service_id, account_type_id, sqlite3.Binary( account_key ), sqlite3.Binary( access_key ), expiry ) )
#
c.execute( 'COMMIT' )
c.execute( 'PRAGMA foreign_keys = ON;' )
c.execute( 'BEGIN IMMEDIATE' )
c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )
def pub_after_commit( self, topic, *args, **kwargs ): self._pubsubs.append( ( topic, args, kwargs ) )
@ -2662,6 +2359,7 @@ class DB( ServiceDB ):
if action == 'access_key': result = self._GetAccessKey( c, *args, **kwargs )
elif action == 'account': result = self._GetAccount( c, *args, **kwargs )
elif action == 'account_info': result = self._GetAccountInfo( c, *args, **kwargs )
elif action == 'account_key': result = self._GetAccountKey( c, *args, **kwargs )
elif action == 'account_types': result = self._GetAccountTypes( c, *args, **kwargs )
elif action == 'dirty_updates': result = self._GetDirtyUpdates( c, *args, **kwargs )
elif action == 'init': result = self._InitAdmin( c, *args, **kwargs )
@ -2675,6 +2373,7 @@ class DB( ServiceDB ):
elif action == 'sessions': result = self._GetSessions( c, *args, **kwargs )
elif action == 'stats': result = self._GetStats( c, *args, **kwargs )
elif action == 'update_ends': result = self._GetUpdateEnds( c, *args, **kwargs )
elif action == 'verify_access_key': result = self._VerifyAccessKey( c, *args, **kwargs )
else: raise Exception( 'db received an unknown read command: ' + action )
return result

View File

@ -48,10 +48,10 @@ class TestManagers( unittest.TestCase ):
def test_services( self ):
def test_service( service, key, type, name, info ):
def test_service( service, key, service_type, name, info ):
self.assertEqual( service.GetKey(), key )
self.assertEqual( service.GetType(), type )
self.assertEqual( service.GetType(), service_type )
self.assertEqual( service.GetName(), name )
self.assertEqual( service.GetInfo(), info )

View File

@ -196,6 +196,8 @@ class TestServer( unittest.TestCase ):
def _test_local_booru( self, host, port ):
#
connection = httplib.HTTPConnection( host, port, timeout = 10 )
#
@ -289,15 +291,9 @@ class TestServer( unittest.TestCase ):
def _test_repo( self, host, port, service_type ):
def _test_repo( self, service, host, port ):
info = {}
info[ 'host' ] = host
info[ 'port' ] = port
info[ 'access_key' ] = self._access_key
service = CC.Service( os.urandom( 32 ), service_type, 'service', info )
service_key = service.GetKey()
# news
@ -338,8 +334,7 @@ class TestServer( unittest.TestCase ):
update = 'update'
begin = 100
if service_type == HC.FILE_REPOSITORY: path = SC.GetExpectedUpdatePath( self._file_service_key, begin )
elif service_type == HC.TAG_REPOSITORY: path = SC.GetExpectedUpdatePath( self._tag_service_key, begin )
path = SC.GetExpectedUpdatePath( service_key, begin )
with open( path, 'wb' ) as f: f.write( update )
@ -389,6 +384,7 @@ class TestServer( unittest.TestCase ):
HC.app.SetRead( 'service', service )
HC.app.SetRead( 'account_key', os.urandom( 32 ) )
HC.app.SetRead( 'account', self._account )
# account
@ -514,7 +510,7 @@ class TestServer( unittest.TestCase ):
self.assertEqual( edit_log, written_edit_log )
def _test_tag_repo( self, host, port ):
def _test_tag_repo( self, service, host, port ):
pass
@ -655,6 +651,7 @@ class TestAMP( unittest.TestCase ):
account = HC.Account( account_id, account_type, created, expiry, used_data )
HC.app.SetRead( 'account_key', os.urandom( 32 ) )
HC.app.SetRead( 'account', account )
deferred = protocol.callRemote( HydrusServerAMP.IMSessionKey, access_key = access_key, name = name )

View File

@ -21,14 +21,16 @@ class TestSessions( unittest.TestCase ):
account_id = 1
account_type = HC.AccountType( 'account', permissions, ( None, None ) )
created = HC.GetNow() - 100000
expiry = None
expiry = HC.GetNow() + 300
used_data = ( 0, 0 )
account_key = os.urandom( 32 )
account = HC.Account( account_id, account_type, created, expiry, used_data )
expiry = HC.GetNow() - 10
HC.app.SetRead( 'sessions', [ ( session_key_1, service_key, account, expiry ) ] )
HC.app.SetRead( 'sessions', [ ( session_key_1, service_key, account_key, account, expiry ) ] )
session_manager = HydrusSessions.HydrusSessionManagerServer()
@ -37,11 +39,11 @@ class TestSessions( unittest.TestCase ):
session_manager.GetAccount( service_key, session_key_1 )
#
# test fetching a session already in db, after bootup
expiry = HC.GetNow() + 10000
expiry = HC.GetNow() + 300
HC.app.SetRead( 'sessions', [ ( session_key_1, service_key, account, expiry ) ] )
HC.app.SetRead( 'sessions', [ ( session_key_1, service_key, account_key, account, expiry ) ] )
session_manager = HydrusSessions.HydrusSessionManagerServer()
@ -49,12 +51,15 @@ class TestSessions( unittest.TestCase ):
self.assertIs( read_account, account )
#
# test adding a session
expiry = None
expiry = HC.GetNow() + 300
account_key_2 = os.urandom( 32 )
account_2 = HC.Account( 2, account_type, created, expiry, used_data )
HC.app.SetRead( 'account_key', account_key_2 )
HC.app.SetRead( 'account', account_2 )
account_identifier = HC.AccountIdentifier( access_key = os.urandom( 32 ) )
@ -71,8 +76,9 @@ class TestSessions( unittest.TestCase ):
self.assertIs( read_account, account_2 )
#
# test adding a new session for an account already in the manager
HC.app.SetRead( 'account_key', account_key )
HC.app.SetRead( 'account', account )
account_identifier = HC.AccountIdentifier( access_key = os.urandom( 32 ) )
@ -89,12 +95,17 @@ class TestSessions( unittest.TestCase ):
self.assertIs( read_account, account )
#
read_account_original = session_manager.GetAccount( service_key, session_key_1 )
expiry = None
self.assertIs( read_account, read_account_original )
updated_account = HC.Account( 1, account_type, created, expiry, ( 1, 1 ) )
# test individual account refresh
expiry = HC.GetNow() + 300
updated_account = HC.Account( account_id, account_type, created, expiry, ( 1, 1 ) )
HC.app.SetRead( 'account_key', account_key )
HC.app.SetRead( 'account', updated_account )
account_identifier = HC.AccountIdentifier( access_key = os.urandom( 32 ) )
@ -109,13 +120,15 @@ class TestSessions( unittest.TestCase ):
self.assertIs( read_account, updated_account )
#
# test all account refresh
expiry = None
expiry = HC.GetNow() + 300
updated_account_key = os.urandom( 32 )
updated_account_2 = HC.Account( 1, account_type, created, expiry, ( 2, 2 ) )
HC.app.SetRead( 'sessions', [ ( session_key_1, service_key, updated_account_2, expiry ), ( session_key_2, service_key, account_2, expiry ), ( session_key_3, service_key, updated_account_2, expiry ) ] )
HC.app.SetRead( 'sessions', [ ( session_key_1, service_key, updated_account_key, updated_account_2, expiry ), ( session_key_2, service_key, account_key_2, account_2, expiry ), ( session_key_3, service_key, account_key_2, updated_account_2, expiry ) ] )
session_manager.RefreshAllAccounts()

17
test.py
View File

@ -54,7 +54,7 @@ class App( wx.App ):
self._reads[ 'options' ] = CC.CLIENT_DEFAULT_OPTIONS
services = []
services.append( CC.Service( HC.LOCAL_BOORU_SERVICE_KEY, HC.LOCAL_BOORU, HC.LOCAL_BOORU_SERVICE_KEY, {} ) )
services.append( CC.Service( HC.LOCAL_BOORU_SERVICE_KEY, HC.LOCAL_BOORU, HC.LOCAL_BOORU_SERVICE_KEY, { 'max_monthly_data' : None, 'used_monthly_data' : 0 } ) )
services.append( CC.Service( HC.LOCAL_FILE_SERVICE_KEY, HC.LOCAL_FILE, HC.LOCAL_FILE_SERVICE_KEY, {} ) )
services.append( CC.Service( HC.LOCAL_TAG_SERVICE_KEY, HC.LOCAL_TAG, HC.LOCAL_TAG_SERVICE_KEY, {} ) )
self._reads[ 'services' ] = services
@ -82,19 +82,6 @@ class App( wx.App ):
self._managers[ 'web_sessions' ] = TestConstants.FakeWebSessionManager()
self._managers[ 'restricted_services_sessions' ] = HydrusSessions.HydrusSessionManagerServer()
self._managers[ 'messaging_sessions' ] = HydrusSessions.HydrusMessagingSessionManagerServer()
info = {}
info[ 'max_monthly_data' ] = None
info[ 'used_monthly_data' ] = 0
service_key = HC.LOCAL_BOORU_SERVICE_KEY
service_type = HC.LOCAL_BOORU
name = HC.LOCAL_BOORU_SERVICE_KEY
service = CC.Service( service_key, service_type, name, info )
HC.app.SetRead( 'service', service )
self._managers[ 'local_booru' ] = CC.LocalBooruCache()
self._cookies = {}
@ -130,7 +117,7 @@ class App( wx.App ):
return True
def GetManager( self, type ): return self._managers[ type ]
def GetManager( self, manager_type ): return self._managers[ manager_type ]
def GetWrite( self, name ):