def comic_admin_folders_do(request): folder = session.query(ComicChapter).get(request.POST['folder_id']) action = request.POST['action'] # Prevent accidents return HTTPSeeOther( location=request.route_url('comic.admin') + '#manage-folders') # TODO this should verify, somehow, that there's actually something to the left or right to move to # TODO ha ha this doesn't work if the chosen folder has children, dummy! if direction == "left": # Move the folder leftwards, so that its new "right" is one less than its current "left" diff = (folder.left - 1) - folder.right elif direction == "right": # Move the folder rightwards, so that its new "left" is one more than its current "right" diff = (folder.right + 1) - folder.left else: raise HTTPBadRequest # TODO this assumes one direction only... or does it? ( session.query(ComicChapter) .filter(ComicChapter.left.between( *sorted((folder.left, folder.left + diff)))) .update({ ComicChapter.left: ComicChapter.left - diff, ComicChapter.right: ComicChapter.right - diff, }, synchronize_session=False) ) folder.left += diff folder.right += diff return HTTPSeeOther( location=request.route_url('comic.admin') + '#manage-folders')
def comic_admin_folders_do(request): for folder_id, direction in request.POST.items(): folder = session.query(ComicChapter).get(folder_id) # TODO this should verify, somehow, that there's actually something to the left or right to move to if direction == "left": # Move the folder leftwards, so that its new "right" is one less than its current "left" diff = (folder.left - 1) - folder.right elif direction == "right": # Move the folder rightwards, so that its new "left" is one more than its current "right" diff = (folder.right + 1) - folder.left else: continue # TODO this assumes one direction only... or does it? ( session.query(ComicChapter) .filter(ComicChapter.left.between(*sorted((folder.left, folder.left + diff)))) .update( {ComicChapter.left: ComicChapter.left - diff, ComicChapter.right: ComicChapter.right - diff}, synchronize_session=False, ) ) folder.left += diff folder.right += diff session.flush() return HTTPSeeOther(location=request.route_url("comic.admin") + "#manage-folders")
def comic_admin_folders_do(request): folder = session.query(ComicChapter).get(request.POST['folder_id']) action = request.POST['action'] # Prevent accidents return HTTPSeeOther(location=request.route_url('comic.admin') + '#manage-folders') # TODO this should verify, somehow, that there's actually something to the left or right to move to # TODO ha ha this doesn't work if the chosen folder has children, dummy! if direction == "left": # Move the folder leftwards, so that its new "right" is one less than its current "left" diff = (folder.left - 1) - folder.right elif direction == "right": # Move the folder rightwards, so that its new "left" is one more than its current "right" diff = (folder.right + 1) - folder.left else: raise HTTPBadRequest # TODO this assumes one direction only... or does it? (session.query(ComicChapter).filter( ComicChapter.left.between( *sorted((folder.left, folder.left + diff)))).update( { ComicChapter.left: ComicChapter.left - diff, ComicChapter.right: ComicChapter.right - diff, }, synchronize_session=False)) folder.left += diff folder.right += diff return HTTPSeeOther(location=request.route_url('comic.admin') + '#manage-folders')
def permissions_revoke(request): # TODO error checking, eh. is there even a flash thing yet, haha data = dict( group_id=request.POST['group'], scope=request.POST['scope'], permission=request.POST['priv'], ) session.query(GroupPermission).filter_by(**data).delete() return HTTPSeeOther(location=request.route_url('__core__.admin.permissions'))
def permissions_revoke(request): # TODO error checking, eh. is there even a flash thing yet, haha data = dict( group_id=request.POST['group'], scope=request.POST['scope'], permission=request.POST['priv'], ) session.query(GroupPermission).filter_by(**data).delete() return HTTPSeeOther( location=request.route_url('__core__.admin.permissions'))
def comic_admin(request): # Figure out the starting date for the calendar. We want to show the # previous four weeks, and start at the beginning of the week. today = get_current_publication_date(XXX_HARDCODED_TIMEZONE) weekday_offset = (today.weekday() - 6) % -7 start = today + timedelta(days=weekday_offset - 7 * 4) # Grab "recent" pages -- any posted in the past two weeks OR in the future. recent_pages = ( session.query(ComicPage) .join(ComicPage.chapter) .filter(ComicPage.date_published >= start.astimezone(pytz.utc)) .order_by(ComicPage.date_published.desc()) .all() ) last_queued, queue_next_date = _get_last_queued_date() num_queued = sum(1 for page in recent_pages if page.is_queued) day_to_page = {page.date_published.date(): page for page in recent_pages} chapters = ( session.query(ComicChapter) .order_by(ComicChapter.order.asc()) .options( joinedload('children') ) .all() ) # Express calendar in dates. Go at least four weeks into the future, OR # one week beyond the last queued comic (for some padding). calendar_start = start.date() calendar_start -= timedelta(days=calendar_start.isoweekday() % 7) calendar_end = today.date() + timedelta(days=7 * 4) if day_to_page: calendar_end = max(calendar_end, max(day_to_page) + timedelta(days=7)) # TODO really really really need to move configuration out of comics. this # was clever but not clever enough. comic = session.query(Comic).order_by(Comic.id.asc()).first() return dict( comic=comic, chapters=chapters, num_queued=num_queued, last_queued=last_queued, queue_next_date=queue_next_date, day_to_page=day_to_page, calendar_start=calendar_start, calendar_end=calendar_end, )
def comic_admin_folders_new_do(request): # TODO error checking... might be no POSTs, for example folder = session.query(GalleryFolder).get(request.POST['relativeto']) if not folder: # TODO raise HTTPBadRequest where = request.POST['where'] if where == 'before': # "Before" really means taking its place, so the target folder and # every subsequent folder should scoot forwards two places left = folder.left elif where == 'after': # New folder's left should immediately follow the target folder's right left = folder.right + 1 elif where == 'child': # New folder should go where its parents' current right is -- in case # there are already children, this puts the new folder last left = folder.right else: # TODO raise HTTPBadRequest # Shift any endpoints after the new left ahead by 2. This will cover both # ancestors and unrelated folders that are further along ( session.query(GalleryFolder) .filter(GalleryFolder.left >= left) .update({ GalleryFolder.left: GalleryFolder.left + 2, }, synchronize_session=False) ) ( session.query(GalleryFolder) .filter(GalleryFolder.right >= left) .update({ GalleryFolder.right: GalleryFolder.right + 2, }, synchronize_session=False) ) # Create the new folder # TODO title has to be unique, non-blank, or somethin session.add(GalleryFolder( title=request.POST['title'], left=left, right=left + 1, # TODO temporary hack until i get rid of comics entirely comic_id=folder.comic_id, )) return HTTPSeeOther( location=request.route_url('comic.admin') + '#manage-folders')
def permissions(request): perms = session.query(GroupPermission).all() groups = session.query(Group).all() all_privileges = [] for scope, priv_names in sorted(ALL_KNOWN_PERMISSIONS_XXX.items()): for priv_name in priv_names: all_privileges.append((scope, priv_name)) return dict( permissions=perms, groups=groups, all_privileges=all_privileges, )
def comic_admin_folders_new_do(request): # TODO error checking... might be no POSTs, for example folder = session.query(GalleryFolder).get(request.POST['relativeto']) if not folder: # TODO raise HTTPBadRequest where = request.POST['where'] if where == 'before': # "Before" really means taking its place, so the target folder and # every subsequent folder should scoot forwards two places left = folder.left elif where == 'after': # New folder's left should immediately follow the target folder's right left = folder.right + 1 elif where == 'child': # New folder should go where its parents' current right is -- in case # there are already children, this puts the new folder last left = folder.right else: # TODO raise HTTPBadRequest # Shift any endpoints after the new left ahead by 2. This will cover both # ancestors and unrelated folders that are further along (session.query(GalleryFolder).filter(GalleryFolder.left >= left).update( { GalleryFolder.left: GalleryFolder.left + 2, }, synchronize_session=False)) (session.query(GalleryFolder).filter(GalleryFolder.right >= left).update( { GalleryFolder.right: GalleryFolder.right + 2, }, synchronize_session=False)) # Create the new folder # TODO title has to be unique, non-blank, or somethin session.add( GalleryFolder( title=request.POST['title'], left=left, right=left + 1, # TODO temporary hack until i get rid of comics entirely comic_id=folder.comic_id, )) return HTTPSeeOther(location=request.route_url('comic.admin') + '#manage-folders')
def comic_admin_folders_new_do(request): # TODO error checking... might be no POSTs, for example folder = session.query(GalleryFolder).get(request.POST['relativeto']) if not folder: # TODO raise HTTPBadRequest where = request.POST['where'] if where == 'before': # "Before" really means taking its place, so the target folder and # every subsequent folder should scoot forwards two places left = folder.left elif where == 'after': # New folder's left should immediately follow the target folder's right left = folder.right + 1 elif where == 'child': # Target folder needs to widen by 2, then the new folder should go just # before its right -- in case there are already children, this puts the # new folder last folder.right += 2 session.flush() left = folder.right - 2 else: # TODO raise HTTPBadRequest # Push everyone else forwards by 2 ( session.query(GalleryFolder) .filter(GalleryFolder.left >= left) .update({ GalleryFolder.left: GalleryFolder.left + 2, GalleryFolder.right: GalleryFolder.right + 2, }, synchronize_session=False) ) # Create the new folder # TODO title has to be unique, non-blank, or somethin session.add(GalleryFolder( title=request.POST['title'], left=left, right=left + 1, # TODO temporary hack until i get rid of comics entirely comic_id=folder.comic_id, )) return HTTPSeeOther( location=request.route_url('comic.admin') + '#manage-folders')
def comic_archive_by_date(request): # XXX remove this; currently used by _base.mako comic = session.query(Comic).order_by(Comic.id.asc()).first() if request.has_permission('queue', comic): queued_clause = True else: queued_clause = ~GalleryItem.is_queued items = (session.query(GalleryItem).order_by( GalleryItem.date_published).filter(queued_clause).all()) return dict( comic=comic, items=items, )
def comic_queue_do(request): # TODO this would be easier with a real validator. weekdays = [] for wd in request.POST.getall('weekday'): if wd in '0123456': weekdays.append(int(wd)) queued = ( session.query(ComicPage) .join(ComicPage.chapter) .filter(ComicPage.is_queued) .order_by(ComicPage.order.asc()) .all() ) new_dates = _generate_queue_dates(weekdays, start=get_current_publication_date(XXX_HARDCODED_TIMEZONE)) for page, new_date in zip(queued, new_dates): page.date_published = datetime.combine( new_date, time()).replace(tzinfo=pytz.utc) page.timezone = XXX_HARDCODED_TIMEZONE.zone comic.config_queue = ''.join(str(wd) for wd in sorted(weekdays)) # TODO flash message? return HTTPSeeOther(location=request.route_url('comic.admin', comic))
def comic_most_recent(request): page = ( session.query(ComicPage) .join(ComicPage.chapter) # "Most recent" never includes the queue .filter(~ ComicPage.is_queued) .order_by(ComicPage.order.desc()) .first() ) comic = page.chapter.comic include_queued = request.has_permission('queue', comic) adjacent_pages = get_adjacent_pages(page, include_queued) # TODO this is duplicated below lol from spline_wiki.models import Wiki wiki = Wiki(request.registry.settings['spline.wiki.root']) transcript = wiki['!comic-pages'][str(page.id)]['en'] ns = dict( comic=comic, page=page, transcript=transcript, adjacent_pages=adjacent_pages, ) # TODO sometime maybe the landing page will be a little more interesting # and this can go away if page: renderer = 'spline_comic:templates/page.mako' else: renderer = 'spline_comic:templates/comic-landing.mako' return render_to_response(renderer, ns, request=request)
def login__do(request): from pyramid.httpexceptions import HTTPForbidden, HTTPSeeOther # TODO don't allow re-login (replay attack where someone hits back+f5, # solved by switching to a new session on login/logout and invalidating the # old one) # TODO haha this still doesn't actually ask for a password. # TODO key errors... username = request.POST['username'] try: user = session.query(User).filter_by(name=username).one() except NoResultFound: raise HTTPForbidden(detail="you don't have an account chief") given_pw = request.POST['password'].encode('utf8') actual_pw = user.password.encode('ascii') if actual_pw == bcrypt.hashpw(given_pw, actual_pw): headers = remember(request, user) # TODO return to same url? return HTTPSeeOther(request.route_url('__core__.home'), headers=headers) else: raise HTTPForbidden
def comic_most_recent(request): page = ( session.query(ComicPage).join(ComicPage.chapter) # "Most recent" never includes the queue .filter(~ComicPage.is_queued).order_by(ComicPage.order.desc()).first()) comic = page.chapter.comic include_queued = request.has_permission('queue', comic) adjacent_pages = get_adjacent_pages(page, include_queued) # TODO this is duplicated below lol from spline_wiki.models import Wiki wiki = Wiki(request.registry.settings['spline.wiki.root']) transcript = wiki['!comic-pages'][str(page.id)]['en'] ns = dict( comic=comic, page=page, transcript=transcript, adjacent_pages=adjacent_pages, ) # TODO sometime maybe the landing page will be a little more interesting # and this can go away if page: renderer = 'spline_comic:templates/page.mako' else: renderer = 'spline_comic:templates/comic-landing.mako' return render_to_response(renderer, ns, request=request)
def offer_blocks(event): last_post = session.query(BlogPost).order_by(BlogPost.timestamp.desc()).first() block = FrontPageBlock( renderer='spline_blog:templates/_lib#front_page_block.mako', last_post=last_post, ) event.blocks.append(block)
def view(request): try: post = session.query(BlogPost).filter_by( id=request.matchdict['post_id']).one() except NoResultFound: return HTTPNotFound return dict(post=post, )
def view(request): try: post = session.query(BlogPost).filter_by(id=request.matchdict['post_id']).one() except NoResultFound: return HTTPNotFound return dict( post=post, )
def quote_view(request): quote = session.query(Quote).get(request.matchdict['id']) if not quote: return HTTPNotFound() return dict( quote=quote, )
def page_route_factory(request): page_id = int(request.matchdict['page_id']) try: page = (session.query(ComicPage).filter_by(id=page_id).options( joinedload('folder').joinedload('ancestors')).one()) except NoResultFound: raise HTTPNotFound else: canonicalize_resource_url(request, page) return page
def get_recent_pages(): # TODO needs date filter for features return ( session.query(ComicPage) .filter(~ ComicPage.is_queued) .order_by(ComicPage.order.desc()) .options( eagerload_all(ComicPage.chapter, ComicChapter.comic) ) )
def activity_from_database(self, table, render_function, timestamp_accessor=operator.attrgetter('timestamp')): """Fetch rows from the database and wrap them in `ActivitySource`s.""" # TODO optimize the heck outta this like spline.frontpage q = ( session.query(table) .order_by(timestamp_accessor(table).desc()) .limit(self.max_count) ) self.add_activity(q, render_function, timestamp_accessor)
def activity_from_database( self, table, render_function, timestamp_accessor=operator.attrgetter('timestamp')): """Fetch rows from the database and wrap them in `ActivitySource`s.""" # TODO optimize the heck outta this like spline.frontpage q = (session.query(table).order_by( timestamp_accessor(table).desc()).limit(self.max_count)) self.add_activity(q, render_function, timestamp_accessor)
def folder_route_factory(request): path_parts = request.matchdict['folder_path'].split('/') try: folder = (session.query(ComicChapter).filter_by( title_slug=path_parts[-1]).options(joinedload('ancestors')).one()) except NoResultFound: raise HTTPNotFound else: canonicalize_resource_url(request, folder) return folder
def comic_admin(request): # Figure out the starting date for the calendar. We want to show the # previous four weeks, and start at the beginning of the week. today = get_current_publication_date(XXX_HARDCODED_TIMEZONE) weekday_offset = (today.weekday() - 6) % -7 start = today + timedelta(days=weekday_offset - 7 * 4) # Grab "recent" pages -- any posted in the past two weeks OR in the future. recent_pages = (session.query(ComicPage).join(ComicPage.chapter).filter( ComicPage.date_published >= start.astimezone(pytz.utc)).order_by( ComicPage.date_published.desc()).all()) last_queued, queue_next_date = _get_last_queued_date() num_queued = sum(1 for page in recent_pages if page.is_queued) day_to_page = {page.date_published.date(): page for page in recent_pages} chapters = (session.query(ComicChapter).order_by( ComicChapter.order.asc()).options(joinedload('children')).all()) # Express calendar in dates. Go at least four weeks into the future, OR # one week beyond the last queued comic (for some padding). calendar_start = start.date() calendar_start -= timedelta(days=calendar_start.isoweekday() % 7) calendar_end = today.date() + timedelta(days=7 * 4) if day_to_page: calendar_end = max(calendar_end, max(day_to_page) + timedelta(days=7)) # TODO really really really need to move configuration out of comics. this # was clever but not clever enough. comic = session.query(Comic).order_by(Comic.id.asc()).first() return dict( comic=comic, chapters=chapters, num_queued=num_queued, last_queued=last_queued, queue_next_date=queue_next_date, day_to_page=day_to_page, calendar_start=calendar_start, calendar_end=calendar_end, )
def build_menu(event): # TODO can these be... cached? but then how would it be busted. # TODO order? # TODO this is pretty piss-poor now that "comic" has been kind of # overloaded to mean not really that for comic in session.query(Comic): event.add_item( "{} comic".format(comic.title), 'comic.most-recent', comic, )
def find_activity(event): # TODO proooobably need some kinda helpful shared date and count limit here # TODO start porting to logic? pastes = session.query(Paste).order_by(Paste.timestamp.desc()).limit(8).all() # TODO is this a good idea if pastes: event.blocks.append(FrontPageBlock( renderer='spline_pastebin:templates/_lib#front_page_block.mako', pastes=pastes, ))
def comic_archive_by_date(request): # XXX remove this; currently used by _base.mako comic = session.query(Comic).order_by(Comic.id.asc()).first() if request.has_permission('queue', comic): queued_clause = True else: queued_clause = ~GalleryItem.is_queued items = ( session.query(GalleryItem) .order_by(GalleryItem.date_published) .filter(queued_clause) .all() ) return dict( comic=comic, items=items, )
def folder_route_factory(request): path_parts = request.matchdict['folder_path'].split('/') try: folder = ( session.query(ComicChapter) .filter_by(title_slug=path_parts[-1]) .options(joinedload('ancestors')) .one() ) except NoResultFound: raise HTTPNotFound else: canonicalize_resource_url(request, folder) return folder
def express_love__do(request): # TODO real form handling thx source = request.user # TODO error handling lol target = session.query(User).filter_by(name=request.POST['target']).one() session.add(Love( source=source, target=target, comment=request.POST['comment'], )) return HTTPSeeOther(request.route_url('love.list'))
def get_adjacent_pages(page, include_queued): if not page: return None, None q = session.query(ComicPage).join(ComicPage.chapter) if not include_queued: q = q.filter(~ ComicPage.is_queued) prev_by_date = ( q .filter(ComicPage.date_published < page.date_published) .order_by(ComicPage.date_published.desc()) .first() ) next_by_date = ( q .filter(ComicPage.date_published > page.date_published) .order_by(ComicPage.date_published.asc()) .first() ) # So, "by story" is a little more complicated. What it really means is: # 1. If there's a prev/next page in this folder, use that. # 2. Otherwise, if there's a prev/next folder, use the # last/first page of it. # Folders are sorted by their /right/ edge so that a page in a folder comes # after every page in any subfolders, just like the archive view shows. prev_by_story = ( q .filter(ComicChapter.comic_id == page.chapter.comic_id) .filter(or_( ComicChapter.right < page.chapter.right, and_(ComicChapter.id == page.chapter.id, ComicPage.order < page.order), )) .order_by(ComicChapter.right.desc(), ComicPage.order.desc()) .first() ) next_by_story = ( q .filter(ComicChapter.comic_id == page.chapter.comic_id) .filter(or_( ComicChapter.right > page.chapter.right, and_(ComicChapter.id == page.chapter.id, ComicPage.order > page.order), )) .order_by(ComicChapter.right.asc(), ComicPage.order.asc()) .first() ) return PreviousNextPager( prev_by_date, next_by_date, prev_by_story, next_by_story)
def page_route_factory(request): page_id = int(request.matchdict['page_id']) try: page = ( session.query(ComicPage) .filter_by(id=page_id) .options(joinedload('folder').joinedload('ancestors')) .one() ) except NoResultFound: raise HTTPNotFound else: canonicalize_resource_url(request, page) return page
def permissions_grant(request): # TODO error checking, eh. is there even a flash thing yet, haha data = dict( group_id=request.POST['group'], scope=request.POST['scope'], permission=request.POST['priv'], ) existing = session.query(GroupPermission).filter_by(**data).all() if not existing: session.add(GroupPermission(**data)) return HTTPSeeOther(location=request.route_url('__core__.admin.permissions'))
def get_adjacent_pages(page, include_queued): if not page: return None, None q = session.query(ComicPage).join(ComicPage.chapter) if not include_queued: q = q.filter(~ ComicPage.is_queued) # TODO humble suggestion: perhaps ordering by date should order by, you know... date? prev_by_date = ( q .filter(ComicPage.order < page.order) .order_by(ComicPage.order.desc()) .first() ) next_by_date = ( q .filter(ComicPage.order > page.order) .order_by(ComicPage.order.asc()) .first() ) # So, "by story" is a little more complicated. What it really means is: # 1. If there's a prev/next page in this folder, use that. # 2. Otherwise, if there's a prev/next folder, use the # last/first page of it. prev_by_story = ( q .filter(ComicChapter.comic_id == page.chapter.comic_id) .filter(or_( ComicChapter.order < page.chapter.order, and_(ComicChapter.id == page.chapter.id, ComicPage.order < page.order), )) .order_by(ComicChapter.order.desc(), ComicPage.order.desc()) .first() ) next_by_story = ( q .filter(ComicChapter.comic_id == page.chapter.comic_id) .filter(or_( ComicChapter.right > page.chapter.right, and_(ComicChapter.id == page.chapter.id, ComicPage.order > page.order), )) .order_by(ComicChapter.order.asc(), ComicPage.order.asc()) .first() ) return PreviousNextPager( prev_by_date, next_by_date, prev_by_story, next_by_story)
def express_love__do(request): # TODO real form handling thx source = request.user # TODO error handling lol target = session.query(User).filter_by(name=request.POST['target']).one() session.add( Love( source=source, target=target, comment=request.POST['comment'], )) return HTTPSeeOther(request.route_url('love.list'))
def permissions_grant(request): # TODO error checking, eh. is there even a flash thing yet, haha data = dict( group_id=request.POST['group'], scope=request.POST['scope'], permission=request.POST['priv'], ) existing = session.query(GroupPermission).filter_by(**data).all() if not existing: session.add(GroupPermission(**data)) return HTTPSeeOther( location=request.route_url('__core__.admin.permissions'))
def view(request): paste = session.query(Paste) \ .filter(Paste.id == request.matchdict['id']) \ .one() if paste.syntax != '': lexer = pygments.lexers.get_lexer_by_name(paste.syntax) else: lexer = pygments.lexers.TextLexer() pretty_content = pygments.highlight(paste.content, lexer, pygments.formatters.HtmlFormatter()) return dict( paste=paste, pretty_content=pretty_content, )
def wiki_history(page, request): if not page.exists: # TODO not sure what should be done here really raise HTTPNotFound history = page.get_history() if history.all_emails: q = (session.query(User.email, User).filter(User.email.in_(history.all_emails))) history.native_email_map = dict(q) return dict( page=page, history=history, )
def wiki_history(page, request): if not page.exists: # TODO not sure what should be done here really raise HTTPNotFound history = page.get_history() if history.all_emails: q = (session.query(User.email, User) .filter(User.email.in_(history.all_emails)) ) history.native_email_map = dict(q) return dict( page=page, history=history, )
def _get_last_queued_date(): queued_q = session.query(ComicPage).join(ComicPage.chapter).filter(ComicPage.is_queued) last_queued = queued_q.order_by(ComicPage.date_published.desc()).first() if last_queued: queue_end_date = last_queued.date_published else: queue_end_date = datetime.combine( get_current_publication_date(XXX_HARDCODED_TIMEZONE).astimezone(pytz.utc), time() ) if queue_end_date == END_OF_TIME: queue_next_date = None else: weekdays = [int(wd) for wd in XXX_HARDCODED_QUEUE] queue_next_date = next(_generate_queue_dates(weekdays, start=queue_end_date)) return last_queued, queue_next_date
def create_user(parser, args): engine = engine_from_config(vars(args), 'sqlalchemy.') session.configure(bind=engine) with transaction.manager: all_groups = { group.name: group for group in session.query(Group) } username = input('username: '******'email: ').strip() password = getpass.getpass('password: '******'confirm password: '******'t match!") sys.exit(1) group_names = [] if all_groups: print() print("available groups: {}".format(', '.join(all_groups))) group_names = input('comma-separated list of groups to add to: ').strip().split(',') with transaction.manager: pwhash = bcrypt.hashpw( password.encode('utf8'), bcrypt.gensalt(14), ).decode('ascii') # TODO would be neat to have a password field that hashes on assignment # and does the right thing with equality check user = User(name=username, email=email, password=pwhash, groups=[]) for group_name in group_names: user.groups.append(all_groups[group_name]) session.add(user) session.flush() userid = user.id print() print("created user {} with id {}".format(username, userid))
def comic_queue_do(request): # TODO this would be easier with a real validator. weekdays = [] for wd in request.POST.getall('weekday'): if wd in '0123456': weekdays.append(int(wd)) queued = (session.query(ComicPage).join(ComicPage.chapter).filter( ComicPage.is_queued).order_by(ComicPage.order.asc()).all()) new_dates = _generate_queue_dates( weekdays, start=get_current_publication_date(XXX_HARDCODED_TIMEZONE)) for page, new_date in zip(queued, new_dates): page.date_published = datetime.combine(new_date, time()).replace(tzinfo=pytz.utc) page.timezone = XXX_HARDCODED_TIMEZONE.zone comic.config_queue = ''.join(str(wd) for wd in sorted(weekdays)) # TODO flash message? return HTTPSeeOther(location=request.route_url('comic.admin', comic))
def root_factory(self, request): """Given a request with a matched URL, produce the object referred to by that URL. Raise a 404 if no such object exists. """ table = self.column.class_ query = session.query(table) relchain = () current = self while current: for rel in relchain: query = query.join(rel) if current.marker in request.matchdict: ident = request.matchdict[current.marker] if current.slug_column: # Split the "real" identifier from the slug ident, _, _ = ident.partition(u'-') # TODO redirect if any slug doesn't match the db # TODO come to think of it... contains_eager? query = query.filter(current.column == ident) elif current is self: # Missing the identifier for the most specific model, which... # don't make sense raise HTTPNotFound() relchain = current.relchain current = current.parent try: row = query.one() except NoResultFound: # Note that MultipleResultsFound isn't caught, because that should # not be *possible* and indicates a programming error raise HTTPNotFound() return row
def _get_last_queued_date(): queued_q = (session.query(ComicPage).join(ComicPage.chapter).filter( ComicPage.is_queued)) last_queued = queued_q.order_by(ComicPage.date_published.desc()).first() if last_queued: queue_end_date = last_queued.date_published else: queue_end_date = datetime.combine( get_current_publication_date(XXX_HARDCODED_TIMEZONE).astimezone( pytz.utc), time(), ) if queue_end_date == END_OF_TIME: queue_next_date = None else: weekdays = [int(wd) for wd in XXX_HARDCODED_QUEUE] queue_next_date = next( _generate_queue_dates(weekdays, start=queue_end_date)) return last_queued, queue_next_date
def list_love(request): loves = session.query(Love).order_by(Love.timestamp.desc()) return dict( loves=loves, )
def comic_upload_do(request): # TODO validation and all that boring stuff file_upload = request.POST['file'] fh = file_upload.file from spline.feature.filestore import IStorage storage = request.registry.queryUtility(IStorage) _, ext = os.path.splitext(file_upload.filename) filename = storage.store(fh, ext) # TODO ha ha this is stupid # TODO very skinny images shouldn't be blindly made 200x200 fh.seek(0) thumb = subprocess.check_output( ['convert', '-', '-resize', '200x200', '-'], stdin=fh) # TODO this interface is bad also thumbname = storage.store(BytesIO(thumb), ext) # TODO wire into transaction so the file gets deleted on rollback last_chapter = (session.query(ComicChapter).filter( ComicChapter.id == int(request.POST['chapter'])).one()) when = request.POST['when'] if when == 'now': date_published = datetime.now(pytz.utc) elif when == 'queue': last_queued, queue_next_date = _get_last_queued_date() date_published = datetime.combine( queue_next_date, time(tzinfo=XXX_HARDCODED_TIMEZONE), ) date_published = date_published.astimezone(pytz.utc) # Fetch next page number and ordering. Also need to shift everyone else # forwards by one if this is bumping the queue. Blurgh. max_order, = (session.query(func.max(ComicPage.order)).filter( ComicPage.date_published <= date_published).first()) if max_order is None: max_order = 0 next_order = max_order + 1 (session.query(ComicPage).filter(ComicPage.order >= next_order).update( {ComicPage.order: ComicPage.order + 1})) max_page_number, = (session.query(func.max( ComicPage.page_number)).with_parent(last_chapter).filter( ComicPage.date_published <= date_published).first()) if max_page_number is None: max_page_number = 0 next_page_number = max_page_number + 1 (session.query(ComicPage).with_parent(last_chapter).filter( ComicPage.page_number >= next_page_number).update( {ComicPage.page_number: ComicPage.page_number + 1})) page = ComicPage( chapter=last_chapter, author=request.user, date_published=date_published, timezone=XXX_HARDCODED_TIMEZONE.zone, order=next_order, page_number=next_page_number, # TODO more validation here too title=request.POST['title'], comment=request.POST['comment'], media=[ GalleryMedia_Image( image_file=os.path.basename(filename), thumbnail_file=os.path.basename(thumbname), ) ], ) if request.POST.get('iframe_url'): url = request.POST['iframe_url'] # If it's a YouTube URL, convert to the embed URL automatically # TODO this seems like a neat thing to do for many other services and # make a tiny library out of, if it's not done already? # TODO why doesn't this use urlparse??? m = re.match( '^(?:https?://)?(?:www[.])?youtube[.]com/watch[?]v=([-_0-9a-zA-Z]+)(?:&|$)', url) if m: url = "https://www.youtube.com/embed/{}?rel=0".format(m.group(1)) m = re.match('^(?:https?://)?youtu[.]be/([-_0-9a-zA-Z]+)(?:[?]|$)', url) if m: url = "https://www.youtube.com/embed/{}?rel=0".format(m.group(1)) try: width = int(request.POST['iframe_width']) except (KeyError, ValueError): width = 800 try: height = int(request.POST['iframe_height']) except (KeyError, ValueError): height = 600 page.media.append( GalleryMedia_IFrame(url=url, width=width, height=height)) session.add(page) session.flush() return HTTPSeeOther(location=request.resource_url(page))
def authenticate_userid(userid, request): if userid is None: return None # TODO should this forget who you are if you don't exist? return session.query(User).get(userid)
def quote_list(request): quotes = session.query(Quote).order_by(Quote.timestamp.desc()) return dict( quotes=quotes, )
def authenticated_userid(self, request): userid = self.unauthenticated_userid(request) if userid: return session.query(User).get(userid) else: return None
def init_db(parser, args): settings = vars(args) # Logging # TODO this should probably go in the main entry point coloredlogs.install(level=logging.INFO) # TODO what is this for, it was debug-only, is there any reason we wouldn't want it #logging.basicConfig() #logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO) # Plugin loading plugin_list = import_plugins(settings.get('spline.plugins', ())) engine = engine_from_config(settings, 'sqlalchemy.') session.configure(bind=engine) Base.metadata.create_all(engine, checkfirst=True) comic_title = settings.get('spline.comic_name') chapter_title = settings.get('spline.chapter_name') with transaction.manager: try: g = session.query(Group).filter_by(id=1).one() except: g = Group(id=1, name='admin') session.add(g) try: gp0 = session.query(GroupPermission).filter_by(id=1).one() except: gp0 = GroupPermission(id=1, scope='core', permission='admin') gp0.group = g session.add(gp0) # Only needed if the comic plugin is loaded if 'spline_comic' in plugin_list: from spline_comic.models import Comic, ComicChapter try: gp1 = session.query(GroupPermission).filter_by(id=1).one() except: gp1 = GroupPermission(id=1, scope='comic', permission='admin') gp1.group = g session.add(gp1) try: comic = session.query(Comic).filter_by(id=1).one() except: comic = Comic(id=1, title=comic_title, config_timezone='GMT') session.add(comic) try: chap = session.query(ComicChapter).filter_by(id=1).one() except: chap = ComicChapter(id=1, title=chapter_title, left=0, right=0) chap.comic = comic session.add(chap) # Only needed if the wiki is loaded if 'spline_wiki' in plugin_list: try: gp2 = session.query(GroupPermission).filter_by(id=2).one() except: gp2 = GroupPermission(id=2, scope='wiki', permission='edit') gp2.group = g session.add(gp2)
def list_love(request): loves = session.query(Love).order_by(Love.timestamp.desc()) return dict(loves=loves, )