def renderMenu(self, main_nav, sub_nav=''):
        children = []
        main_menu = []
        sub_menu = []

        menu_items = self.main_nav

        for item in menu_items:
            css_class = ''
             
            if main_nav == item['name']: 
                # We found the menu item that is currently active - set the correct
                # CSS class so that it is rendered properly, plus grab any children that we 
                # need to handle
                css_class = 'active'
                children = item['children']

            # Skip this item if they don't have permission to access
            if item.has_key('perm') and not identity.has_permission(item['perm']): continue

            children = []
            for child in item['children']:
                if child.has_key('perm') and not identity.has_permission(child['perm']): continue
                children.append(child)

            main_menu.append({'name': item['label'], 
                              'link': item['link'], 
                              'link_class': item.get('link_class', ''),
                              'css_class': css_class,
                              'children': children})

        return (main_menu, sub_menu)
Esempio n. 2
0
    def dashboard(self):
        q_score = None
        current = None
        age = None
        feed_entries = None
        usage = dict()
        now = datetime.now()
        curso = self.get_curso_actual()
        instancias = list()
        correcciones = list()
        respuestas_pendientes = list()
        if curso and identity.has_permission(Permiso.entregar_tp):
            for ej in curso.ejercicios:
                for inst in ej.instancias_a_entregar:
                    instancias.append(inst)
            alumno = identity.current.user
            alumno_inscripto = alumno.get_inscripcion(curso)
            correcciones = alumno.get_correcciones(curso)
            correcciones.sort(lambda x,y: cmp(x.instancia, y.instancia))
        if identity.has_permission(Permiso.examen.respuesta.revisar):
            respuestas_pendientes = Respuesta.get_pendientes_de_revision()

        feed_url = config.get('sercom.welcome.rssfeed.url')
        if identity.has_permission(Permiso.admin):
            # A los admins les muestro info del server
            q_score = Entrega.selectBy(inicio=None).count()
            current = None
            try:
                current = Entrega.select(AND(Entrega.q.inicio!=None, Entrega.q.fin==None)).orderBy(Entrega.q.fecha).reversed()[0]
                age = current.fecha
            except:
                pass
            usage = sercom.serverinfo.getinfo()
        elif feed_url:
            # Al resto el feed de noticias, hasta cuatro
            count = 0
            
            feed = feedparser.parse(feed_url)
            if feed is not None:
                feed_entries = list()
                for e in feed.entries:
                    if e.category == 'Noticias' and count < 4:
                        # No logré que el parser deje de escapear el HTML y lo necesito
                        e.html_content = e.summary.replace('&gt;', '>')
                        e.html_content = e.html_content.replace('&lt;', '<')
                        e.presented_date = time.strftime('%d/%m/%Y %H:%M', e.updated_parsed)
                        feed_entries.append(e)
                        count = count + 1

        return dict(curso=curso, now=now, instancias_activas = instancias, correcciones = correcciones, 
                    respuestas_pendientes = respuestas_pendientes, q_score = q_score, usage=usage, age=age, q_current=current,
                    feed_entries = feed_entries) 
Esempio n. 3
0
    def statistics(self, **kw):
        """Crea el formulario de estadisticas sobre entregas"""
        curso = self.get_curso_actual()
        cant_por_instancia = []
        cant_por_dias_anticip = {}
        for e in curso.ejercicios:
            for i in e.instancias:
              cant_por_instancia += [(i.shortrepr(), len(i.entregas))]

              for entrega in i.entregas:
                 anticip = (i.fin - entrega.fecha)
                 dias_anticipacion = anticip.days
                 if dias_anticipacion in cant_por_dias_anticip:
                     cant_por_dias_anticip[dias_anticipacion] += 1
                 else:
                     cant_por_dias_anticip[dias_anticipacion] = 1
        items = cant_por_dias_anticip.items()
        items.sort()
        items.reverse()
        # Entregas colgadas, sólo admins
        q_data = None
        if identity.has_permission(Permiso.admin):
            q_data = Entrega.selectBy(inicio=None, fin=None).orderBy('fecha')
            for e in q_data:
                e.edad = (datetime.now() - e.fecha)
                e.suficientemente_viejo = e.edad > timedelta(minutes=5)
        return dict(cant_por_instancia=cant_por_instancia, 
                    q_data = q_data,
                    cant_por_dias_anticip = [('%s dias' % dias, cant) for dias, cant in items])
Esempio n. 4
0
 def get_curso_actual(self):
     try:
         contexto = SessionHelper().get_contexto_usuario()
         return contexto.get_curso()
     except SinCursosDisponibles as e:
         if identity.has_permission(Permiso.admin):
             raise redirect(url('/curso/new'))
         else:
             raise redirect(url('/error/%s' % e))
Esempio n. 5
0
def filter_members(location, text_filter, type, active_only, start, end, override_user=None):

    if type == "member_search":

        text_filter = "%" + " ".join(text_filter.split()).replace("'","\\'") + "%"

        if override_user:
            user_locs = Location.select()
        else:
            user_locs = user_locations(identity.current.user, ['member', 'host'])

        if user_locs:
            if location:
                relevant_groups = location.groups
                relevant_user_ids = tuple((ug.userID for ug in UserGroup.select(IN(UserGroup.q.group, tuple(relevant_groups)))))
                display_name_clause = iLIKE(User.q.display_name, text_filter)
                user_id_clause = IN(User.q.id, relevant_user_ids) # so that we select all members even those with homehub as this hub
                if active_only:
                    user_active_clause = (User.q.active == 1)
                    users = User.select(AND(display_name_clause, user_id_clause, user_active_clause))
                else:
                    users = User.select(AND(display_name_clause, user_id_clause))

            else:
                display_name_clause = iLIKE(User.q.display_name, text_filter)
                if active_only:
                    user_active_clause = (User.q.active == 1)
                    users = User.select(AND(display_name_clause, user_active_clause))
                else:
                    users = User.select(display_name_clause)

            users = users.orderBy('display_name')
        else:
            users = []

    elif type == 'rfid_member_search':
        users = User.select(AND(User.q.rfid == text_filter))

    elif type == 'fulltext_member_search':
        users = hubspace.search.do_search(text_filter)
        if location:
            user_ids = tuple(user.id for user in users)
            if not user_ids:
                users = []
            else:
                users = User.select(AND(IN(User.q.id, user_ids), User.q.homeplaceID==location.id))

    if start != None and end != None:
        users = users[start:end]

    try:
        webapi = User.selectBy(first_name="web", last_name="api")[0]
        if webapi in users and not identity.has_permission("superuser"):
            users.remove(webapi)
    except:
        pass
    return users
Esempio n. 6
0
def locations(permission="manage_resources"):
    """get all the locations in which the current user has a specific permission
    """
    if identity.has_permission('superuser'):
        locations = list(Location.select())
    else:
        locations = []
        for group in identity.current.user.groups:
            location = get_place(group)
            if location:
                if permission_or_owner(location, location, permission) and location not in locations:
                    locations.append(location)
    locations.sort(loc_alpha)
    return locations
Esempio n. 7
0
class IdentityRoot(RootController):

    [expose()]

    def index(self):
        pass

    [expose()]

    def identity_failed(self, **kw):
        cherrypy.response.status = 401
        return 'identity_failed_answer'

    [expose()]
    [identity.require(not_anonymous())]

    def logged_in_only(self):
        return 'logged_in_only'

    [expose()]
    [identity.require(in_group('peon'))]

    def in_peon_group(self):
        return 'in_peon_group'

    [expose()]

    def test_exposed_require(self):
        if not hasattr(self.in_peon_group, '_require'):
            return 'no _require attr'
        if not isinstance(self.in_peon_group._require, in_group):
            return 'not correct class'
        if 'peon' != self.in_peon_group._require.group_name:
            return 'not correct group name'
        return '_require is exposed'

    [expose()]
    [identity.require(in_group('admin'))]

    def in_admin_group(self):
        return 'in_admin_group'

    [expose()]
    [identity.require(has_permission('chops_wood'))]

    def has_chopper_permission(self):
        return 'has_chopper_permission'

    [expose()]
    [identity.require(has_permission('bosses_people'))]

    def has_boss_permission(self):
        return "has_boss_permission"

    [expose()]

    def logout(self):
        identity.current.logout()
        return "logged out"

    [expose()]
    [identity.require(not_anonymous())]

    def user_email(self):
        return identity.current.user.email_address

    peon_area = RestrictedArea()

    [expose()]

    def new_user_setup(self, user_name, password):
        return '%s %s' % (user_name, password)

    _test_encoded_params = ('b=krümel&d.a=klöße1')

    [expose()]
    [identity.require(not_anonymous())]

    def test_params(self, **kwargs):
        params = self._test_encoded_params
        # formencode's variable_decode create a datastructure
        #  but does not "decode" anything
        to_datastruct = formencode.variabledecode.variable_decode
        expected_params = to_datastruct(
            dict([p.split('=') for p in params.split('&')]))
        params_ok = True
        if not expected_params['b'].decode(
                'utf8') == cherrypy.request.params['b']:
            params_ok = False
        if not expected_params['d']['a'].decode(
                'utf8') == cherrypy.request.params['d']['a']:
            params_ok = False
        if params_ok:
            return 'params ok'
        else:
            return 'wrong params: %s\nexpected unicode objects' \
                ' for all strings' % cherrypy.request.params
