1 from optparse
import make_option
2 from itertools
import count
3 from functools
import partial
5 from django
.core
.management
.base
import BaseCommand
7 from mygpo
.utils
import progress
, multi_request_view
8 from mygpo
.users
.models
import EpisodeUserState
9 from mygpo
.counter
import Counter
10 from mygpo
.maintenance
.merge
import merge_episode_states
11 from mygpo
.couch
import bulk_save_retry
, get_main_database
14 class Command(BaseCommand
):
15 """ Merge duplicate EpisodeUserState documents """
17 option_list
= BaseCommand
.option_list
+ (
18 make_option('--skip', action
='store', type=int, dest
='skip', default
=0,
19 help="Number of states to skip"),
22 def handle(self
, *args
, **options
):
24 skip
= options
.get('skip')
25 total
= EpisodeUserState
.view('episode_states/by_user_episode',
28 db
= get_main_database()
36 first
= EpisodeUserState
.view('episode_states/by_user_episode',
48 states
= EpisodeUserState
.view('episode_states/by_user_episode',
49 key
= [first
.user
, first
.episode
],
55 # we don't want to delete this one
58 assert len(states
) == l1
-1
61 updater
= get_updater(states
)
63 obj_funs
= [(first
, updater
)] + [(state
, do_delete
) for state
in states
]
65 bulk_save_retry(db
, obj_funs
)
67 merged
= len(states
)-1
68 actions
['merged'] += merged
71 status_str
= ', '.join('%s: %d' % x
for x
in actions
.items())
72 progress(n
+1, total
, status_str
)
75 def get_updater(states
):
83 actions
.union(set(state
.actions
))
84 settings
.update(state
.settings
)
85 merged_ids
.union(set(state
.merged_ids
+ [state
._id
]))
86 chapters
.union(set(state
.chapters
))
88 return partial(do_update
, list(actions
), settings
, list(merged_ids
), list(chapters
))
91 def do_update(actions
, settings
, merged_ids
, chapters
, state
):
92 state
.add_actions(actions
)
93 # overwrite settings in old_state with state's settings
94 state
.settings
= settings
.update(state
.settings
or {})
95 state
.merged_ids
= list(set(state
.merged_ids
+ merged_ids
))
96 state
.chapters
= list(set(state
.chapters
+ chapters
))
100 def do_delete(state
):
101 # remove all attributes
102 for attr
in filter(lambda n
: not n
.startswith('_'), dir(state
)):
105 except AttributeError:
108 state
._deleted
= True