Permalink
Browse files

First commit

  • Loading branch information...
dnouri committed Jan 28, 2011
0 parents commit 9556a3e745ad3614c687312ee67705a94216de06
@@ -0,0 +1,13 @@
Kotti.db
Kotti.egg-info/
bin/
dist/
include/
lib/
*.pyc
*.pt.py
.coverage
mechanize-*
pytz-*
wsgi_intercept-*
zope.testbrowser-*
@@ -0,0 +1,4 @@
0.1
---

- Initial version
@@ -0,0 +1,2 @@
include *.txt *.ini *.cfg *.rst
recursive-include kotti *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml
@@ -0,0 +1,59 @@
=====
Kotti
=====

What is it?
===========

Kotti is a minimal CMS based written in Python and based on the two
most excellent libraries Pyramid_ and SQLAlchemy_. Kotti tries to
leverage these libraries as much as possible, thus:

- minimizing the amount of code written,

- and allowing users familiar with these frameworks to feel right at
home.

Kotti aims to use few abstractions, yet it aims to be somewhat
extensible. You can extend Kotti with new content types and views
from your own Python packages. If all that you want is replace
templates and styles, then it's sufficient to hook up your static
files in the configuration, i.e. without writing a single line of
Python.

At this moment, Kotti is **unstable software**. You're on your own if
you want to use it. We're going to break the API and the SQLAlchemy
model in ways that is likely to break your application when you
upgrade to a newer version of Kotti, and we won't support a migration
path.

CMS Features (at this point mostly goals)
=========================================

- Access control lists for fine-grained security (like Plone_)

- Separation of public skin and editor interface (unlike Plone_)

- Support for instance-level views; documents may have different views
based on context (like Plone_)

- Easily extend with your own look & feel without writing a single
line of Python (unlike Plone_)

- Easily extend with new content types and views

Implementation notes
====================

Take a look at `this blog post`_ for implementation details.

Thanks
======

Kotti is proudly sponsored by the `University of Coimbra`_.

.. _Pyramid: http://docs.pylonsproject.org/projects/pyramid/dev/
.. _SQLAlchemy: http://www.sqlalchemy.org/
.. _Plone: http://plone.org/
.. _this blog post: http://danielnouri.org/notes/2010/01/25/16-hours-into-a-new-cms-with-pyramid/
.. _University of Coimbra: http://uc.pt/
@@ -0,0 +1,65 @@
[app:Kotti]
use = egg:kotti
reload_templates = true
debug_authorization = false
debug_notfound = false
debug_routematch = false
debug_templates = true
default_locale_name = en
sqlalchemy.url = sqlite:///%(here)s/Kotti.db
secret = qwerty
#includeme = kotti.views.view kotti.views.edit

[pipeline:main]
pipeline =
egg:WebError#evalerror
tm
Kotti

[filter:tm]
use = egg:repoze.tm2#tm
commit_veto = repoze.tm:default_commit_veto

[server:main]
use = egg:Paste#http
host = 0.0.0.0
port = 6543

# Begin logging configuration

[loggers]
keys = root, kotti, sqlalchemy

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console

[logger_kotti]
level = DEBUG
handlers =
qualname = kotti

[logger_sqlalchemy]
level = INFO
handlers =
qualname = sqlalchemy.engine
# "level = INFO" logs SQL queries.
# "level = DEBUG" logs SQL queries and results.
# "level = WARN" logs neither. (Recommended for production systems.)

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s

# End logging configuration
@@ -0,0 +1,47 @@
from sqlalchemy import engine_from_config
from pyramid.config import Configurator
#from pyramid.authentication import AuthTktAuthenticationPolicy
#from pyramid.authorization import ACLAuthorizationPolicy

from kotti.resources import appmaker
from kotti.resources import Node

# All of these can be set by passing them in the Paste Deploy settings:
configuration = {
'kotti.templates.snippets': 'kotti:templates/snippets.pt',
'kotti.templates.master_view': 'kotti:templates/master_view.pt',
'kotti.templates.master_edit': 'kotti:templates/master_edit.pt',
'kotti.includes': 'kotti.views.view kotti.views.edit',
}

def main(global_config, **settings):
""" This function returns a WSGI application.
"""
for key in configuration:
if key in settings:
configuration[key] = settings.pop(key)

engine = engine_from_config(settings, 'sqlalchemy.')
get_root = appmaker(engine)

# XXX These two want to be configurable:
# authentication_policy = AuthTktAuthenticationPolicy(settings.pop('secret'))
# authorization_policy = ACLAuthorizationPolicy()

config = Configurator(
settings=settings,
root_factory=get_root,
# authentication_policy=authentication_policy,
# authorization_policy=authorization_policy,
)

config.add_static_view('static-deform', 'deform:static')
config.add_static_view('static-kotti', 'kotti:static')
config.add_view('kotti.views.node_default_view', context=Node)

# Include modules listed in 'includeme' configuration:
modules = [m.strip() for m in configuration['kotti.includes'].split()]
for module in modules:
config.include(module)

return config.make_wsgi_app()
@@ -0,0 +1,43 @@
Kotti browser tests
==================

Setup
-----

>>> from kotti import tests
>>> from kotti.resources import Node, Document, DBSession

>>> tools = tests.setUpFunctional()
>>> browser = tools['Browser']()
>>> browser.open(tests.BASE_URL)
>>> session = DBSession()
>>> root = session.query(Node).get(1)

Create a child object in the DB and access it with the browser
--------------------------------------------------------------

>>> root['child1'] = Document(title=u"Child One")
>>> browser.open(tests.BASE_URL + '/child1')
>>> "Child One" in browser.contents
True

Change the title in the edit screen
-----------------------------------

>>> browser.getLink("Edit").click()
>>> browser.getControl("Title").value = "First Child"
>>> browser.getControl("save").click()
>>> browser.getLink("View").click()
>>> "First Child" in browser.contents
True

And now force a validation error:

>>> browser.getLink("Edit").click()
>>> browser.getControl("Title").value = ""
>>> browser.getControl("save").click()
>>> "There was a problem" in browser.contents
True
>>> browser.getLink("View").click()
>>> "First Child" in browser.contents
True
Oops, something went wrong.

0 comments on commit 9556a3e

Please sign in to comment.