Esempio n. 8
0
	def UserMenu(self, **kw):
		'''     Return a list of menu items available to the current user
		'''
		#log.debug('UserMenu')
		results = []
		#Display top menu based on permissions of user. 
		results.append(dict(link='/',name='Main Menu',sub_menu=[]))
		if identity.has_permission("reg_view"):    
			results.append(dict(link='/registration',name='Registration',sub_menu=[]))
		if identity.has_permission("bill_view"):
			results.append(dict(link='/billing',name='Billing',sub_menu=[]))
		Locations = model.InvLocation.select()
		LocationStoreGroups = {}
		LocationDispGroups = {}
		for location in Locations:
			name_store = '%s_store' % location.Name.lower().replace(' ','_')
			name_disp = '%s_disp' % location.Name.lower().replace(' ','_')
			# Create the store link
			if getattr(self,name_store,None) != None and identity.has_permission('%s_view' % name_store):
					for group in location.Groups:
							if LocationStoreGroups.has_key(group.Name):
									LocationStoreGroups[group.Name].append(dict(link='/%s' % name_store, name='%s Inventory' % location.Name,sub_menu=[]))
							else:
									LocationStoreGroups[group.Name] = [dict(link='/%s' % name_store, name='%s Inventory' % location.Name,sub_menu=[])]
					if len(location.Groups) == 0:
							if LocationStoreGroups.has_key('Other'):
									LocationStoreGroups['Other'].append(dict(link='/%s' % name_store, name='%s Inventory' % location.Name,sub_menu=[]))
							else:
									LocationStoreGroups['Other'] = [dict(link='/%s' % name_store, name='%s Inventory' % location.Name,sub_menu=[])]
			# Create the dispensing location
			if location.CanSell:
					if getattr(self,name_disp,None) != None and identity.has_permission('%s_view' % name_disp):
							for group in location.Groups:
									if LocationDispGroups.has_key(group.Name):
											LocationDispGroups[group.Name].append(dict(link='/%s' % name_disp, name='%s Dispensing' % location.Name,sub_menu=[]))
									else:
											LocationDispGroups[group.Name] = [dict(link='/%s' % name_disp, name='%s Dispensing' % location.Name,sub_menu=[])]
							if len(location.Groups) == 0:
									if LocationDispGroups.has_key('Other'):
											LocationDispGroups['Other'].append(dict(link='/%s' % name_disp, name='%s Dispensing' % location.Name,sub_menu=[]))
									else:
											LocationDispGroups['Other'] = [dict(link='/%s' % name_disp, name='%s Dispensing' % location.Name,sub_menu=[])]
		if len(LocationStoreGroups) > 0:
				SubMenu = []
				keys = LocationStoreGroups.keys()
				keys.sort()
				for key in keys:
						SubMenu.append(dict(link='',name=key, sub_menu=LocationStoreGroups[key]))
				results.append(dict(link='', name='Inventory', sub_menu=SubMenu))
		if len(LocationDispGroups) > 0:
				SubMenu = []
				keys = LocationDispGroups.keys()
				keys.sort()
				for key in keys:
						SubMenu.append(dict(link='',name=key, sub_menu=LocationDispGroups[key]))
				results.append(dict(link='', name='Dispensing', sub_menu=SubMenu))
		if identity.has_permission("admin_controllers_inventory"):
			results.append(dict(link='/inventory',name='Admin Inventory',sub_menu=[]))
		if identity.has_permission("admin_users"):
			results.append(dict(link='/user_manager',name='User admin',sub_menu=[]))
		if identity.has_permission("admin_controllers_configuration"):
			results.append(dict(link='/configuration',name='Configuration Admin',sub_menu=[]))
		if identity.not_anonymous():
				results.append(dict(link='/user_reports',name='User Reports',sub_menu=[]))
		return results
