def setUp(self): from flask import Flask from flask.ext.appbuilder.baseapp import BaseApp from flask.ext.appbuilder.models.datamodel import SQLAModel from flask.ext.appbuilder.views import GeneralView self.app = Flask(__name__) self.basedir = os.path.abspath(os.path.dirname(__file__)) self.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' self.app.config['CSRF_ENABLED'] = False self.app.config['SECRET_KEY'] = 'thisismyscretkey' self.app.config['WTF_CSRF_ENABLED'] = False self.db = SQLAlchemy(self.app) class Model1View(GeneralView): datamodel = SQLAModel(Model1, self.db.session) class Model2View(GeneralView): datamodel = SQLAModel(Model2, self.db.session) related_views = [Model1View] self.baseapp = BaseApp(self.app, self.db) self.baseapp.add_view(Model1View(), "Model1") self.baseapp.add_view(Model2View(), "Model2") self.baseapp.add_view(Model2View(), "Model2 Add", href='/model2view/add')
class FlaskTestCase(unittest.TestCase): def setUp(self): from flask import Flask from flask.ext.appbuilder.baseapp import BaseApp from flask.ext.appbuilder.models.datamodel import SQLAModel from flask.ext.appbuilder.views import GeneralView self.app = Flask(__name__) self.basedir = os.path.abspath(os.path.dirname(__file__)) self.app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' self.app.config['CSRF_ENABLED'] = False self.app.config['SECRET_KEY'] = 'thisismyscretkey' self.app.config['WTF_CSRF_ENABLED'] = False self.db = SQLAlchemy(self.app) class Model1View(GeneralView): datamodel = SQLAModel(Model1) class Model2View(GeneralView): datamodel = SQLAModel(Model2) related_views = [Model1View] class Model1Filtered1View(GeneralView): datamodel = SQLAModel(Model1) base_filters = [['field_string', FilterStartsWith, 'a']] class Model1Filtered2View(GeneralView): datamodel = SQLAModel(Model1, self.db.session) base_filters = [['field_integer', FilterEqual, 0]] self.baseapp = BaseApp(self.app, self.db) self.baseapp.add_view(Model1View, "Model1") self.baseapp.add_view(Model1Filtered1View, "Model1Filtered1") self.baseapp.add_view(Model1Filtered2View, "Model1Filtered2") self.baseapp.add_view(Model2View, "Model2") self.baseapp.add_view(Model2View, "Model2 Add", href='/model2view/add') def tearDown(self): self.baseapp = None self.app = None self.db = None log.debug("TEAR DOWN") """ --------------------------------- TEST HELPER FUNCTIONS --------------------------------- """ def login(self, client, username, password): # Login with default admin return client.post('/login/', data=dict( username=username, password=password ), follow_redirects=True) def logout(self, client): return client.get('/logout/') def insert_data(self): for x,i in zip(string.ascii_letters[:23], range(23)): model = Model1(field_string="%stest" % (x), field_integer=i) self.db.session.add(model) self.db.session.commit() def test_fab_views(self): """ Test views creation and registration """ eq_(len(self.baseapp.baseviews), 15) # current minimal views are 11 def test_model_creation(self): """ Test Model creation """ from sqlalchemy.engine.reflection import Inspector engine = self.db.session.get_bind(mapper=None, clause=None) inspector = Inspector.from_engine(engine) # Check if tables exist ok_('model1' in inspector.get_table_names()) ok_('model2' in inspector.get_table_names()) def test_index(self): """ Test initial access and index message """ client = self.app.test_client() # Check for Welcome Message rv = client.get('/') data = rv.data.decode('utf-8') ok_(DEFAULT_INDEX_STRING in data) def test_sec_login(self): """ Test Security Login, Logout, invalid login, invalid access """ client = self.app.test_client() # Try to List and Redirect to Login rv = client.get('/model1view/list/') eq_(rv.status_code, 302) rv = client.get('/model2view/list/') eq_(rv.status_code, 302) # Login and list with admin self.login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD) rv = client.get('/model1view/list/') eq_(rv.status_code, 200) rv = client.get('/model2view/list/') eq_(rv.status_code, 200) # Logout and and try to list self.logout(client) rv = client.get('/model1view/list/') eq_(rv.status_code, 302) rv = client.get('/model2view/list/') eq_(rv.status_code, 302) # Invalid Login rv = self.login(client, DEFAULT_ADMIN_USER, 'password') data = rv.data.decode('utf-8') ok_(INVALID_LOGIN_STRING in data) def test_sec_reset_password(self): """ Test Security reset password """ client = self.app.test_client() # Try Reset My password rv = client.get('/users/action/resetmypassword/1', follow_redirects=True) data = rv.data.decode('utf-8') ok_(ACCESS_IS_DENIED in data) #Reset My password rv = self.login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD) rv = client.get('/users/action/resetmypassword/1', follow_redirects=True) data = rv.data.decode('utf-8') ok_("Reset Password Form" in data) rv = client.post('/resetmypassword/form', data=dict(password='******', conf_password='******'), follow_redirects=True) eq_(rv.status_code, 200) self.logout(client) self.login(client, DEFAULT_ADMIN_USER, 'password') rv = client.post('/resetmypassword/form', data=dict(password=DEFAULT_ADMIN_PASSWORD, conf_password=DEFAULT_ADMIN_PASSWORD), follow_redirects=True) eq_(rv.status_code, 200) def test_model_crud(self): """ Test Model add, delete, edit """ client = self.app.test_client() rv = self.login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD) rv = client.post('/model1view/add', data=dict(field_string='test1', field_integer='1'), follow_redirects=True) eq_(rv.status_code, 200) model = self.db.session.query(Model1).first() eq_(model.field_string, u'test1') eq_(model.field_integer, 1) rv = client.post('/model1view/edit/1', data=dict(field_string='test2', field_integer='2'), follow_redirects=True) eq_(rv.status_code, 200) model = self.db.session.query(Model1).first() eq_(model.field_string, u'test2') eq_(model.field_integer, 2) rv = client.get('/model1view/delete/1', follow_redirects=True) eq_(rv.status_code, 200) model = self.db.session.query(Model1).first() eq_(model, None) def test_model_add_validation(self): """ Test Model add validations """ client = self.app.test_client() self.login(client, 'admin', 'general') rv = client.post('/model1view/add', data=dict(field_string='test1', field_integer='1'), follow_redirects=True) eq_(rv.status_code, 200) rv = client.post('/model1view/add', data=dict(field_string='test1', field_integer='2'), follow_redirects=True) eq_(rv.status_code, 200) data = rv.data.decode('utf-8') ok_(UNIQUE_VALIDATION_STRING in data) model = self.db.session.query(Model1).all() eq_(len(model), 1) rv = client.post('/model1view/add', data=dict(field_string='', field_integer='1'), follow_redirects=True) eq_(rv.status_code, 200) data = rv.data.decode('utf-8') ok_(NOTNULL_VALIDATION_STRING in data) model = self.db.session.query(Model1).all() eq_(len(model), 1) def test_model_edit_validation(self): """ Test Model edit validations """ client = self.app.test_client() self.login(client, 'admin', 'general') client.post('/model1view/add', data=dict(field_string='test1', field_integer='1'), follow_redirects=True) client.post('/model1view/add', data=dict(field_string='test2', field_integer='1'), follow_redirects=True) rv = client.post('/model1view/edit/1', data=dict(field_string='test2', field_integer='2'), follow_redirects=True) eq_(rv.status_code, 200) data = rv.data.decode('utf-8') ok_(UNIQUE_VALIDATION_STRING in data) rv = client.post('/model1view/edit/1', data=dict(field_string='', field_integer='2'), follow_redirects=True) eq_(rv.status_code, 200) data = rv.data.decode('utf-8') ok_(NOTNULL_VALIDATION_STRING in data) def test_model_base_filter(self): """ Test Model base filtered views """ client = self.app.test_client() self.login(client, DEFAULT_ADMIN_USER, DEFAULT_ADMIN_PASSWORD) self.insert_data() models = self.db.session.query(Model1).all() eq_(len(models), 23) # Base filter string starts with rv = client.get('/model1filtered1view/list/') data = rv.data.decode('utf-8') ok_('atest' in data) ok_('btest' not in data) # Base filter integer equals rv = client.get('/model1filtered2view/list/') data = rv.data.decode('utf-8') ok_('atest' in data) ok_('btest' not in data)
label_columns = ContactGeneralView.label_columns group_by_columns = ["group", "gender"] datamodel = SQLAModel(Contact, db.session) class ContactTimeChartView(TimeChartView): chart_title = "Grouped Birth contacts" chart_type = "AreaChart" label_columns = ContactGeneralView.label_columns group_by_columns = ["birthday"] datamodel = SQLAModel(Contact, db.session) class GroupGeneralView(GeneralView): datamodel = SQLAModel(Group, db.session) related_views = [ContactGeneralView] fixed_translations_import = [_("List Groups"), _("List Contacts"), _("Contacts Chart"), _("Contacts Birth Chart")] fill_gender() genapp = BaseApp(app, db) genapp.add_view( GroupGeneralView(), "List Groups", icon="fa-folder-open-o", category="Contacts", category_icon="fa-envelope" ) genapp.add_view(ContactGeneralView(), "List Contacts", icon="fa-envelope", category="Contacts") genapp.add_separator("Contacts") genapp.add_view(ContactChartView(), "Contacts Chart", icon="fa-dashboard", category="Contacts") genapp.add_view(ContactTimeChartView(), "Contacts Birth Chart", icon="fa-dashboard", category="Contacts")
list_widget = ListBlock show_widget = ShowBlockWidget label_columns = {'photo_img': 'Photo'} list_columns = ['name', 'photo_img', 'price_label'] search_columns = ['name', 'price', 'product_type'] show_fieldsets = [ ('Summary', {'fields': ['name', 'price_label', 'photo_img', 'product_type']}), ( 'Description', {'fields': ['description'], 'expanded': True}), ] class ProductView(GeneralView): datamodel = SQLAModel(Product) class ProductTypeView(GeneralView): datamodel = SQLAModel(ProductType) related_views = [ProductView] baseapp = BaseApp(app, db) baseapp.add_view(ProductPubView, "Our Products", icon="fa-folder-open-o") baseapp.add_view(ProductView, "List Products", icon="fa-folder-open-o", category="Management") baseapp.add_separator("Management") baseapp.add_view(ProductTypeView, "List Product Types", icon="fa-envelope", category="Management")
from flask.ext.appbuilder.baseviews import expose from flask.ext.appbuilder.security.decorators import has_access from app import app, db class MyView(BaseView): default_view = "method1" @expose("/method1/") @has_access def method1(self): # do something with param1 # and return to previous page or index return "Hello" @expose("/method2/<string:param1>") @has_access def method2(self, param1): # do something with param1 # and render template with param param1 = "Goodbye %s" % (param1) return param1 genapp = BaseApp(app, db) genapp.add_view(MyView(), "Method1", category="My View") # genapp.add_view(MyView(), "Method2", href='/myview/method2/jonh', category='My View') # Use add link instead there is no need to create MyView twice. genapp.add_link("Method2", href="/myview/method2/jonh", category="My View")
class ProjectFilesGeneralView(GeneralView): datamodel = SQLAModel(ProjectFiles) label_columns = {'file_name': 'File Name', 'download': 'Download'} add_columns = ['file', 'description','project'] edit_columns = ['file', 'description','project'] list_columns = ['file_name', 'download'] show_columns = ['file_name', 'download'] class ProjectGeneralView(CompactCRUDMixin, GeneralView): datamodel = SQLAModel(Project) related_views = [ProjectFilesGeneralView] show_template = 'appbuilder/general/model/show_cascade.html' edit_template = 'appbuilder/general/model/edit_cascade.html' add_columns = ['name'] edit_columns = ['name'] list_columns = ['name', 'created_by', 'created_on', 'changed_by', 'changed_on'] show_fieldsets = [ ('Info', {'fields': ['name']}), ('Audit', {'fields': ['created_by', 'created_on', 'changed_by', 'changed_on'], 'expanded': False}) ] baseapp = BaseApp(app, db) baseapp.add_view(ProjectGeneralView, "List Projects", icon="fa-table", category="Projects") baseapp.add_view_no_menu(ProjectFilesGeneralView)
from flask.ext.appbuilder.baseapp import BaseApp from flask.ext.appbuilder.baseviews import BaseView from flask.ext.appbuilder.baseviews import expose from app import app, db class MyView(BaseView): route_base = "/myview" @expose('/method1/<string:param1>') def method1(self, param1): # do something with param1 # and return to previous page or index param1 = 'Hello %s' % (param1) return param1 @expose('/method2/<string:param1>') def method2(self, param1): # do something with param1 # and render template with param param1 = 'Goodbye %s' % (param1) return param1 genapp = BaseApp(app, db) genapp.add_view_no_menu(MyView())
from flask import render_template from flask.ext.appbuilder.baseapp import BaseApp from flask.ext.appbuilder.models.datamodel import SQLAModel from flask.ext.appbuilder.views import GeneralView, BaseView, expose from app import app, db class FABView(BaseView): """ A simple view that implements the index for the site """ route_base = '' default_view = 'index' index_template = 'index.html' @expose('/') def index(self): return render_template(self.index_template, baseapp = self.baseapp) class ContactsView(BaseView): route_base = "/contacts" index_template = 'contacts.html' @expose('/') def index(self): return render_template(self.index_template, baseapp = self.baseapp) baseapp = BaseApp(app, db, indexview = FABView) baseapp.add_view(ContactsView(), "Contacts", href='/contacts',icon='earphone',category='Info')
('Summary', {'fields': ['name', 'photo', 'address', 'group']}), ('Personal Info', {'fields': ['birthday', 'personal_phone', 'personal_celphone', 'personal_email'], 'expanded': False}), ('Professional Info', {'fields': ['business_function', 'business_phone', 'business_celphone', 'business_email'], 'expanded': False}), ('Extra', {'fields': ['notes'], 'expanded': False}), ] class GroupGeneralView(GeneralView): datamodel = SQLAModel(Group, db.session) related_views = [PersonGeneralView] label_columns = {'phone1': 'Phone (1)', 'phone2': 'Phone (2)', 'taxid': 'Tax ID'} list_columns = ['name', 'notes'] class PersonChartView(ChartView): route_base = '/persons' datamodel = SQLAModel(Person, db.session) chart_title = 'Grouped Persons' label_columns = PersonGeneralView.label_columns group_by_columns = ['group'] search_columns = ['name', 'group'] baseapp = BaseApp(app, db) baseapp.add_view(GroupGeneralView(), "List Groups", icon="fa-folder-open-o", category="Contacts") baseapp.add_view(PersonGeneralView(), "List Contacts", icon="fa-envelope", category="Contacts") baseapp.add_view(PersonChartView(), "Contacts Chart", icon="fa-dashboard", category="Contacts")
from flask.ext.appbuilder.models.datamodel import SQLAModel from flask.ext.appbuilder.views import GeneralView from flask_appbuilder.charts.views import DirectChartView from app import app, db from models import CountryStats, Country class CountryStatsGeneralView(GeneralView): datamodel = SQLAModel(CountryStats) list_columns = ['country', 'stat_date', 'population', 'unemployed', 'college'] class CountryGeneralView(GeneralView): datamodel = SQLAModel(Country) class CountryStatsDirectChart(DirectChartView): datamodel = SQLAModel(CountryStats) chart_title = 'Statistics' chart_type = 'LineChart' direct_columns = {'General Stats': ('stat_date', 'population', 'unemployed', 'college')} base_order = ('stat_date', 'asc') genapp = BaseApp(app, db) genapp.add_view(CountryGeneralView, "List Countries", icon="fa-folder-open-o", category="Statistics") genapp.add_view(CountryStatsGeneralView, "List Country Stats", icon="fa-folder-open-o", category="Statistics") genapp.add_separator("Statistics") genapp.add_view(CountryStatsDirectChart, "Show Country Chart", icon="fa-dashboard", category="Statistics")
class GroupGeneralView(GeneralView): datamodel = SQLAModel(Group, db.session) related_views = [ContactGeneralView()] list_columns = ['name'] order_columns = ['name'] search_columns = ['name'] class ContactChartView(ChartView): chart_title = 'Grouped contacts' label_columns = ContactGeneralView.label_columns group_by_columns = ['group'] datamodel = SQLAModel(Contact, db.session) class ContactTimeChartView(TimeChartView): chart_title = 'Grouped Birth contacts' label_columns = ContactGeneralView.label_columns group_by_columns = ['birthday'] datamodel = SQLAModel(Contact, db.session) genapp = BaseApp(app, db) genapp.add_view(GroupGeneralView(), "List Groups",icon = "th-large",category = "Contacts") genapp.add_view(ContactGeneralView(), "List Contacts",icon = "earphone",category = "Contacts") genapp.add_separator("Contacts") genapp.add_view(ContactChartView(), "Contacts Chart","/contactchartview/chart","signal","Contacts") genapp.add_view(ContactTimeChartView(), "Contacts Birth Chart","/contacttimechartview/chart/month","signal","Contacts")
('Summary',{'fields':['name','photo','address', 'group']}), ('Personal Info',{'fields':['birthday','personal_phone','personal_celphone','personal_email'],'expanded':False}), ('Professional Info',{'fields':['business_function','business_phone','business_celphone','business_email'],'expanded':False}), ('Extra',{'fields':['notes'],'expanded':False}), ] class GroupGeneralView(GeneralView): datamodel = SQLAModel(Group, db.session) related_views = [PersonGeneralView()] label_columns = { 'phone1':'Phone (1)','phone2':'Phone (2)','taxid':'Tax ID'} list_columns = ['name','notes'] show_columns = ['name','address','phone1','phone2','taxid','notes'] order_columns = ['name','notes'] search_columns = ['name'] class PersonChartView(ChartView): route_base = '/persons' datamodel = SQLAModel(Person, db.session) chart_title = 'Grouped Persons' label_columns = PersonGeneralView.label_columns group_by_columns = ['group'] search_columns = ['name','group'] baseapp = BaseApp(app, db) baseapp.add_view(GroupGeneralView(), "List Groups",icon = "th-large",category = "Contacts") baseapp.add_view(PersonGeneralView(), "List Contacts",icon = "earphone",category = "Contacts") baseapp.add_view(PersonChartView(), "Contacts Chart","/persons/chart","earphone","Contacts")
class GroupGeneralView(GeneralView): route_base = '/groups' datamodel = SQLAModel(Group, db.session) related_views = [PersonGeneralView()] list_title = 'List Groups' show_title = 'Show Group' add_title = 'Add Group' edit_title = 'Edit Group' label_columns = { 'name':'Name','address':'Address','phone1':'Phone (1)','phone2':'Phone (2)','taxid':'Tax ID','notes':'Notes'} list_columns = ['name','notes'] show_columns = ['name','address','phone1','phone2','taxid','notes'] order_columns = ['name','notes'] search_columns = ['name'] class PersonChartView(ChartView): route_base = '/persons' chart_title = 'Grouped Persons' label_columns = PersonGeneralView.label_columns group_by_columns = ['group'] datamodel = SQLAModel(Person, db.session) baseapp = BaseApp(app) baseapp.add_view(GroupGeneralView, "List Groups","/groups/list","th-large","Contacts") baseapp.add_view(PersonGeneralView, "List Contacts","/persons/list","earphone","Contacts") baseapp.add_view(PersonChartView, "Contacts Chart","/persons/chart","earphone","Contacts")