Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
hasankhan committed Jan 23, 2013
1 parent ef82130 commit 8641205
Show file tree
Hide file tree
Showing 82 changed files with 2,090 additions and 37 deletions.
39 changes: 5 additions & 34 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,35 +1,6 @@
*.py[cod]
*.pyc
*.project
*.settings
node_modules
venv*

# C extensions
*.so

# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64

# Installer logs
pip-log.txt

# Unit test / coverage reports
.coverage
.tox
nosetests.xml

# Translations
*.mo

# Mr Developer
.mr.developer.cfg
.project
.pydevproject
23 changes: 20 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
pyMVC
=====
PyMVC Framework
===

A python MVC web application framework written using Flask
PyMVC is a MVC web application framework written in Python using Flask.

Requires
---

- PIP ([Install instructions](http://www.pip-installer.org/en/latest/installing.html))
- VirtualEnv ([Install instructions](http://pypi.python.org/pypi/virtualenv/))


Getting Started
---

1. Install PIP
2. Install VirtualEnv
3. Create a virtual environment using virtualenv and activate it
4. Copy the PyMVC source in your virtual env
5. Install the requirements using <code>pip install -r requirements.pip</code>
6. Run the application with <code>python manage.py runserver</code>
Empty file added application/__init__.py
Empty file.
53 changes: 53 additions & 0 deletions application/config/Settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@

class BaseSettings(object):
ENABLE_ASYNC = True

LOGGING_CONFIG = {
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'short',
'level': 'DEBUG'
}
},
'formatters': {
'short': {
'format': '%(levelname)s: %(message)s'
},
'full': {
'format': '%(levelname)s|%(asctime)s|%(pathname)s:%(lineno)s|%(message)s'
}
},
'loggers': {
'development': {
'handlers': ['console'],
'level': 'DEBUG'
},
'staging': {
'handlers': ['console'],
'level': 'DEBUG'
},
'production': {
'handlers': ['console'],
'level': 'DEBUG'
},
},
'version': 1
}

class DevelopmentSettings(BaseSettings):
ENVIRONMENT = 'development'
DEVELOPMENT = True
ENABLE_ASYNC = True

class StagingSettings(BaseSettings):
ENVIRONMENT = 'staging'
STAGING = True

class ProductionSettings(BaseSettings):
ENVIRONMENT = 'production'
PRODUCTION = True

settings = {'development': DevelopmentSettings(),
'staging': StagingSettings(),
'production': ProductionSettings()}
Empty file added application/config/__init__.py
Empty file.
7 changes: 7 additions & 0 deletions application/config/asset_bundles.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# desktop specific javascript
js_login:
filters: jsmin
output: compiled/login.%(version)s.js
contents:
- scripts/libs/less-min.js
- scripts/libs/require-min.js
13 changes: 13 additions & 0 deletions application/config/development.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# -*- mode: conf -*-

APP_HOST = 'localhost:5000'

# Storage setup
SQLALCHEMY_DATABASE_URI = 'mysql://root:test@localhost/pyMVC'
SQLALCHEMY_POOL_RECYCLE = 60
SQLALCHEMY_ECHO = False

# StatsD
STATSD_HOST = 'localhost'
STATSD_PORT = 8125
STATSD_PREFIX = 'application'
13 changes: 13 additions & 0 deletions application/config/production.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# -*- mode: conf -*-

APP_HOST = 'localhost:5000'

# Storage setup
SQLALCHEMY_DATABASE_URI = 'mysql://root:test@localhost/pyMVC'
SQLALCHEMY_POOL_RECYCLE = 60
SQLALCHEMY_ECHO = False

# StatsD
STATSD_HOST = 'localhost'
STATSD_PORT = 8125
STATSD_PREFIX = 'application'
13 changes: 13 additions & 0 deletions application/config/staging.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# -*- mode: conf -*-

APP_HOST = 'localhost:5000'

# Storage setup
SQLALCHEMY_DATABASE_URI = 'mysql://root:test@localhost/pyMVC'
SQLALCHEMY_POOL_RECYCLE = 60
SQLALCHEMY_ECHO = False

# StatsD
STATSD_HOST = 'localhost'
STATSD_PORT = 8125
STATSD_PREFIX = 'application'
38 changes: 38 additions & 0 deletions application/controllers/AccountController.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from flask import request, flash, redirect, url_for, jsonify
from core.Controller import Controller
from models.account.RegisterModel import RegisterModel
from services.UserService import UserService, DuplicateUserException
from services.entities.User import User

class AccountController(Controller):

def __init__(self, action_name, user_service = None):
super(AccountController, self).__init__(action_name)
self.__user_service = user_service or UserService()

def register(self):
model = RegisterModel(request.form, csrf_context=self._session)
return self._view(model=model)

def register_post(self):
model = RegisterModel(request.form, csrf_context=self._session)
if model.validate():
user = User()
user.username = model.username.data
user.email = model.email.data
user.ignite_id = 'blah'

try:
self.__user_service.create_user(user)
self._session['username'] = model.username.data
flash('You were successfully registered in')
return redirect(url_for('index'))
except DuplicateUserException:
model.username.errors.append('user already exists')

return self._view('register.html', model=model)

def user_exists(self):
username = request.args.get('username', '')
exists = self.__user_service.get_user(username = username) is not None
return jsonify(result = exists)
16 changes: 16 additions & 0 deletions application/controllers/AdminController.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from flask.ext.admin import AdminIndexView, BaseView, expose
from flask.ext.login import current_user

class ProtectedView(object):
def is_accessible(self):
return current_user.is_authenticated() and current_user.is_admin

class HomeView(ProtectedView, AdminIndexView):
@expose()
def index(self):
return self.render('admin/index.html')

class SampleView(ProtectedView, BaseView):
@expose('/')
def index(self):
return self.render('admin/sample.html')
35 changes: 35 additions & 0 deletions application/controllers/AuthController.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from flask import request, redirect, url_for, jsonify
from core.Controller import Controller
from models.account.LoginModel import LoginModel
from services.UserService import UserService
from flask.ext.login import login_user, logout_user

class AuthController(Controller):
def __init__(self, action_name, user_service = None):
super(AuthController, self).__init__(action_name)
self.__user_service = user_service or UserService()

def login(self):
model = LoginModel(request.form, csrf_context=self._session)
next = request.args.get('next', url_for('index'))
return self._view(model=model, next = next)

def login_post(self):
model = LoginModel(request.form, csrf_context=self._session)
next = request.args.get('next', url_for('index'))
if model.validate():
user = self.__user_service.get_user(username = model.username.data)
if user is None:
model.username.errors.append('invalid username')
else:
login_user(user, model.remember_me.data)
return redirect(next)
return self._view('login.html', model=model, next = next)

def user(self):
result = {'DisplayName': self._user.DisplayName if hasattr(self._user, 'DisplayName') else None}
return jsonify(result)

def logout(self):
logout_user()
return redirect (url_for('index'), 302)
20 changes: 20 additions & 0 deletions application/controllers/HomeController.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from core.Controller import Controller
from flask.ext.login import login_required

class HomeController(Controller):

def index(self):
self._logger.debug('home page served')
name = getattr(self._user, 'username', 'unknown')
message = u'Welcome %(name)s' % {'name': name}
self._app.stats.increment('index')

return self._view(message = message)

@login_required
def client(self, **args):
import datetime

now = datetime.datetime.now()
self._logger.debug('going to client page')
return self._view(now=str(now))
Empty file.
11 changes: 11 additions & 0 deletions application/core/Cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from flask import current_app

class Cache(object):
def __init__(self, app = None):
self.__app = app or current_app

def get(self, key):
return self.__app.cache.get(key)

def set(self, key, value, expire = None):
self.__app.cache.set(key, value, expire)
49 changes: 49 additions & 0 deletions application/core/Controller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from flask import current_app as app, session, request, render_template
from flask.views import View
from flask.ext.login import current_user

from core.ViewLocator import ViewLocator
from core.Cache import Cache

import logging
import inspect
import re

class Controller(View):
__mobileAgentPattern = re.compile('iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm');

def __init__(self, action_name):
super(Controller, self).__init__()

self.__action_name = action_name
self._app = app
self._session = session
self._logger = logging.getLogger(app.config['ENVIRONMENT'])
self._cache = Cache()
self._user = current_user

def dispatch_request(self, *args, **kwargs):
action = getattr(self, self.__action_name, None)
if action is None:
raise Exception('action_name', 'Action {0} not found'.format(self.__action_name))
return action(*args, **kwargs)

def _is_mobile(self):
is_mobile = Controller.__mobileAgentPattern.search(request.user_agent.string.lower()) is not None;
return is_mobile;

def resolve_device_name(self):
if self._is_mobile():
return 'mobile'
return '';

def _view(self, view_name = None, **kwargs):
if view_name is None:
view_name = inspect.stack()[1][3];

view_path = ViewLocator.resolve_view_name(self, view_name)

if 'app' not in kwargs:
kwargs['app'] = self._app

return render_template(view_path, **kwargs)
3 changes: 3 additions & 0 deletions application/core/Routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

def add_route(app, routeName, pattern, controller, action, **kwargs):
app.add_url_rule(pattern, view_func=controller.as_view(routeName, action), **kwargs)
6 changes: 6 additions & 0 deletions application/core/SecureForm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from wtforms.ext.csrf.session import SessionSecureForm
from datetime import timedelta

class SecureForm(SessionSecureForm):
SECRET_KEY = 'Enj09jpkj8Gx1SjnyLxwBBSQfnQ9DJYe0Ym'
TIME_LIMIT = timedelta(minutes=20)
Loading

0 comments on commit 8641205

Please sign in to comment.