Esempio n. 9
0
class Root(controllers.RootController):

  @expose(template="dejagears.templates.page")
  def index(self, pagename="FrontPage" ):
    box = hub.getConnection()
    player_fields = {
      Player : [
        ('Name', 'name'),
        ('Birth Date', 'birthdate'),
        #('Team', 'team'),
        ('Points', 'points'),
      ],
      Team : [
        ('City', 'city'),
        ('NickName', 'nickname'),
      ],
    }
    team_fields = [
      ('City', 'city'),
      ('NickName', 'nickname'),
    ]
    page = box.Page(pagename=pagename)
    if page == None:
      raise turbogears.redirect("notfound", pagename = pagename)
    content = publish_parts(page.data, writer_name="html")['html_body']
    root = str(turbogears.url('/'))
    content = wikiwords.sub(r'<a href="%s\1">\1</a>' % root, content)
    return dict(
      data=content,
      page=page,
      players=box.recall(Team + Player),
      teams=box.recall(Team),
      players_widget=DataGrid(fields=player_fields),
      teams_widget=DataGrid(fields=team_fields),
    )
  
  @expose(template="dejagears.templates.edit")
  def edit(self,pagename):
    box = hub.getConnection()
    page = box.Page(pagename=pagename)
    return dict(page=page)

  @expose()
  @identity.require(identity.Any(identity.in_group("admin"),identity.has_permission("ls")))
  def save(self, pagename, data, submit):
    box = hub.getConnection() #.begin( isolation = turbogears.database.SERIALIZABLE )
    self.increment_counter()
    page = box.Page(pagename=pagename)
    if page == None:
      page = Page(pagename=pagename,data=data)
      box.memorize(page)
    page.data = data
    turbogears.flash("Changes saved!")
    raise turbogears.redirect("/", pagename=pagename)
    
  @expose()
  def default_values(self):
    "Set some default values in the database"
    
    # Add some information
    box = hub.getConnection()
    t1 = Team(city='Pittsburgh', nickname='Ferrous Metals')
    box.memorize(t1)
    t2 = Team(city='Seattle', nickname='Seagulls')
    box.memorize(t2)
    p1 = Player(name='Bob Waffleburger', birthdate=datetime.date(1982,3,2), points=21)
    box.memorize(p1)
    p2 = Player(name='Mike Handleback', birthdate=datetime.date(1975,9,25), points=10)
    box.memorize(p2)
    p1.team = t1.ID
    p2.team = t2.ID
    
    # Add a default Page
    page = Page( pagename="FrontPage", data="This is the main page, please edit it." )
    box.memorize( page )
    
    # Setup identity data 
    jrodrigo = TG_User( user_name = "jrodrigo" )
    box.memorize( jrodrigo )
    jrodrigo.password = "******"
    
    root = TG_User( user_name = "root" )
    box.memorize( root )
    root.password = "******"
    
    user = TG_Group( group_name = "user" )
    box.memorize( user )
    
    admin = TG_Group( group_name = "admin" )
    box.memorize( admin )
    
    format = TG_Permission( permission_name = "format" )
    box.memorize( format )
    ls = TG_Permission( permission_name = "ls" )
    box.memorize( ls )
    cat = TG_Permission( permission_name = "cat" )
    box.memorize( cat )
    
    o = TG_UserGroup( user_id = root.user_id, group_id = user.group_id )
    box.memorize( o )
    o = TG_UserGroup( user_id = root.user_id, group_id = admin.group_id )
    box.memorize( o )
    o = TG_UserGroup( user_id = jrodrigo.user_id, group_id = user.group_id )
    box.memorize( o )
    
    o = TG_GroupPermission( group_id = admin.group_id, permission_id = format.permission_id )
    box.memorize( o )
    o = TG_GroupPermission( group_id = user.group_id, permission_id = ls.permission_id )
    box.memorize( o )
    o = TG_GroupPermission( group_id = user.group_id, permission_id = cat.permission_id )
    box.memorize( o )
    
    return "done"

  @expose()
  def default(self, pagename):
    return self.index(pagename)

  @expose("dejagears.templates.edit")
  def notfound(self, pagename):
    page = Page(pagename=pagename, data="")
    return dict(page=page)

  @expose("dejagears.templates.pagelist")
  @expose("json")
  def pagelist(self):
    box = hub.getConnection()
    self.increment_counter()
    pages = box.recall(Page)
    pages.sort(dejavu.sort('pagename'))
    pages = [page.pagename for page in pages]
    return dict(pages=pages)

  def increment_counter(self):
    # We call acquire_lock at the beginning
    #   of the method
    cherrypy.session.acquire_lock()
    c = cherrypy.session.get('counter', 0) + 1
    cherrypy.session['counter'] = c
    return str(c)
  increment_counter.exposed = True

  def read_counter(self):
    # No need to call acquire_lock
    #   because we're only reading
    #   the session data
    c = cherrypy.session.get('counter', 0) + 1
    return str(c)
  read_counter.exposed = True
    
  @expose()
  def logout(self):
    identity.current.logout()
    raise redirect("/")
  
  @expose("json")
  def lookup( self ):
    user = identity.current.user
    print user.userId
    print user.emailAddress
    print user.displayName
    group = user.groups.pop()
    print group.groupId
    print group.displayName
    permission = user.permissions.pop()
    print permission.permissionId
    
    print permission.groups

    print group.permissions
    print group.users
    
    print user.groups
    print user.permissions
    
    return [
      jsonify.encode( identity.current.user ),
      jsonify.encode( identity.current.user.groups.pop() ),
      jsonify.encode( identity.current.user.permissions.pop() ),
    ]

  @expose("dejagears.templates.login")
  def login(self, forward_url=None, previous_url=None, *args, **kw):
  
    if not identity.current.anonymous \
        and identity.was_login_attempted() \
        and not identity.get_identity_errors():
      raise redirect(forward_url)

    forward_url=None
    previous_url= request.path
  
    if identity.was_login_attempted():
      msg=_("The credentials you supplied were not correct or "
             "did not grant access to this resource.")
    elif identity.get_identity_errors():
      msg=_("You must provide your credentials before accessing "
             "this resource.")
    else:
      msg=_("Please log in.")
      forward_url= request.headers.get("Referer", "/")
      
    response.status=403
    return dict(message=msg, previous_url=previous_url, logging_in=True,
                original_parameters=request.params,
                forward_url=forward_url)

  @expose()
  @identity.require(identity.has_permission("format"))
  def format_only(self):
      return "format_only"
  
  @expose()
  @identity.require(identity.in_group("admin"))
  def root_only(self):
      return "root_only"
  
  @expose()
  @identity.require(identity.Any(identity.has_permission("ls"),identity.has_permission("format")))
  def both(self):
      return "both"
  
  @expose()
  @identity.require(identity.All(identity.has_permission("format"),identity.in_group("user")))
  def all(self):
      return "all"
 def test_has_permission(self):
     """Test predicate for checking particular permissions."""
     assert self.met(has_permission('read'))
     assert not self.met(has_permission('delete'))
    def renderMenu(self, main_nav, sub_nav=''):
        children = []
        main_menu = []
        sub_menu = []

        user = identity.current.user
        customer = identity.current.user.customer
        brand = customer.brand

        # See if we have a cached copy available to use
        last_config_change = masterdb.Customer._connection.queryOne("select last_config_change from Customer where id=%s" % customer.id)[0]
        if not last_config_change: 
            last_config_change = datetime.now()
            customer.last_config_change = last_config_change
        if 'menu-user' in session and 'menu-content' in session and session['menu-user'] == user and \
              session.get('menu-timestamp', datetime(2014,1,1)) > last_config_change:
            return (session['menu-content'], [])

        # If we get a customer that hasn't picked a package, set it to the Brand's highlight_package
        if customer.brand and not customer.package:
            customer.package = customer.brand.highlight_package


        menu_items = self.main_nav
        extra_items = []
        excluded_items = []

        #if customer.package.isFreeTrial():
	    #excluded_items.append('menu.billing')
        # Exclude some items that aren't included in some brands

        if brand:
            if not brand.show_billing and not user.isSuperuser(): excluded_items.append('menu.billing')
            if not brand.show_support and not user.isSuperuser(): excluded_items.append('menu.support')
            if not brand.show_public_reports: excluded_items.append('menu.reports.public')
            if not brand.show_email_templates: excluded_items.append('menu.settings.email_templates')
            if not customer.hasSnmpPolling(): excluded_items.append('menu.settings.snmp_credential')
            #print "="*80 + user.server_group_access + "*"*80
            if brand.isWhiteLabel() and brand.textkey != 'panopta':
                excluded_items.append('menu.downloads')

            # Special template for FireHost doesn't need Dashboard menu
            if brand.textkey == 'partner.firehost': 
                excluded_items.append('menu.dashboard')
                
        if not customer.public_reports_v1: excluded_items.append('menu.reports.public')

        if user.server_group_access == 'selected': excluded_items.append('menu.settings.apikey')

        # Exclude the user/contacts menu if the user only has a partial view of the account
        if user.server_group_access == 'selected': excluded_items.append('menu.contacts')

        if not customer.canAddServer(): excluded_items.append('menu.server.add_server')

        # Show the global menu for install-level and brand-level admins
        if not user.hasModeratePermission(): excluded_items.append('menu.global')
        
        if not user.isRelatedToAdmin() and not user.customer.brand.hasHeatmap(): 
            excluded_items.append('menu.global.unified_heatmap')

        if not user.isRelatedToAdmin(): 
            # Hide the global items that only apply to install-level admins
            excluded_items.append('menu.global.outage_history')
            excluded_items.append('menu.global.account_history')

        if not user.isRelatedToSuperuser(): excluded_items.append('menu.reports.reseller_summary')

        if not user.isRelatedToAdmin(): excluded_items.append('menu.settings.dashboard')
        
        if user.isDashboardOnlyAccess():
            excluded_items.append('menu.outages')
            excluded_items.append('menu.config')
            excluded_items.append('menu.reports')
            excluded_items.append('menu.billing')
            excluded_items.append('menu.downloads')
            excluded_items.append('menu.global')
            for item in menu_items:
                if item["id"] == "menu.settings":   
                    item.update({
                        'id': 'menu.settings.my_account',
                        'label': 'My Account',
                        'name': _('My Account'), 
                        'data-toggle': 'modal',
                        'link': '/userconfig/EditUser?user_id=-1',
                        'children': []
                    })
                    
#        # Show billing if not restricted by branding
#        if not brand or (brand and brand.show_billing):
#            extra_items.append({'name': 'billing',
#                                'label': _('Billing'),
#                                'link': '/billing',
#                                'children': [],
#                                'perm': 'perm.billing',
#                               })
#        if not brand or (brand and brand.show_support):
#            extra_items.append({'name': 'support',
#                               'label': _('Support'),
#                               'link': '/support',
#                               'children': []
#                               })


        for item in menu_items:
            css_class = ''

 
            if main_nav == item['name']: 
                # We found the menu item that is currently active - set the correct
                # CSS class so that it is rendered properly, plus grab any children that we 
                # need to handle
                css_class = 'active'
                children = item['children']

            # Skip this item if they don't have permission to access or it should be shielded for the brand
            if item['id'] in excluded_items: continue
            if item.has_key('perm') and not identity.has_permission(item['perm']): continue
            
            children = []
            for child in item['children']:
                if child['id'] in excluded_items: continue
                if child.has_key('perm') and not identity.has_permission(child['perm']): continue
                children.append(child)

            link = item['link']
            if len(children) == 1:
                link = children[0]['link']
                children = []

            main_menu.append({'name': item['label'], 
                              'link': link, 
                              'link_class': item.get('link_class', ''),
                              'css_class': css_class,
                              'target': item.get('target', '_self'),
                              'data-toggle': item.get('data-toggle', ''),
                              'children': children})

        # Add custom dashboard links
        main_menu[0]['children'].append({'id': 'menu.dashboard.panopta',
                                         'name': '%s Home' % brand.name,
                                         'label': '%s Home' % brand.name,
                                         'link': '/dashboard',
                                         'children': []})

        dashboards = masterdb.Dashboard.selectBy(customer=customer, deleted=False).orderBy("rank")
        dashboard_list = []
        for d in dashboards:
            if d.created_by != user:
                if d.access_level == 'only_for_me': continue
                elif d.access_level == 'limited_by_tag' and not any([t in user.tags for t in d.tags]): continue
            dashboard_list.append({
                'name': d.name,                
                'rank': d.rank,
                'id': d.id,
                'link': '/dashboard/render_dashboard?dashboard_id=%s' % d.id
            })
        customer_heatmap = customer.getAttribute("heatmap_config")
        try:
            config = json.loads(customer_heatmap)
            d = config['dashboard']
            dashboard_list.append({
                'name': d['name'],
                'rank': d['rank'],
                'id': 'heatmap',
                'link': '/dashboard/Heatmap'
            })
        except:
            pass
        dashboard_list.sort(key=lambda d: d['rank'])        
        for d in dashboard_list:
            main_menu[0]['children'].append({'id': 'menu.dashboard.%s' % d['id'],
                                             'name': d['name'],
                                             'label': d['name'],
                                             'link': d['link'],
                                             'children': [],
                                             })

        if user.inGroup("customer.config") or user.inGroup('brand.superuser') or user.inGroup('customer.admin') or user.inGroup('admin'):
            main_menu[0]['children'].append({'id': 'menu.dashboard.add_dashboard',
                                             'name': 'Add Dashboard',
                                             'label': 'Add Dashboard',  
                                             'data-toggle': 'modal',
                                             'data-divider': 'true',
                                             'link': '/dashboard/EditDashboard',
                                             'children': []})

        # Store the rendered menu in the session so it can be reused on the next pageload
        session['menu-user'] = user
        session['menu-content'] = main_menu
        session['menu-timestamp'] = datetime.now()

        return (main_menu, sub_menu)
Esempio n. 12
0
class Root(controllers.RootController):
    """The root controller of the application."""
    @expose(template="gordonweb.templates.index")
    # @identity.require(identity.in_group("admin"))
    def index(self):
        """Show the welcome page."""
        # log.debug("Happy TurboGears Controller Responding For Duty")
        #flash(_(u"Your application is now running"))
        return dict(now=datetime.datetime.now())

    @expose(template='gordonweb.templates.admin')
    @identity.require(identity.has_permission("edit"))
    def admin(self, task=''):

        if task == 'resolve_all_albums':  #closest_mb_albums_to_db' :
            mbrainz_resolver = gordon.db.mbrainz_resolver.GordonResolver()
            flash("Running mbrainz_resolver.resolve_all_albums()")
            mbrainz_resolver.resolve_all_albums()

        return dict()

    @expose("json")
    @identity.require(identity.has_permission("listen"))
    def audio(self, fn_or_track_id):
        #this should be flexible enough to do either a filename or track_id
        fn_or_track_id = str(fn_or_track_id)
        (path, fn) = os.path.split(fn_or_track_id)
        vals = fn.split('.')
        stub = vals[0]
        if stub.startswith('T'):
            stub = stub[1:]
        try:
            track_id = int(stub)
        except:
            return "Cannot find audio file %s" % str(fn_or_track_id)

        #we are hardcoding a path here to get around NFS issues
        outfn = gordon_db.get_full_audiofilename(track_id)
        print 'Serving', outfn
        return cherrypy.lib.cptools.serveFile(path=outfn,
                                              disposition='attachment',
                                              name=os.path.basename(outfn))

    @expose("json")
    @identity.require(identity.has_permission("listen"))
    def mp3(self, fn_or_track_id):
        #this should be flexible enough to do either a filename or track_id
        fn_or_track_id = str(fn_or_track_id)
        (path, fn) = os.path.split(fn_or_track_id)
        vals = fn.split('.')
        stub = vals[0]
        if stub.startswith('T'):
            stub = stub[1:]
        try:
            track_id = int(stub)
        except:
            return "Cannot find audio file %s" % str(fn_or_track_id)

        #we are hardcoding a path here to get around NFS issues
        audiofn = gordon_db.get_full_audiofilename(track_id)
        if not audiofn.endswith('.mp3'):
            audiofn = widgets.transcode_audio_to_mp3(audiofn)
        print 'Serving', audiofn
        return cherrypy.lib.cptools.serveFile(path=audiofn,
                                              disposition='attachment',
                                              name=os.path.basename(audiofn))

    @expose("json")
    @identity.require(identity.has_permission("listen"))
    def feature(self, fn_or_track_id):
        #this should be flexible enough to do either a filename or track_id
        fn_or_track_id = str(fn_or_track_id)
        (path, fn) = os.path.split(fn_or_track_id)
        vals = fn.split('.')
        stub = vals[0]
        if stub.startswith('T'):
            stub = stub[1:]
        try:
            track_id = int(stub)
        except:
            return "Cannot find feature %s" % str(fn_or_track_id)

        track = gordon_model.Track.query.get(track_id)
        outfn = track.fn_feature

        print 'Serving', outfn
        return cherrypy.lib.cptools.serveFile(path=outfn,
                                              disposition='attachment',
                                              name=os.path.basename(outfn))
        #return serve_file(fn)

    @expose("json")
    @identity.require(identity.has_permission("listen"))
    def cover(self, fn_or_album_id):
        #this should be flexible enough to do either a filename or album_id
        #serves a cover if it is found. Otherwise serves an empty album graphic
        fn_or_album_id = str(fn_or_album_id)
        (path, fn) = os.path.split(fn_or_album_id)
        vals = fn.split('.')
        stub = vals[0]
        if stub.startswith('A'):
            stub = stub[1:]
        try:
            album_id = int(stub)
        except:
            return "Cannot find cover %s" % str(fn_or_album_id)

        fn = ''
        try:
            album = gordon_db.Album.query.get(album_id)
            fn = album.fn_albumcover
        except:
            pass
        if fn == '' or not os.path.exists(fn):
            fn = '/static/images/emptyalbum.jpg'
#        return serve_file(fn)
        return cherrypy.lib.cptools.serveFile(path=fn)

    @expose(template="gordonweb.templates.login")
    def login(self, forward_url=None, *args, **kw):
        """Show the login form or forward user to previously requested page."""

        if forward_url:
            if isinstance(forward_url, list):
                forward_url = forward_url.pop(0)
            else:
                del request.params['forward_url']

        new_visit = visit.current()
        if new_visit:
            new_visit = new_visit.is_new

        if (not new_visit and not identity.current.anonymous
                and identity.was_login_attempted()
                and not identity.get_identity_errors()):
            redirect(forward_url or '/', kw)

        if identity.was_login_attempted():
            if new_visit:
                msg = _(u"Cannot log in because your browser "
                        "does not support session cookies.")
            else:
                msg = _(u"The credentials you supplied were not correct or "
                        "did not grant access to this resource.")
        elif identity.get_identity_errors():
            msg = _(u"You must provide your credentials before accessing "
                    "this resource.")
        else:
            msg = _(u"Please log in.")
            if not forward_url:
                forward_url = request.headers.get("Referer", "/")

        # we do not set the response status here anymore since it
        # is now handled in the identity exception.
        return dict(logging_in=True,
                    message=msg,
                    forward_url=forward_url,
                    previous_url=request.path_info,
                    original_parameters=request.params)

    @expose()
    def logout(self):
        """Log out the current identity and redirect to start page."""
        identity.current.logout()
        redirect("/")

    @expose(template="gordonweb.templates.stats")
    @identity.require(identity.has_permission("listen"))
    def stats(self):
        track_total = gordon_model.Track.query.count()
        artist_total = gordon_model.Artist.query.count()
        album_total = gordon_model.Album.query.count()
        sec_total = gordon_model.session.query(
            func.sum(gordon_model.Track.secs)).first()[0]

        #string
        s = sec_total
        temp = float(s) / (60 * 60 * 24)
        d = int(temp)
        temp = (temp - d) * 24
        h = int(temp)
        temp = (temp - h) * 60
        m = int(temp)
        temp = (temp - m) * 60
        sec = temp
        time_total = '%s days %s hours %s minutes %i seconds' % (d, h, m,
                                                                 int(sec))

        track_labeled = track_total - gordon_model.Track.query.filter_by(
            mb_id='').count()
        artist_labeled = artist_total - gordon_model.Artist.query.filter_by(
            mb_id='').count()
        album_labeled = album_total - gordon_model.Album.query.filter_by(
            mb_id='').count()
        x = 100.0 * track_labeled / track_total

        track_pct = '%2.2f%%' % (100.0 * track_labeled / track_total)
        artist_pct = '%2.2f%%' % (100.0 * artist_labeled / artist_total)
        album_pct = '%2.2f%%' % (100.0 * album_labeled / album_total)

        return dict(track_total=track_total,
                    artist_total=artist_total,
                    album_total=album_total,
                    track_labeled=track_labeled,
                    artist_labeled=artist_labeled,
                    album_labeled=album_labeled,
                    track_pct=track_pct,
                    artist_pct=artist_pct,
                    album_pct=album_pct,
                    time_total=time_total,
                    sec_total=sec_total)

#track-------------------------------------------

    @expose(template="gordonweb.templates.track")
    @identity.require(identity.has_permission("listen"))
    @paginate('artists', default_order='name', limit=20)
    @paginate('albums', default_order='name', limit=20)
    def track(self, id=1, action='view'):

        if len(id) == 36:
            #mbid
            track = gordon_model.Track.query.filter_by(mb_id=id)
            if track.count() > 0:
                track = track.first()
                id = track.id
            else:
                track = None
        else:
            track = gordon_model.Track.query.get(id)
        if track == None:
            flash('gordon_model.Track %s not found' % str(id))
            redirect('/')
        track = gordon_model.Track.query.get(id)
        referer = cherrypy.request.headerMap.get("Referer", "/")
        track.referer = referer
        yahoo_url = get_yahoo_player_audio_url(track)
        #widget_data is for the widget to render while track is the actual record.
        #allows us to render for viewing using DataGrid
        track_time = widgets.get_track_time(track)

        #feat_pathlist = widgets.get_featurelist(track.id)
        feat_urllist = list()
        #for p in feat_pathlist :
        #    elem =ET.Element('a',href='/%s' % p)
        #    (pth,feat)=os.path.split(p)##

        #set a short name to display in url
        #            shortfeat=feat.split('.')
        #           shortfeat=string.join(shortfeat[2:],'.')
        #          elem.text=shortfeat
        #         feat_urllist.append(elem)

        if action == 'edit':
            track_widget = track_edit_widget
            track_widget_data = track
            alternate_action = list()
            sub1 = ET.Element('a', href='/track/%s/view' % str(id))
            sub1.text = 'View'
            alternate_action.append(sub1)

            print alternate_action
            #alternate_action=ET.Element('a',href='/track/%s/view' % str(id))
            #alternate_action.text='View'
            afeat_graph = ''
        else:  #view
            track_widget = null_widget
            track_widget_data = list()  #rotate_record(track)
            alternate_action = list()
            sub1 = ET.Element('a', href='/track/%s/edit' % str(id))
            sub1.text = 'Edit'
            alternate_action.append(sub1)
            grstr = '/dynimage?track=%s' % str(id)
            afeat_graph = ET.Element('a', href=grstr)
            afeat_img = ET.SubElement(afeat_graph,
                                      'img',
                                      align='right',
                                      src=grstr,
                                      width='750')

        #suppress alternate action if we are not an editor
        if not ("edit" in identity.current.permissions):
            alternate_action = ''

        if track.mb_id <> None and len(track.mb_id) > 5:
            track_mb_id_link = ET.Element(
                'a',
                href='http://www.musicbrainz.org/track/%s.html' %
                track.mb_id)  #,target='_blank')
            track_mb_id_link.text = "MusicBrainz"
        else:
            track_mb_id_link = ''

        try:
            htk_annotation_datatables = (
                widgets.generate_htk_annotation_datatables_for_track(track))
        except:
            htk_annotation_datatables = []

        return dict(track_widget=track_widget,
                    track_widget_data=track_widget_data,
                    track=track,
                    afeat_graph=afeat_graph,
                    alternate_action=alternate_action,
                    artist_widget=artist_datagrid,
                    artists=track.artists,
                    track_time=track_time,
                    album_widget=album_datagrid,
                    albums=track.albums,
                    collection_widget=collection_datagrid,
                    collections=track.collections,
                    yahoo_url=yahoo_url,
                    feat_urllist=feat_urllist,
                    track_mb_id_link=track_mb_id_link,
                    htk_annotation_datatables=htk_annotation_datatables)

    @expose(template='gordonweb.templates.tracks')
    @identity.require(identity.has_permission("listen"))
    @paginate('tracks', default_order='id', limit=20)
    def tracks(self, track=''):
        print 'gordon_model.Track is', track
        if track <> '':
            tracks = gordon_model.Track.query.filter(
                "(lower(track.title) ~ ('%s'))" % track.lower())
            if tracks.count() == 1:
                #we only have one track, redirect to the album page
                redirect("/track/%s/view" % tracks[0].id)
            print 'gordon_model.Tracks', tracks.count()
        else:
            tracks = gordon_model.Track.query().order_by('title')
        print 'gordon_model.Tracks', tracks.count(), type(tracks)
        return dict(tracks=tracks, tracklist=track_datagrid)

    @expose()
    @validate(form=track_edit_widget)
    @error_handler(track)
    @identity.require(identity.has_permission("edit"))
    def track_modify(self, **kw):
        operation = kw.pop('operation')
        id = kw.pop('id')
        referer = kw.pop('referer')
        track = gordon_model.Track.query.get(id)
        modfields = list()
        if operation == 'edit':
            for field in kw.keys():
                #if track._SO_getValue(field)<> kw[field] :
                if track.__getattribute__(field) <> kw[field]:
                    modfields.append(field)
                    track.__setattr__(field, kw[field])
                    #not sure how to set a value using field name so we use eval
                    #exec('track.%s=%s' % (field,repr(kw[field])))

            if len(modfields) > 0:
                st = 'Saved track %s with field(s) %s' % (
                    str(id), string.join(modfields, ','))
            else:
                st = 'Nothing to save in track %s' % str(id)
            flash(st)
            if referer.count('resolve') > 0:
                raise (redirect(referer))
            else:
                raise redirect('/track/%s/edit' % id)

        elif operation == 'delete':
            #decrement track count for related album
            #I wish this could happen in the gordon_model.Track class but can't figure out how to get things to work.
            gordon_db.delete_track(track)
            #albums = track.albums;
            #session.delete(track)
            flash('Deleted track %s' % str(id))

            for album in albums:
                if album.trackcount > 0:
                    print 'Decrementing track count of album', album
                    album.trackcount -= 1
                    print 'gordon_model.Album track count is now', album.trackcount

            redirect(referer)

    @expose("json")
    @identity.require(identity.has_permission("listen"))
    def dynimage(self, track=1, name=None, **kwargs):
        track = gordon_model.Track.query.get(track)
        h = widgets.plot_track_features(track, name, **kwargs)
        cherrypy.response.headers['Content-Type'] = "image/png"
        page = h.getvalue()
        return page

    #artists-----------------------------------------
    @expose(template="gordonweb.templates.artist")
    @paginate('albums', default_order='name', limit=25)
    @paginate('artist_top_sims', default_order='value', limit=20)
    @paginate('artist_bottom_sims', default_order='value', limit=20)
    #@paginate('tracks', default_order='title',limit=10)
    @identity.require(identity.has_permission("listen"))
    def artist(self, id=1, action='view', shuffle=''):
        if len(id) == 36:
            #mbid
            artist = gordon_model.Artist.query.filter_by(mb_id=id)
            if artist.count() > 0:
                artist = artist.first()
                id = artist.id
            else:
                artist = None
        else:
            artist = gordon_model.Artist.query.get(id)

        if artist == None:
            flash('gordon_model.Artist %s not found' % str(id))
            redirect('/')

        referer = cherrypy.request.headerMap.get("Referer", "/")
        artist.referer = referer

        if artist.mb_id <> None and len(artist.mb_id) > 5:
            artist_mb_id_link = ET.Element(
                'a',
                href='http://www.musicbrainz.org/artist/%s.html' %
                artist.mb_id)  #,target='_top')
            artist_mb_id_link.text = "MusicBrainz"
        else:
            artist_mb_id_link = ''
        #widget_data is for the widget to render while track is the actual record.
        #allows us to render for viewing using DataGrid
        if action == 'edit':
            artist_widget = artist_edit_widget
            artist_widget_data = artist
            alternate_action = ET.Element('a',
                                          href='/artist/%s/view' % str(id))
            alternate_action.text = 'View'
        else:
            artist_widget = null_widget
            artist_widget_data = list()  #rotate_record(artist)
            alternate_action = ET.Element('a',
                                          href='/artist/%s/edit' % str(id))
            alternate_action.text = 'Edit'

        artist_sims = list()
        artist_top_sims = list()
        artist_bottom_sims = list()
        #artist_sims=gordon_model.ArtistSim.query.filter_by(artist_id=id)
        #if artist_sims.count()==0 :
        #    artist_top_sims=list()
        #    artist_bottom_sims=list()
        #else :
        #    artist_sims=artist_sims[artist_sims.count()-1]
        #    artist_top_sims=artist_sims.top_sims
        #    artist_bottom_sims=artist_sims.bottom_sims

        #build list of audio files
        #for t in artist.tracks :
        tracks = artist.tracks
        random.shuffle(tracks)
        audiourls = list()
        for (ctr, t) in enumerate(tracks):
            link = widgets.get_yahoo_player_audio_url(t, arrow=False)
            audiourls.append(link)
            if ctr == 100:
                break

        if shuffle == '':
            shuffle_state = 0
        else:
            shuffle_state = 1
        return dict(artist_widget=artist_widget,
                    artist_widget_data=artist_widget_data,
                    artist=artist,
                    alternate_action=alternate_action,
                    album_widget=album_datagrid,
                    albums=artist.albums,
                    artist_mb_id_link=artist_mb_id_link,
                    shuffle_state=shuffle_state,
                    action=action,
                    artist_top_sims=artist_top_sims,
                    artist_bottom_sims=artist_bottom_sims,
                    artist_top_sim_datagrid=artist_top_sim_datagrid,
                    artist_bottom_sim_datagrid=artist_bottom_sim_datagrid,
                    audiourls=audiourls)

    @expose(template='gordonweb.templates.artists')
    @identity.require(identity.has_permission("listen"))
    @paginate('artists', default_order='name', limit=20)
    def artists(self, artist='', album=''):
        if artist <> '':
            artists = gordon_model.Artist.query.filter(
                "(lower(artist.name) ~ ('%s'))" % artist.lower())
            if artists.count() == 1:
                redirect("/artist/%s/view" % artists[0].id)
        else:
            artists = gordon_model.Artist.query()

        return dict(artists=artists, artistlist=artist_datagrid)

    @expose(template="gordonweb.templates.artists")
    @identity.require(identity.has_permission("listen"))
    @paginate('artists', default_order='name', limit=10000000)
    def artists_all(self):
        artists = gordon_model.Artist.query()
        return dict(artists=artists, artistlist=artist_datagrid)

    @expose()
    @validate(form=artist_edit_widget)
    @identity.require(identity.has_permission("edit"))
    @error_handler(artist)
    def artist_modify(self, **kw):
        operation = kw.pop('operation')
        id = kw.pop('id')
        mergeid = kw.pop('mergeid')

        referer = kw.pop('referer')
        artist = gordon_model.Artist.query.get(id)
        modfields = list()
        if operation == 'edit':
            for field in kw.keys():
                #if artist._SO_getValue(field)<> kw[field] :
                if artist.__getattribute__(field) <> kw[field]:
                    modfields.append(field)
                    artist.__setattr__(field, kw[field])

            if len(modfields) > 0:
                st = 'Saved artist %s with field(s) %s' % (
                    str(id), string.join(modfields, ','))
            else:
                st = 'Nothing to save in artist %s' % str(id)
            flash(st)
            if referer.count('resolve') > 0:
                raise (redirect(referer))
            else:
                raise redirect('/artist/%s/edit' % id)

        elif operation == 'delete':
            #session.delete(artist)
            flash('Would have deleted artist %s' % str(id))
            redirect(referer)

        elif operation == 'merge':
            #str = 'Would have merged artist %s with artist %s' % (str(id),str(mergeid))
            flash('Would have merged artist %s with artist %s' %
                  (str(id), str(mergeid)))
            tracks = gordon_model.Artist.query.get(int(id))
            for t in tracks:
                print

            redirect(referer)

    #queries -----------------------
    @expose("json")
    @identity.require(identity.has_permission("listen"))
    def query(self, album='', artist='', track='', collection=''):
        if album <> '':
            redirect("/albums", dict(album=album))
        elif artist <> '':
            redirect("/artists", dict(artist=artist))
        elif collection <> '':
            redirect("/collections", dict(collection=collection))
        elif track <> '':
            redirect("/tracks", dict(track=track))
        else:
            referrer = request.headers.get("Referer", "/")
            if referrer.endswith('query'):
                #break feedback loop
                redirect('/')
            else:
                redirect(referrer)

    #albums-----------------------------------------
    @expose(template="gordonweb.templates.album")
    @identity.require(identity.has_permission("listen"))
    @paginate('tracks', default_order='tracknum', limit=1000000)
    @paginate('artists', default_order='name', limit=50)
    def album(self, id=1, action='view', shuffle=''):
        if len(id) == 36:
            #mbid
            album = gordon_model.Album.query.filter_by(mb_id=id)
            if album.count() > 0:
                album = album.first()
                id = album.id
            else:
                album = None
        else:
            album = gordon_model.Album.query.get(id)
        if album == None:
            flash('gordon_model.Album %s not found' % str(id))
            redirect('/')

        referer = cherrypy.request.headerMap.get("Referer", "/")
        album.referer = referer
        albumcover = widgets.get_albumcover(album)
        artiststring = widgets.get_album_artiststring(album)
        if album.mb_id <> None and len(album.mb_id) > 5:
            album_mb_id_link = ET.Element(
                'a',
                href='http://www.musicbrainz.org/release/%s.html' %
                album.mb_id)  #target='_blank')
            album_mb_id_link.text = "MusicBrainz"
        else:
            album_mb_id_link = ''
        #widget_data is for the widget to render while track is the actual record.
        #allows us to render for viewing using DataGrid
        if action == 'edit':
            album_widget = album_edit_widget
            album_widget_data = album
            alternate_action = ET.Element('a', href='/album/%s/view' % str(id))
            alternate_action.text = 'View'
            track_widget = track_edit_datagrid
            deleteform_header = ET.Element('form',
                                           action='/album_modify/deletetracks',
                                           method="post")
            deleteform_button = ET.Element(
                'input',
                type='submit',
                value='Delete Selected gordon_model.Tracks')
            deleteform_footer = ET.Element('/form')
        else:
            album_widget = null_widget
            album_widget_data = list()  #rotate_record(artist)
            alternate_action = ET.Element('a', href='/album/%s/edit' % str(id))
            alternate_action.text = 'Edit'
            track_widget = track_datagrid_no_album
            deleteform_header = ''
            deleteform_button = ''
            deleteform_footer = ''

        album_sims = list()
        album_top_sims = list()
        album_bottom_sims = list()
        #        album_sims=gordon_model.AlbumSim.query.filter_by(album_id=id)
        #        if album_sims.count()==0 :
        #            album_top_sims=list()
        #            album_bottom_sims=list()
        #        else :
        #            album_sims=album_sims[album_sims.count()-1]
        #            album_top_sims=album_sims.top_sims
        #            album_bottom_sims=album_sims.bottom_sims

        top_albumcovers = list()
        top_albumtitles = list()
        top_albumartists = list()
        albumtitles = set()
        albumartists = set()
        albumids = set()  #albums already used
        ctr = 0
        idx = 0
        #build our grid for similar albums
        doall = False
        do_albumgrid = False
        while do_albumgrid and len(album_top_sims) > 0:
            if idx == len(album_top_sims):
                #oops we ran out of data. Loop again and take whatever we can get
                idx = 1
                doall = True

            if ctr == 9:
                break

            other = album_top_sims[idx].other
            if not other:
                break
            album_id = other.id
            atitle = other.name
            if len(album_top_sims[idx].other.artists) > 1:
                aartist = "Various gordon_model.Artists"
            elif len(album_top_sims[idx].other.artists) == 0:
                aartist = "Unknown"
            else:
                aartist = album_top_sims[idx].other.artists[0].name
            albumcvr = widgets.get_albumcover(album_top_sims[idx].other,
                                              clickable=False,
                                              sz=90)

            albumtitle = ET.Element('a', href='/album/%s' % album_id)
            if len(atitle) > 20:
                atitle = '%s...' % atitle[0:19]
            albumtitle.text = atitle

            albumartist = ET.Element('a', href='/album/%s' % album_id)
            albumartist.text = aartist
            idx += 1

            if not doall:
                #we try to skip some undesirable albums
                if atitle == "":  #skip blank albums
                    continue
                if atitle.lower() == gordon_model.Album.query.get(
                        id).name.lower and aartist.lower(
                        ) == gordon_model.Album.query.get(id).artists[0].name:
                    continue
                if aartist.lower() == 'various artists':
                    continue
                if aartist.lower() in albumartists:
                    continue
            albumartists.add(aartist.lower())
            albumtitles.add(atitle.lower())

            top_albumcovers.append(albumcvr)
            top_albumtitles.append(albumtitle)
            top_albumartists.append(albumartist)
            ctr += 1
        do_albumgrid = len(top_albumcovers) > 8  #should we show an album grid?

        tracks = album.tracks
        if shuffle <> '':
            random.shuffle(tracks)

        return dict(album_widget=album_widget,
                    album_widget_data=album_widget_data,
                    album=album,
                    alternate_action=alternate_action,
                    artiststring=artiststring,
                    album_mb_id_url=get_album_mb_id_url(album.mb_id),
                    albumcover=albumcover,
                    tracks=album.tracks,
                    track_widget=track_widget,
                    artist_widget=artist_datagrid,
                    artists=album.artists,
                    deleteform_header=deleteform_header,
                    deleteform_button=deleteform_button,
                    deleteform_footer=deleteform_footer,
                    album_mb_id_link=album_mb_id_link,
                    action=action,
                    album_top_sims=album_top_sims,
                    album_bottom_sims=album_bottom_sims,
                    album_top_sim_datagrid=album_top_sim_datagrid,
                    album_bottom_sim_datagrid=album_bottom_sim_datagrid,
                    top_albumcovers=top_albumcovers,
                    top_albumtitles=top_albumtitles,
                    top_albumartists=top_albumartists,
                    do_albumgrid=do_albumgrid)

    @expose()
    @validate(form=album_edit_widget)
    @identity.require(identity.has_permission("edit"))
    @error_handler(album)
    def album_modify(self, **kw):
        operation = kw.pop('operation')
        id = kw.pop('id')
        referer = kw.pop('referer')
        album = gordon_model.Album.query.get(id)
        modfields = list()
        if operation == 'edit':
            for field in kw.keys():
                if album.__getattribute__(field) <> kw[field]:
                    modfields.append(field)
                    album.__setattr__(field, kw[field])
                    #not sure how to set a value using field name so we use eval
                    exec('album.%s=%s' % (field, repr(kw[field])))

            if len(modfields) > 0:
                st = 'Saved album %s with field(s) %s' % (
                    str(id), string.join(modfields, ','))
            else:
                st = 'Nothing to save in album %s' % str(id)
            flash(st)
            if referer.count('resolve') > 0:
                raise (redirect(referer))
            else:
                raise redirect('/album/%s/edit' % id)

        elif operation == 'delete':
            gordon_db.delete_album(album)
            flash('Deleted album %s' % str(id))
            redirect(referer)

        elif operation == 'deletetracks':
            for field in kw.keys():
                #delete checked tracks
                if kw[field] == 'on':
                    try:
                        id = int(field)
                        track = gordon_model.Track.query.get(id)
                        print 'Deleting', track
                        gordon_db.delete_track(track)
                    except:
                        print 'Could not delete track', field
            redirect(referer)

#123979

    @expose(template='gordonweb.templates.albums')
    @paginate('albums', default_order='name', limit=20)
    @identity.require(identity.has_permission("listen"))
    def albums(self, album=''):
        if album <> '':
            print 'Searching for', album
            albums = gordon_model.Album.query.filter(
                "(lower(album.name) ~ ('%s'))" % album.lower())
            if albums.count() == 1:
                #we only have one album, redirect to the album page
                redirect("/album/%s/view" % albums[0].id)
        else:
            albums = gordon_model.Album.query()

        return dict(albums=albums, albumlist=album_datagrid)

    @expose(template="gordonweb.templates.albums")
    @paginate('albums', default_order='name', limit=1000000)
    @identity.require(identity.has_permission("listen"))
    def albums_all(self):
        albums = gordon_model.Album.query()
        return dict(albums=albums, albumlist=album_datagrid)

    #resolver---------------------------------------------
    @expose("json")
    @identity.require(identity.has_permission("edit"))
    def resolve_submitalbum(self, id=0, mb_id=''):
        mbrainz_resolver = gordon.db.mbrainz_resolver.GordonResolver()
        if mb_id == '':
            st = 'Recieved no mb_id'
        elif id == 0:
            st = 'Recieved invalid id'
        else:
            mbrainz_resolver.update_album(id=id,
                                          mb_id=mb_id,
                                          use_recommended_track_order=True,
                                          doit=True)
            st = 'Resolved musicbrainz album id %s against internal album id %s' % (
                mb_id, id)

        flash(st)

        #now go back to our review page
        redirect("/resolve_viewalbums")
        #referrer=request.headers.get("Referer", "/")
        #redirect(referrer)

    @expose()
    @identity.require(identity.has_permission("edit"))
    def resolve_submitalbums(self, **kw):
        mbrainz_resolver = gordon.db.mbrainz_resolver.GordonResolver()
        st = ''
        for k in kw:
            (id, mb_id) = k.split('SEP')
            mb_id = mb_id.replace('H', '-')
            mbrainz_resolver.update_album(id=id,
                                          mb_id=mb_id,
                                          use_recommended_track_order=True,
                                          doit=True)
            st = "%s\nUpdated %s" % (st, id)
        flash(st)
        redirect("/resolve_viewalbums")

    @expose()
    @identity.require(identity.has_permission("edit"))
    def resolve_recommendalbum(self, id=1):
        mbrainz_resolver = gordon.db.mbrainz_resolver.GordonResolver()
        mbrainz_resolver.resolve_album(id=id)
        redirect(request.headers.get("Referer", "/"))

    @expose()
    @identity.require(identity.has_permission("edit"))
    def resolve_setalbumstatus(self, id, status="weird", sort_order='conf'):
        #set the status of an album.
        id = int(id)
        album = gordon_model.Album.query.get(id)
        if gordon_model.AlbumStatus.query.filter_by(
                album=album, status=status).count() == 0:
            gordon_model.AlbumStatus(album=album, status=status)

        #TODO: this next line will not ever return recommendations for albums marked with *any* AlbumStatus
        #it should probably be to only ignore those which are from a fixed list of AlbumStatus codewords.  Anyway this warrants
        #discussion. . .

        #here we pull up the next album in the list. Is that what we want to do?
        mbrecommend = gordon_model.Mbalbum_recommend.query.filter(
            gordon_model.Mbalbum_recommend.album.has(
                gordon_model.Album.mb_id == '')).filter(
                    gordon_model.Mbalbum_recommend.album.has(
                        ~gordon_model.Album.status.any())).order_by('%s DESC' %
                                                                    sort_order)
        print 'Redirecting to', str(mbrecommend[0].album_id)
        redirect("/resolve_viewalbum/%s" % str(mbrecommend[0].album_id))

    @expose(template="gordonweb.templates.resolve_viewalbum")
    @paginate('tracks', limit=100000000)
    @identity.require(identity.has_permission("edit"))
    def resolve_viewalbum(self, id=1):

        album = gordon_model.Album.query.get(id)
        tracks = album.tracks
        albumcover = widgets.get_albumcover(album)
        artiststring = widgets.get_album_artiststring(album)
        res = gordon_model.Mbalbum_recommend.query.filter_by(album_id=id)

        if res.count() <> 1:
            flash(
                'No recommendation or multiple recommendations for album %s' %
                id)
            redirect("/resolve_viewalbums")
        else:
            mbrecommend = res[0]

        if mbrecommend.trackorder <> None:
            trackorder = eval(mbrecommend.trackorder)
            if len(trackorder) == len(tracks):
                trks = [0] * len(tracks)
                for t in tracks:
                    idx = trackorder[t.id]
                    trks[idx] = t
                tracks = trks

        mbrainz_resolver = gordon.db.mbrainz_resolver.GordonResolver()

        #get the recommended album name for display

        (recommend_tracks,
         status) = mbrainz_resolver.add_mbalbumdata_to_trackdict(
             mbrecommend.mb_id, tracks)  #adds mb tracks to tracks structure
        if status == False:
            #try redoing the recommmendation
            print 'Trying to get closest album'
            mbrainz_resolver.resolve_album(id)
            (recommend_tracks,
             status) = mbrainz_resolver.add_mbalbumdata_to_trackdict(
                 mbrecommend.mb_id,
                 tracks)  #adds mb tracks to tracks structure
            if status == False:
                flash('Unable to merge tracks for album %s' % id)
                redirect('/resolve_viewalbums')
        mbrecommend_mb_id_url = widgets.get_album_mb_id_url(mbrecommend.mb_id)
        mb_album = mbrecommend.mb_album
        submit_form = TableForm(
            fields=[
                TextField(name='mb_id',
                          default=mbrecommend.mb_id,
                          label='Recommended MB_ID',
                          attrs=dict(size='38'))
            ],
            action="../resolve_submitalbum/%s" % str(id),
            submit_text="Accept and Update(!)",
        )
        return dict(album=album,
                    artiststring=artiststring,
                    albumcover=albumcover,
                    tracks=recommend_tracks,
                    mb_album=mb_album,
                    tracklist=mbrecommend_track_datagrid,
                    mbrecommend=mbrecommend,
                    submit_form=submit_form,
                    mbrecommend_mb_id_url=mbrecommend_mb_id_url)

    @expose(template="gordonweb.templates.resolve_viewalbums")
    @paginate('mbrecommend', default_order='-conf', limit=20)
    def resolve_viewalbums(self):
        #get recommendations for un-mbrid albums with no status messages
        #here we assume that any status is a bad one. But this could be softened  by changing the any part of the query
        mbrecommend = gordon_model.Mbalbum_recommend.query.filter(
            gordon_model.Mbalbum_recommend.album.has(
                or_(gordon_model.Album.mb_id == '',
                    gordon_model.Album.mb_id == None))).filter(
                        gordon_model.Mbalbum_recommend.album.has(
                            ~gordon_model.Album.status.any()))
        return dict(mbrecommend=mbrecommend,
                    mbrecommend_list=mbrecommend_datagrid)

    #download ---------------------------------------
    #@expose("json")
    @expose()
    #@identity.require(identity.has_permission("listen"))
    def download(self, params=''):
        pdict = {
            'track_id': '',
            'artist_id': '',
            'album_id': '',
            'collection_id': '',
            'randomize': '0'
        }
        pairs = params.split('!')
        for p in pairs:
            (key, val) = p.split(':')
            pdict[key] = val
        tracks = ''
        album = ''
        if pdict['album_id'] <> '':
            tracks = gordon_model.Album.query.get(int(
                pdict['album_id'])).tracks
        elif pdict['collection_id'] <> '':
            tracks = gordon_model.Collection.query.get(
                int(pdict['collection_id'])).tracks
        elif pdict['artist_id'] <> '':
            tracks = gordon_model.Artist.query.get(int(
                pdict['artist_id'])).tracks
        elif pdict['track_id'] <> '':
            tracks = [gordon_model.Track.query.get(int(pdict['track_id']))]

        return widgets.download(tracks=tracks,
                                album=album,
                                randomize=int(pdict['randomize']))

    #playlist ---------------------------------------
#    @expose("json", format="xml")

    @expose("gordonweb.templates.playlist_album", format="XML")
    #@identity.require(identity.has_permission("listen"))
    def playlist(self, params=''):
        if params.endswith('.xml'):
            params = params[0:len(params) - 4]
            print params
        pdict = {
            'track_id': '',
            'artist_id': '',
            'album_id': '',
            'randomize': '0'
        }
        pairs = params.split('!')
        for p in pairs:
            (key, val) = p.split(':')
            pdict[key] = val
        tracks = ''
        album = ''
        if pdict['album_id'] <> '':
            album = gordon_model.Album.query.get(int(pdict['album_id']))
            tracks = album.tracks
        elif pdict['artist_id'] <> '':
            tracks = gordon_model.Artist.query.get(int(
                pdict['artist_id'])).tracks
        elif pdict['track_id'] <> '':
            tracks = [gordon_model.Track.query.get(int(pdict['track_id']))]
        return widgets.playlist(tracks=tracks,
                                album=album,
                                randomize=int(pdict['randomize']))

    #collections-----------------------------------------
    @expose(template="gordonweb.templates.collection")
    @identity.require(identity.has_permission("listen"))
    @paginate('tracks', default_order='album', limit=1000000)
    def collection(self, id=1, action='view', shuffle=''):
        collection = gordon_model.Collection.query.get(id)
        if collection == None:
            flash('gordon_model.Collection %s not found' % str(id))
            redirect('/')

        tracks = collection.tracks
        if shuffle <> '':
            random.shuffle(tracks)

        return dict(action=action,
                    collection=collection,
                    collection_datagrid=collection_datagrid,
                    tracks=tracks,
                    track_datagrid=track_datagrid)

    @expose(template='gordonweb.templates.collections')
    @paginate('collections', default_order='name', limit=20)
    @identity.require(identity.has_permission("listen"))
    def collections(self, collection=''):
        if collection <> '':
            print 'Searching for', collection
            collections = gordon_model.Collection.query.filter(
                "(lower(collection.name) ~ ('%s'))" % collection.lower())
            if collections.count() == 1:
                #we only have one collection, redirect to the collection page
                redirect("/collection/%s/view" % collections[0].id)
        else:
            collections = gordon_model.Collection.query()

        return dict(collections=collections,
                    collectionlist=collection_datagrid)

    @expose(template="gordonweb.templates.collections")
    @paginate('collections', default_order='name', limit=1000000)
    @identity.require(identity.has_permission("listen"))
    def collections_all(self):
        collections = gordon_model.Collection.query()
        return dict(collections=collections,
                    collectionlist=collection_datagrid)

    #feature extractors-----------------------------------------
    @expose(template="gordonweb.templates.feature_extractor")
    @identity.require(identity.has_permission("listen"))
    #@paginate('tracks', default_order='tracknum',limit=1000000)
    def feature_extractor(self, id=1, action='view'):
        fe = gordon_model.FeatureExtractor.query.get(id)
        if fe == None:
            flash('gordon_model.FeatureExtractor %s not found' % str(id))
            redirect('/')

        source_code = get_feature_extractor_source_code(fe)

        return dict(action=action,
                    feature_extractor=fe,
                    source_code=source_code)

    @expose(template='gordonweb.templates.feature_extractors')
    @paginate('feature_extractors', default_order='name', limit=20)
    def feature_extractors(self, feature_extractor=''):
        if feature_extractor <> '':
            print 'Searching for', feature_extractor
            fes_extractors = gordon_model.FeatureExtractor.query.filter(
                "(lower(feature_extractor.name) ~ ('%s'))" %
                feature_extractor.lower())
            if fes.count() == 1:
                #we only have one feature_extractor, redirect to the feature_extractor page
                redirect("/feature_extractor/%s/view" % fes[0].id)
        else:
            fes = gordon_model.FeatureExtractor.query()

        return dict(feature_extractors=fes,
                    feature_extractorlist=feature_extractor_datagrid)