From: Adrian Schröter
---
src/README.devel | 105 ++
src/TODO | 102 ++
src/api/README | 153 ++
src/api/README_LOGIN | 119 ++
src/api/Rakefile | 10 +
src/api/app/controllers/about_controller.rb | 7 +
src/api/app/controllers/admin_controller.rb | 29 +
src/api/app/controllers/apidocs_controller.rb | 29 +
src/api/app/controllers/application.rb | 143 ++
src/api/app/controllers/main_controller.rb | 5 +
src/api/app/controllers/person_controller.rb | 99 ++
src/api/app/controllers/platform_controller.rb | 60 +
src/api/app/controllers/result_controller.rb | 107 ++
src/api/app/controllers/rpm_controller.rb | 28 +
src/api/app/controllers/source_controller.rb | 188 ++
src/api/app/helpers/about_helper.rb | 2 +
src/api/app/helpers/admin_helper.rb | 2 +
src/api/app/helpers/apidocs_helper.rb | 2 +
src/api/app/helpers/application_helper.rb | 4 +
src/api/app/helpers/main_helper.rb | 2 +
src/api/app/helpers/person_helper.rb | 2 +
src/api/app/helpers/platform_helper.rb | 2 +
src/api/app/helpers/result_helper.rb | 2 +
src/api/app/helpers/rpm_helper.rb | 2 +
src/api/app/helpers/source_helper.rb | 2 +
src/api/app/models/watched_project.rb | 3 +
src/api/app/views/about/index.rxml | 6 +
src/api/app/views/admin/index.rhtml | 11 +
src/api/app/views/admin/list_sources.rhtml | 5 +
src/api/app/views/admin/say_hello.rhtml | 1 +
src/api/app/views/error.rxml | 16 +
src/api/app/views/layouts/html.rhtml | 36 +
src/api/app/views/main/index.rhtml | 19 +
src/api/app/views/person/userinfo.rxml | 23 +
src/api/app/views/result/packageresult.rxml | 16 +
src/api/app/views/result/projectresult.rxml | 18 +
src/api/app/views/source/_meta.rhtml | 10 +
src/api/app/views/source/package_meta.rxml | 10 +
src/api/components/active_rbac/CHANGELOG | 27 +
.../components/active_rbac/component_controller.rb | 24 +
src/api/components/active_rbac/configuration.rb | 57 +
src/api/components/active_rbac/db/create.mssql.sql | 374 ++++
src/api/components/active_rbac/db/create.mysql.sql | 130 ++
.../active_rbac/db/create.postgresql.sql | 147 ++
src/api/components/active_rbac/exceptions.rb | 15 +
src/api/components/active_rbac/group.rb | 135 ++
src/api/components/active_rbac/group/_form.rhtml | 44 +
src/api/components/active_rbac/group/delete.rhtml | 13 +
src/api/components/active_rbac/group/edit.rhtml | 9 +
src/api/components/active_rbac/group/list.rhtml | 23 +
src/api/components/active_rbac/group/new.rhtml | 8 +
src/api/components/active_rbac/group/show.rhtml | 71 +
src/api/components/active_rbac/group_controller.rb | 150 ++
.../components/active_rbac/helpers/rbac_helper.rb | 104 ++
.../components/active_rbac/layouts/_password.rhtml | 17 +
.../components/active_rbac/layouts/confirm.rhtml | 10 +
.../active_rbac/layouts/confirm_failure.rhtml | 5 +
.../active_rbac/layouts/confirm_success.rhtml | 6 +
.../active_rbac/layouts/lostpassword.rhtml | 38 +
.../active_rbac/layouts/lostpassword_success.rhtml | 7 +
.../components/active_rbac/layouts/register.rhtml | 28 +
.../active_rbac/layouts/register_success.rhtml | 10 +
.../active_rbac/login/already_logged_in.rhtml | 7 +
src/api/components/active_rbac/login/login.rhtml | 27 +
.../active_rbac/login/login_success.rhtml | 5 +
src/api/components/active_rbac/login/logout.rhtml | 6 +
.../active_rbac/login/logout_success.rhtml | 5 +
src/api/components/active_rbac/login_controller.rb | 89 +
.../active_rbac/registration/_password.rhtml | 17 +
.../active_rbac/registration/confirm.rhtml | 10 +
.../active_rbac/registration/confirm_failure.rhtml | 5 +
.../active_rbac/registration/confirm_success.rhtml | 6 +
.../active_rbac/registration/lostpassword.rhtml | 38 +
.../registration/lostpassword_success.rhtml | 7 +
.../active_rbac/registration/register.rhtml | 28 +
.../registration/register_success.rhtml | 10 +
.../active_rbac/registration_controller.rb | 126 ++
.../components/active_rbac/registration_mailer.rb | 65 +
.../registration_mailer/confirm_registration.rhtml | 6 +
.../registration_mailer/lost_password.rhtml | 13 +
src/api/components/active_rbac/role.rb | 141 ++
src/api/components/active_rbac/role/_form.rhtml | 57 +
src/api/components/active_rbac/role/delete.rhtml | 12 +
src/api/components/active_rbac/role/edit.rhtml | 9 +
src/api/components/active_rbac/role/list.rhtml | 22 +
src/api/components/active_rbac/role/new.rhtml | 8 +
src/api/components/active_rbac/role/show.rhtml | 110 ++
src/api/components/active_rbac/role_controller.rb | 152 ++
.../active_rbac/shared/_pagination.rhtml | 19 +
.../components/active_rbac/static_permission.rb | 34 +
.../active_rbac/static_permission/_form.rhtml | 10 +
.../active_rbac/static_permission/delete.rhtml | 13 +
.../active_rbac/static_permission/edit.rhtml | 9 +
.../active_rbac/static_permission/list.rhtml | 30 +
.../active_rbac/static_permission/new.rhtml | 8 +
.../active_rbac/static_permission/show.rhtml | 43 +
.../active_rbac/static_permission_controller.rb | 128 ++
.../active_rbac/test/fixtures/groups.yml | 80 +
.../active_rbac/test/fixtures/groups_roles.yml | 23 +
.../active_rbac/test/fixtures/groups_users.yml | 29 +
.../registration_mailer/confirm_registration | 6 +
.../fixtures/registration_mailer/lost_password | 13 +
.../components/active_rbac/test/fixtures/roles.yml | 56 +
.../test/fixtures/roles_static_permissions.yml | 14 +
.../active_rbac/test/fixtures/roles_users.yml | 11 +
.../test/fixtures/static_permissions.yml | 17 +
.../test/fixtures/user_registrations.yml | 18 +
.../components/active_rbac/test/fixtures/users.yml | 199 +++
.../test/functional/group_controller_test.rb | 263 +++
.../test/functional/login_controller_test.rb | 149 ++
.../functional/registration_controller_test.rb | 396 +++++
.../test/functional/role_controller_test.rb | 262 +++
.../static_permission_controller_test.rb | 95 ++
.../test/functional/user_controller_test.rb | 445 +++++
src/api/components/active_rbac/test/test_helper.rb | 26 +
.../components/active_rbac/test/unit/group_test.rb | 535 ++++++
.../test/unit/registration_mailer_test.rb | 61 +
.../components/active_rbac/test/unit/role_test.rb | 351 ++++
.../test/unit/static_permission_test.rb | 535 ++++++
.../test/unit/user_registration_test.rb | 47 +
.../components/active_rbac/test/unit/user_test.rb | 821 +++++++++
src/api/components/active_rbac/user.rb | 409 +++++
src/api/components/active_rbac/user/_form.rhtml | 53 +
.../components/active_rbac/user/_password.rhtml | 19 +
src/api/components/active_rbac/user/delete.rhtml | 13 +
src/api/components/active_rbac/user/edit.rhtml | 10 +
src/api/components/active_rbac/user/list.rhtml | 49 +
src/api/components/active_rbac/user/new.rhtml | 9 +
src/api/components/active_rbac/user/show.rhtml | 75 +
src/api/components/active_rbac/user_controller.rb | 163 ++
.../components/active_rbac/user_registration.rb | 32 +
src/api/config/active_rbac_config.rb | 3 +
src/api/config/boot.rb | 19 +
src/api/config/database.yml | 88 +
src/api/config/deploy.rb | 103 ++
src/api/config/environment.rb | 61 +
src/api/config/environments/development.rb | 38 +
src/api/config/environments/production.rb | 28 +
src/api/config/environments/test.rb | 29 +
src/api/config/routes.rb | 89 +
src/api/db/create_mysql.sql | 215 +++
src/api/doc/README_FOR_APP | 2 +
src/api/files/specfiletemplate | 26 +
src/api/lib/login_system.rb | 88 +
src/api/lib/opensuse/backend.rb | 300 ++++
src/api/lib/opensuse/permission.rb | 108 ++
src/api/lib/opensuse/validator.rb | 141 ++
src/api/lib/tasks/switchtower.rake | 48 +
src/api/public/.htaccess | 40 +
src/api/public/404.html | 8 +
src/api/public/500.html | 8 +
src/api/public/dispatch.cgi | 10 +
src/api/public/dispatch.fcgi | 24 +
src/api/public/dispatch.rb | 10 +
src/api/public/images/opensuse.gif | Bin 0 -> 1474 bytes
src/api/public/images/rails.png | Bin 0 -> 1787 bytes
src/api/public/javascripts/controls.js | 750 ++++++++
src/api/public/javascripts/dragdrop.js | 539 ++++++
src/api/public/javascripts/effects.js | 904 ++++++++++
src/api/public/javascripts/prototype.js | 1768 +++++++++++++++++++
src/api/public/robots.txt | 1 +
src/api/public/stylesheets/opensuse.css | 69 +
src/api/script/about | 3 +
src/api/script/breakpointer | 3 +
src/api/script/console | 3 +
src/api/script/destroy | 3 +
src/api/script/generate | 3 +
src/api/script/performance/benchmarker | 3 +
src/api/script/performance/profiler | 3 +
src/api/script/plugin | 3 +
src/api/script/process/reaper | 3 +
src/api/script/process/spawner | 3 +
src/api/script/process/spinner | 3 +
src/api/script/runner | 3 +
src/api/script/server | 5 +
src/api/test/fixtures/roles.yml | 6 +
src/api/test/fixtures/roles_static_permissions.yml | 19 +
src/api/test/fixtures/roles_users.yml | 5 +
src/api/test/fixtures/static_permissions.yml | 23 +
src/api/test/fixtures/users.yml | 39 +
src/api/test/fixtures/watched_projects.yml | 9 +
src/api/test/functional/about_controller_test.rb | 15 +
src/api/test/functional/admin_controller_test.rb | 15 +
src/api/test/functional/apidocs_controller_test.rb | 15 +
src/api/test/functional/main_controller_test.rb | 15 +
src/api/test/functional/person_controller_test.rb | 72 +
.../test/functional/platform_controller_test.rb | 33 +
src/api/test/functional/result_controller_test.rb | 15 +
src/api/test/functional/rpm_controller_test.rb | 15 +
src/api/test/functional/source_controller_test.rb | 436 +++++
src/api/test/test_helper.rb | 66 +
src/api/test/unit/watched_project_test.rb | 11 +
src/api/vendor/plugins/railfix/init.rb | 34 +
src/backend-dummy/README | 153 ++
src/backend-dummy/Rakefile | 10 +
.../app/controllers/admin_controller.rb | 27 +
src/backend-dummy/app/controllers/application.rb | 25 +
.../app/controllers/platform_controller.rb | 47 +
.../app/controllers/result_controller.rb | 58 +
.../app/controllers/rpm_controller.rb | 29 +
.../app/controllers/source_controller.rb | 101 ++
src/backend-dummy/app/helpers/admin_helper.rb | 2 +
.../app/helpers/application_helper.rb | 3 +
src/backend-dummy/app/helpers/platform_helper.rb | 2 +
src/backend-dummy/app/helpers/result_helper.rb | 2 +
src/backend-dummy/app/helpers/rpm_helper.rb | 2 +
src/backend-dummy/app/helpers/source_helper.rb | 2 +
src/backend-dummy/app/views/admin/index.rhtml | 3 +
.../app/views/admin/list_sources.rhtml | 5 +
src/backend-dummy/app/views/admin/say_hello.rhtml | 1 +
src/backend-dummy/app/views/error.rxml | 16 +
src/backend-dummy/app/views/layouts/admin.rhtml | 10 +
src/backend-dummy/app/views/platform/index.rxml | 5 +
src/backend-dummy/app/views/source/_meta.rhtml | 10 +
src/backend-dummy/app/views/source/index.rxml | 5 +
src/backend-dummy/config/boot.rb | 19 +
src/backend-dummy/config/database.yml | 85 +
src/backend-dummy/config/deploy.rb | 69 +
src/backend-dummy/config/environment.rb | 55 +
.../config/environments/development.rb | 21 +
.../config/environments/production.rb | 21 +
src/backend-dummy/config/environments/test.rb | 21 +
src/backend-dummy/config/routes.rb | 50 +
.../data_test/platform/SUSE-10.0/superkde | 37 +
.../data_test/platform/SUSE-10.0/suselinux-10.0 | 37 +
.../data_test/platform/SUSE10.1/Debian-Etch | 37 +
.../data_test/platform/SUSE10.1/superkde | 37 +
.../data_test/platform/SUSE10.1/suselinux-10.0 | 37 +
src/backend-dummy/data_test/source/kde4/_meta | 21 +
.../data_test/source/kde4/kdebase/_meta | 5 +
.../data_test/source/kde4/kdelibs/_meta | 24 +
.../data_test/source/kde4/kdelibs/kdelibs.tar.gz | 1 +
.../source/kde4/kdelibs/make_it_cool.patch | 1 +
.../data_test/source/kde4/kdelibs/my_patch.diff | 1 +
src/backend-dummy/doc/README_FOR_APP | 2 +
src/backend-dummy/lib/dummy_builder.rb | 163 ++
src/backend-dummy/lib/tasks/switchtower.rake | 48 +
src/backend-dummy/public/.htaccess | 40 +
src/backend-dummy/public/404.html | 8 +
src/backend-dummy/public/500.html | 8 +
src/backend-dummy/public/dispatch.cgi | 10 +
src/backend-dummy/public/dispatch.fcgi | 24 +
src/backend-dummy/public/dispatch.rb | 10 +
src/backend-dummy/public/images/rails.png | Bin 0 -> 1787 bytes
src/backend-dummy/public/index.html | 277 +++
src/backend-dummy/public/javascripts/controls.js | 750 ++++++++
src/backend-dummy/public/javascripts/dragdrop.js | 539 ++++++
src/backend-dummy/public/javascripts/effects.js | 904 ++++++++++
src/backend-dummy/public/javascripts/prototype.js | 1768 +++++++++++++++++++
src/backend-dummy/public/robots.txt | 1 +
src/backend-dummy/script/about | 3 +
src/backend-dummy/script/breakpointer | 3 +
src/backend-dummy/script/console | 3 +
src/backend-dummy/script/destroy | 3 +
src/backend-dummy/script/generate | 3 +
src/backend-dummy/script/performance/benchmarker | 3 +
src/backend-dummy/script/performance/profiler | 3 +
src/backend-dummy/script/plugin | 3 +
src/backend-dummy/script/process/reaper | 3 +
src/backend-dummy/script/process/spawner | 3 +
src/backend-dummy/script/process/spinner | 3 +
src/backend-dummy/script/runner | 3 +
src/backend-dummy/script/server | 5 +
.../test/functional/admin_controller_test.rb | 18 +
.../test/functional/platform_controller_test.rb | 18 +
.../test/functional/result_controller_test.rb | 18 +
.../test/functional/rpm_controller_test.rb | 18 +
.../test/functional/source_controller_test.rb | 18 +
src/backend-dummy/test/test_helper.rb | 28 +
src/debug | 28 +
src/deploy | 7 +
src/start | 38 +
src/start_buildsystem.sh | 31 +
src/webui/README | 153 ++
src/webui/Rakefile | 10 +
src/webui/app/controllers/application.rb | 94 +
src/webui/app/controllers/home_controller.rb | 14 +
src/webui/app/controllers/main_controller.rb | 2 +
src/webui/app/controllers/package_controller.rb | 274 +++
src/webui/app/controllers/platform_controller.rb | 101 ++
src/webui/app/controllers/project_controller.rb | 282 +++
src/webui/app/controllers/user_controller.rb | 80 +
src/webui/app/helpers/application_helper.rb | 9 +
src/webui/app/helpers/home_helper.rb | 2 +
src/webui/app/helpers/main_helper.rb | 2 +
src/webui/app/helpers/package_helper.rb | 13 +
src/webui/app/helpers/platform_helper.rb | 13 +
src/webui/app/helpers/project_helper.rb | 37 +
src/webui/app/helpers/user_helper.rb | 2 +
src/webui/app/models/package.rb | 100 ++
src/webui/app/models/person.rb | 27 +
src/webui/app/models/platform.rb | 12 +
src/webui/app/models/project.rb | 90 +
src/webui/app/models/result.rb | 4 +
src/webui/app/views/error.rhtml | 24 +
src/webui/app/views/home/index.rhtml | 33 +
src/webui/app/views/layouts/application.rhtml | 69 +
src/webui/app/views/main/about.rhtml | 5 +
src/webui/app/views/main/index.rhtml | 20 +
.../app/views/package/_update_build_log.rhtml | 11 +
src/webui/app/views/package/add_file.rhtml | 13 +
src/webui/app/views/package/add_person.rhtml | 10 +
src/webui/app/views/package/edit.rhtml | 12 +
src/webui/app/views/package/edit_spec.rhtml | 9 +
src/webui/app/views/package/live_build_log.rhtml | 33 +
src/webui/app/views/package/new.rhtml | 13 +
src/webui/app/views/package/save.rhtml | 5 +
src/webui/app/views/package/show.rhtml | 100 ++
src/webui/app/views/platform/edit.rhtml | 11 +
src/webui/app/views/platform/list_all.rhtml | 19 +
src/webui/app/views/platform/new.rhtml | 14 +
src/webui/app/views/platform/show.rhtml | 35 +
src/webui/app/views/project/_watch_link.rhtml | 4 +
src/webui/app/views/project/add_person.rhtml | 10 +
src/webui/app/views/project/add_target.rhtml | 14 +
src/webui/app/views/project/edit.rhtml | 10 +
src/webui/app/views/project/list_all.rhtml | 9 +
src/webui/app/views/project/list_my.rhtml | 12 +
src/webui/app/views/project/monitor.rhtml | 50 +
src/webui/app/views/project/new.rhtml | 12 +
src/webui/app/views/project/refresh_monitor.rhtml | 15 +
src/webui/app/views/project/show.rhtml | 124 ++
src/webui/app/views/user/edit.rhtml | 50 +
src/webui/app/views/user/login.rhtml | 23 +
src/webui/app/views/user/logout.rhtml | 10 +
src/webui/app/views/user/newaccount.rhtml | 22 +
src/webui/config/boot.rb | 19 +
src/webui/config/database.yml | 85 +
src/webui/config/deploy.rb | 59 +
src/webui/config/environment.rb | 63 +
src/webui/config/environments/development.rb | 23 +
src/webui/config/environments/production.rb | 24 +
src/webui/config/environments/test.rb | 22 +
src/webui/config/routes.rb | 14 +
src/webui/doc/README_FOR_APP | 2 +
src/webui/lib/tasks/switchtower.rake | 48 +
src/webui/public/.htaccess | 40 +
src/webui/public/404.html | 8 +
src/webui/public/500.html | 8 +
src/webui/public/dispatch.cgi | 10 +
src/webui/public/dispatch.fcgi | 24 +
src/webui/public/dispatch.rb | 10 +
src/webui/public/images/accent.png | Bin 0 -> 3534 bytes
src/webui/public/images/bg-gradient.png | Bin 0 -> 414 bytes
src/webui/public/images/logo-buildservice.png | Bin 0 -> 5156 bytes
src/webui/public/images/opensuse.gif | Bin 0 -> 1474 bytes
src/webui/public/images/rails.png | Bin 0 -> 1787 bytes
src/webui/public/javascripts/controls.js | 750 ++++++++
src/webui/public/javascripts/dragdrop.js | 584 +++++++
src/webui/public/javascripts/effects.js | 854 ++++++++++
src/webui/public/javascripts/prototype.js | 1785 ++++++++++++++++++++
src/webui/public/robots.txt | 1 +
src/webui/public/stylesheets/opensuse.css | 257 +++
src/webui/script/about | 3 +
src/webui/script/breakpointer | 3 +
src/webui/script/console | 3 +
src/webui/script/destroy | 3 +
src/webui/script/generate | 3 +
src/webui/script/performance/benchmarker | 3 +
src/webui/script/performance/profiler | 3 +
src/webui/script/plugin | 3 +
src/webui/script/process/reaper | 3 +
src/webui/script/process/spawner | 3 +
src/webui/script/process/spinner | 3 +
src/webui/script/runner | 3 +
src/webui/script/server | 3 +
src/webui/test/fixtures/platforms.yml | 5 +
src/webui/test/fixtures/users.yml | 5 +
src/webui/test/functional/home_controller_test.rb | 18 +
src/webui/test/functional/main_controller_test.rb | 18 +
.../test/functional/package_controller_test.rb | 20 +
.../test/functional/platform_controller_test.rb | 18 +
.../test/functional/project_controller_test.rb | 51 +
src/webui/test/test_helper.rb | 28 +
src/xml_bindings.txt | 40 +
375 files changed, 28758 insertions(+), 0 deletions(-)
create mode 100644 src/README.devel
create mode 100644 src/TODO
create mode 100644 src/api/README
create mode 100644 src/api/README_LOGIN
create mode 100644 src/api/Rakefile
create mode 100644 src/api/app/controllers/about_controller.rb
create mode 100644 src/api/app/controllers/admin_controller.rb
create mode 100644 src/api/app/controllers/apidocs_controller.rb
create mode 100644 src/api/app/controllers/application.rb
create mode 100644 src/api/app/controllers/main_controller.rb
create mode 100644 src/api/app/controllers/person_controller.rb
create mode 100644 src/api/app/controllers/platform_controller.rb
create mode 100644 src/api/app/controllers/result_controller.rb
create mode 100644 src/api/app/controllers/rpm_controller.rb
create mode 100644 src/api/app/controllers/source_controller.rb
create mode 100644 src/api/app/helpers/about_helper.rb
create mode 100644 src/api/app/helpers/admin_helper.rb
create mode 100644 src/api/app/helpers/apidocs_helper.rb
create mode 100644 src/api/app/helpers/application_helper.rb
create mode 100644 src/api/app/helpers/main_helper.rb
create mode 100644 src/api/app/helpers/person_helper.rb
create mode 100644 src/api/app/helpers/platform_helper.rb
create mode 100644 src/api/app/helpers/result_helper.rb
create mode 100644 src/api/app/helpers/rpm_helper.rb
create mode 100644 src/api/app/helpers/source_helper.rb
create mode 100644 src/api/app/models/watched_project.rb
create mode 100644 src/api/app/views/about/index.rxml
create mode 100644 src/api/app/views/admin/index.rhtml
create mode 100644 src/api/app/views/admin/list_sources.rhtml
create mode 100644 src/api/app/views/admin/say_hello.rhtml
create mode 100644 src/api/app/views/error.rxml
create mode 100644 src/api/app/views/layouts/html.rhtml
create mode 100644 src/api/app/views/main/index.rhtml
create mode 100644 src/api/app/views/person/userinfo.rxml
create mode 100644 src/api/app/views/result/packageresult.rxml
create mode 100644 src/api/app/views/result/projectresult.rxml
create mode 100644 src/api/app/views/source/_meta.rhtml
create mode 100644 src/api/app/views/source/package_meta.rxml
create mode 100644 src/api/components/active_rbac/CHANGELOG
create mode 100644 src/api/components/active_rbac/component_controller.rb
create mode 100644 src/api/components/active_rbac/configuration.rb
create mode 100644 src/api/components/active_rbac/db/create.mssql.sql
create mode 100644 src/api/components/active_rbac/db/create.mysql.sql
create mode 100644 src/api/components/active_rbac/db/create.postgresql.sql
create mode 100644 src/api/components/active_rbac/exceptions.rb
create mode 100644 src/api/components/active_rbac/group.rb
create mode 100644 src/api/components/active_rbac/group/_form.rhtml
create mode 100644 src/api/components/active_rbac/group/delete.rhtml
create mode 100644 src/api/components/active_rbac/group/edit.rhtml
create mode 100644 src/api/components/active_rbac/group/list.rhtml
create mode 100644 src/api/components/active_rbac/group/new.rhtml
create mode 100644 src/api/components/active_rbac/group/show.rhtml
create mode 100644 src/api/components/active_rbac/group_controller.rb
create mode 100644 src/api/components/active_rbac/helpers/rbac_helper.rb
create mode 100644 src/api/components/active_rbac/layouts/_password.rhtml
create mode 100644 src/api/components/active_rbac/layouts/confirm.rhtml
create mode 100644 src/api/components/active_rbac/layouts/confirm_failure.rhtml
create mode 100644 src/api/components/active_rbac/layouts/confirm_success.rhtml
create mode 100644 src/api/components/active_rbac/layouts/lostpassword.rhtml
create mode 100644 src/api/components/active_rbac/layouts/lostpassword_success.rhtml
create mode 100644 src/api/components/active_rbac/layouts/register.rhtml
create mode 100644 src/api/components/active_rbac/layouts/register_success.rhtml
create mode 100644 src/api/components/active_rbac/login/already_logged_in.rhtml
create mode 100644 src/api/components/active_rbac/login/login.rhtml
create mode 100644 src/api/components/active_rbac/login/login_success.rhtml
create mode 100644 src/api/components/active_rbac/login/logout.rhtml
create mode 100644 src/api/components/active_rbac/login/logout_success.rhtml
create mode 100644 src/api/components/active_rbac/login_controller.rb
create mode 100644 src/api/components/active_rbac/registration/_password.rhtml
create mode 100644 src/api/components/active_rbac/registration/confirm.rhtml
create mode 100644 src/api/components/active_rbac/registration/confirm_failure.rhtml
create mode 100644 src/api/components/active_rbac/registration/confirm_success.rhtml
create mode 100644 src/api/components/active_rbac/registration/lostpassword.rhtml
create mode 100644 src/api/components/active_rbac/registration/lostpassword_success.rhtml
create mode 100644 src/api/components/active_rbac/registration/register.rhtml
create mode 100644 src/api/components/active_rbac/registration/register_success.rhtml
create mode 100644 src/api/components/active_rbac/registration_controller.rb
create mode 100644 src/api/components/active_rbac/registration_mailer.rb
create mode 100644 src/api/components/active_rbac/registration_mailer/confirm_registration.rhtml
create mode 100644 src/api/components/active_rbac/registration_mailer/lost_password.rhtml
create mode 100644 src/api/components/active_rbac/role.rb
create mode 100644 src/api/components/active_rbac/role/_form.rhtml
create mode 100644 src/api/components/active_rbac/role/delete.rhtml
create mode 100644 src/api/components/active_rbac/role/edit.rhtml
create mode 100644 src/api/components/active_rbac/role/list.rhtml
create mode 100644 src/api/components/active_rbac/role/new.rhtml
create mode 100644 src/api/components/active_rbac/role/show.rhtml
create mode 100644 src/api/components/active_rbac/role_controller.rb
create mode 100644 src/api/components/active_rbac/shared/_pagination.rhtml
create mode 100644 src/api/components/active_rbac/static_permission.rb
create mode 100644 src/api/components/active_rbac/static_permission/_form.rhtml
create mode 100644 src/api/components/active_rbac/static_permission/delete.rhtml
create mode 100644 src/api/components/active_rbac/static_permission/edit.rhtml
create mode 100644 src/api/components/active_rbac/static_permission/list.rhtml
create mode 100644 src/api/components/active_rbac/static_permission/new.rhtml
create mode 100644 src/api/components/active_rbac/static_permission/show.rhtml
create mode 100644 src/api/components/active_rbac/static_permission_controller.rb
create mode 100644 src/api/components/active_rbac/test/fixtures/groups.yml
create mode 100644 src/api/components/active_rbac/test/fixtures/groups_roles.yml
create mode 100644 src/api/components/active_rbac/test/fixtures/groups_users.yml
create mode 100644 src/api/components/active_rbac/test/fixtures/registration_mailer/confirm_registration
create mode 100644 src/api/components/active_rbac/test/fixtures/registration_mailer/lost_password
create mode 100644 src/api/components/active_rbac/test/fixtures/roles.yml
create mode 100644 src/api/components/active_rbac/test/fixtures/roles_static_permissions.yml
create mode 100644 src/api/components/active_rbac/test/fixtures/roles_users.yml
create mode 100644 src/api/components/active_rbac/test/fixtures/static_permissions.yml
create mode 100644 src/api/components/active_rbac/test/fixtures/user_registrations.yml
create mode 100644 src/api/components/active_rbac/test/fixtures/users.yml
create mode 100644 src/api/components/active_rbac/test/functional/group_controller_test.rb
create mode 100644 src/api/components/active_rbac/test/functional/login_controller_test.rb
create mode 100644 src/api/components/active_rbac/test/functional/registration_controller_test.rb
create mode 100644 src/api/components/active_rbac/test/functional/role_controller_test.rb
create mode 100644 src/api/components/active_rbac/test/functional/static_permission_controller_test.rb
create mode 100644 src/api/components/active_rbac/test/functional/user_controller_test.rb
create mode 100644 src/api/components/active_rbac/test/test_helper.rb
create mode 100644 src/api/components/active_rbac/test/unit/group_test.rb
create mode 100644 src/api/components/active_rbac/test/unit/registration_mailer_test.rb
create mode 100644 src/api/components/active_rbac/test/unit/role_test.rb
create mode 100644 src/api/components/active_rbac/test/unit/static_permission_test.rb
create mode 100644 src/api/components/active_rbac/test/unit/user_registration_test.rb
create mode 100644 src/api/components/active_rbac/test/unit/user_test.rb
create mode 100644 src/api/components/active_rbac/user.rb
create mode 100644 src/api/components/active_rbac/user/_form.rhtml
create mode 100644 src/api/components/active_rbac/user/_password.rhtml
create mode 100644 src/api/components/active_rbac/user/delete.rhtml
create mode 100644 src/api/components/active_rbac/user/edit.rhtml
create mode 100644 src/api/components/active_rbac/user/list.rhtml
create mode 100644 src/api/components/active_rbac/user/new.rhtml
create mode 100644 src/api/components/active_rbac/user/show.rhtml
create mode 100644 src/api/components/active_rbac/user_controller.rb
create mode 100644 src/api/components/active_rbac/user_registration.rb
create mode 100644 src/api/config/active_rbac_config.rb
create mode 100644 src/api/config/boot.rb
create mode 100644 src/api/config/database.yml
create mode 100644 src/api/config/deploy.rb
create mode 100644 src/api/config/environment.rb
create mode 100644 src/api/config/environments/development.rb
create mode 100644 src/api/config/environments/production.rb
create mode 100644 src/api/config/environments/test.rb
create mode 100644 src/api/config/routes.rb
create mode 100644 src/api/db/create_mysql.sql
create mode 100644 src/api/doc/README_FOR_APP
create mode 100644 src/api/files/specfiletemplate
create mode 100644 src/api/lib/login_system.rb
create mode 100644 src/api/lib/opensuse/backend.rb
create mode 100644 src/api/lib/opensuse/permission.rb
create mode 100644 src/api/lib/opensuse/validator.rb
create mode 100644 src/api/lib/tasks/switchtower.rake
create mode 100644 src/api/public/.htaccess
create mode 100644 src/api/public/404.html
create mode 100644 src/api/public/500.html
create mode 100755 src/api/public/dispatch.cgi
create mode 100755 src/api/public/dispatch.fcgi
create mode 100755 src/api/public/dispatch.rb
create mode 100644 src/api/public/favicon.ico
create mode 100644 src/api/public/images/opensuse.gif
create mode 100644 src/api/public/images/rails.png
create mode 100644 src/api/public/javascripts/controls.js
create mode 100644 src/api/public/javascripts/dragdrop.js
create mode 100644 src/api/public/javascripts/effects.js
create mode 100644 src/api/public/javascripts/prototype.js
create mode 100644 src/api/public/robots.txt
create mode 100644 src/api/public/stylesheets/opensuse.css
create mode 100755 src/api/script/about
create mode 100755 src/api/script/breakpointer
create mode 100755 src/api/script/console
create mode 100755 src/api/script/destroy
create mode 100755 src/api/script/generate
create mode 100755 src/api/script/performance/benchmarker
create mode 100755 src/api/script/performance/profiler
create mode 100755 src/api/script/plugin
create mode 100755 src/api/script/process/reaper
create mode 100755 src/api/script/process/spawner
create mode 100755 src/api/script/process/spinner
create mode 100755 src/api/script/runner
create mode 100755 src/api/script/server
create mode 100644 src/api/test/fixtures/roles.yml
create mode 100644 src/api/test/fixtures/roles_static_permissions.yml
create mode 100644 src/api/test/fixtures/roles_users.yml
create mode 100644 src/api/test/fixtures/static_permissions.yml
create mode 100644 src/api/test/fixtures/users.yml
create mode 100644 src/api/test/fixtures/watched_projects.yml
create mode 100644 src/api/test/functional/about_controller_test.rb
create mode 100644 src/api/test/functional/admin_controller_test.rb
create mode 100644 src/api/test/functional/apidocs_controller_test.rb
create mode 100644 src/api/test/functional/main_controller_test.rb
create mode 100644 src/api/test/functional/person_controller_test.rb
create mode 100644 src/api/test/functional/platform_controller_test.rb
create mode 100644 src/api/test/functional/result_controller_test.rb
create mode 100644 src/api/test/functional/rpm_controller_test.rb
create mode 100644 src/api/test/functional/source_controller_test.rb
create mode 100644 src/api/test/test_helper.rb
create mode 100644 src/api/test/unit/watched_project_test.rb
create mode 100644 src/api/vendor/plugins/railfix/init.rb
create mode 100644 src/backend-dummy/README
create mode 100644 src/backend-dummy/Rakefile
create mode 100644 src/backend-dummy/app/controllers/admin_controller.rb
create mode 100644 src/backend-dummy/app/controllers/application.rb
create mode 100644 src/backend-dummy/app/controllers/platform_controller.rb
create mode 100644 src/backend-dummy/app/controllers/result_controller.rb
create mode 100644 src/backend-dummy/app/controllers/rpm_controller.rb
create mode 100644 src/backend-dummy/app/controllers/source_controller.rb
create mode 100644 src/backend-dummy/app/helpers/admin_helper.rb
create mode 100644 src/backend-dummy/app/helpers/application_helper.rb
create mode 100644 src/backend-dummy/app/helpers/platform_helper.rb
create mode 100644 src/backend-dummy/app/helpers/result_helper.rb
create mode 100644 src/backend-dummy/app/helpers/rpm_helper.rb
create mode 100644 src/backend-dummy/app/helpers/source_helper.rb
create mode 100644 src/backend-dummy/app/views/admin/index.rhtml
create mode 100644 src/backend-dummy/app/views/admin/list_sources.rhtml
create mode 100644 src/backend-dummy/app/views/admin/say_hello.rhtml
create mode 100644 src/backend-dummy/app/views/error.rxml
create mode 100644 src/backend-dummy/app/views/layouts/admin.rhtml
create mode 100644 src/backend-dummy/app/views/platform/index.rxml
create mode 100644 src/backend-dummy/app/views/source/_meta.rhtml
create mode 100644 src/backend-dummy/app/views/source/index.rxml
create mode 100644 src/backend-dummy/config/boot.rb
create mode 100644 src/backend-dummy/config/database.yml
create mode 100644 src/backend-dummy/config/deploy.rb
create mode 100644 src/backend-dummy/config/environment.rb
create mode 100644 src/backend-dummy/config/environments/development.rb
create mode 100644 src/backend-dummy/config/environments/production.rb
create mode 100644 src/backend-dummy/config/environments/test.rb
create mode 100644 src/backend-dummy/config/routes.rb
create mode 100644 src/backend-dummy/data_test/platform/SUSE-10.0/superkde
create mode 100644 src/backend-dummy/data_test/platform/SUSE-10.0/suselinux-10.0
create mode 100644 src/backend-dummy/data_test/platform/SUSE10.1/Debian-Etch
create mode 100644 src/backend-dummy/data_test/platform/SUSE10.1/superkde
create mode 100644 src/backend-dummy/data_test/platform/SUSE10.1/suselinux-10.0
create mode 100644 src/backend-dummy/data_test/source/kde4/_meta
create mode 100644 src/backend-dummy/data_test/source/kde4/kdebase/_meta
create mode 100644 src/backend-dummy/data_test/source/kde4/kdelibs/_meta
create mode 100644 src/backend-dummy/data_test/source/kde4/kdelibs/kdelibs.tar.gz
create mode 100644 src/backend-dummy/data_test/source/kde4/kdelibs/make_it_cool.patch
create mode 100644 src/backend-dummy/data_test/source/kde4/kdelibs/my_patch.diff
create mode 100644 src/backend-dummy/db/development_structure.sql
create mode 100644 src/backend-dummy/doc/README_FOR_APP
create mode 100644 src/backend-dummy/lib/dummy_builder.rb
create mode 100644 src/backend-dummy/lib/tasks/switchtower.rake
create mode 100644 src/backend-dummy/public/.htaccess
create mode 100644 src/backend-dummy/public/404.html
create mode 100644 src/backend-dummy/public/500.html
create mode 100755 src/backend-dummy/public/dispatch.cgi
create mode 100755 src/backend-dummy/public/dispatch.fcgi
create mode 100755 src/backend-dummy/public/dispatch.rb
create mode 100644 src/backend-dummy/public/favicon.ico
create mode 100644 src/backend-dummy/public/images/rails.png
create mode 100644 src/backend-dummy/public/index.html
create mode 100644 src/backend-dummy/public/javascripts/controls.js
create mode 100644 src/backend-dummy/public/javascripts/dragdrop.js
create mode 100644 src/backend-dummy/public/javascripts/effects.js
create mode 100644 src/backend-dummy/public/javascripts/prototype.js
create mode 100644 src/backend-dummy/public/robots.txt
create mode 100755 src/backend-dummy/script/about
create mode 100755 src/backend-dummy/script/breakpointer
create mode 100755 src/backend-dummy/script/console
create mode 100755 src/backend-dummy/script/destroy
create mode 100755 src/backend-dummy/script/generate
create mode 100755 src/backend-dummy/script/performance/benchmarker
create mode 100755 src/backend-dummy/script/performance/profiler
create mode 100755 src/backend-dummy/script/plugin
create mode 100755 src/backend-dummy/script/process/reaper
create mode 100755 src/backend-dummy/script/process/spawner
create mode 100755 src/backend-dummy/script/process/spinner
create mode 100755 src/backend-dummy/script/runner
create mode 100755 src/backend-dummy/script/server
create mode 100644 src/backend-dummy/test/functional/admin_controller_test.rb
create mode 100644 src/backend-dummy/test/functional/platform_controller_test.rb
create mode 100644 src/backend-dummy/test/functional/result_controller_test.rb
create mode 100644 src/backend-dummy/test/functional/rpm_controller_test.rb
create mode 100644 src/backend-dummy/test/functional/source_controller_test.rb
create mode 100644 src/backend-dummy/test/test_helper.rb
create mode 100755 src/debug
create mode 100755 src/deploy
create mode 100755 src/start
create mode 100755 src/start_buildsystem.sh
create mode 100644 src/webui/README
create mode 100644 src/webui/Rakefile
create mode 100644 src/webui/app/controllers/application.rb
create mode 100644 src/webui/app/controllers/home_controller.rb
create mode 100644 src/webui/app/controllers/main_controller.rb
create mode 100644 src/webui/app/controllers/package_controller.rb
create mode 100644 src/webui/app/controllers/platform_controller.rb
create mode 100644 src/webui/app/controllers/project_controller.rb
create mode 100644 src/webui/app/controllers/user_controller.rb
create mode 100644 src/webui/app/helpers/application_helper.rb
create mode 100644 src/webui/app/helpers/home_helper.rb
create mode 100644 src/webui/app/helpers/main_helper.rb
create mode 100644 src/webui/app/helpers/package_helper.rb
create mode 100644 src/webui/app/helpers/platform_helper.rb
create mode 100644 src/webui/app/helpers/project_helper.rb
create mode 100644 src/webui/app/helpers/user_helper.rb
create mode 100644 src/webui/app/models/package.rb
create mode 100644 src/webui/app/models/person.rb
create mode 100644 src/webui/app/models/platform.rb
create mode 100644 src/webui/app/models/project.rb
create mode 100644 src/webui/app/models/result.rb
create mode 100644 src/webui/app/views/error.rhtml
create mode 100644 src/webui/app/views/home/index.rhtml
create mode 100644 src/webui/app/views/layouts/application.rhtml
create mode 100644 src/webui/app/views/main/about.rhtml
create mode 100644 src/webui/app/views/main/index.rhtml
create mode 100644 src/webui/app/views/package/_update_build_log.rhtml
create mode 100644 src/webui/app/views/package/add_file.rhtml
create mode 100644 src/webui/app/views/package/add_person.rhtml
create mode 100644 src/webui/app/views/package/edit.rhtml
create mode 100644 src/webui/app/views/package/edit_spec.rhtml
create mode 100644 src/webui/app/views/package/live_build_log.rhtml
create mode 100644 src/webui/app/views/package/new.rhtml
create mode 100644 src/webui/app/views/package/save.rhtml
create mode 100644 src/webui/app/views/package/show.rhtml
create mode 100644 src/webui/app/views/platform/edit.rhtml
create mode 100644 src/webui/app/views/platform/list_all.rhtml
create mode 100644 src/webui/app/views/platform/new.rhtml
create mode 100644 src/webui/app/views/platform/show.rhtml
create mode 100644 src/webui/app/views/project/_watch_link.rhtml
create mode 100644 src/webui/app/views/project/add_person.rhtml
create mode 100644 src/webui/app/views/project/add_target.rhtml
create mode 100644 src/webui/app/views/project/edit.rhtml
create mode 100644 src/webui/app/views/project/list_all.rhtml
create mode 100644 src/webui/app/views/project/list_my.rhtml
create mode 100644 src/webui/app/views/project/monitor.rhtml
create mode 100644 src/webui/app/views/project/new.rhtml
create mode 100644 src/webui/app/views/project/refresh_monitor.rhtml
create mode 100644 src/webui/app/views/project/show.rhtml
create mode 100644 src/webui/app/views/user/edit.rhtml
create mode 100644 src/webui/app/views/user/login.rhtml
create mode 100644 src/webui/app/views/user/logout.rhtml
create mode 100644 src/webui/app/views/user/newaccount.rhtml
create mode 100644 src/webui/config/boot.rb
create mode 100644 src/webui/config/database.yml
create mode 100644 src/webui/config/deploy.rb
create mode 100644 src/webui/config/environment.rb
create mode 100644 src/webui/config/environments/development.rb
create mode 100644 src/webui/config/environments/production.rb
create mode 100644 src/webui/config/environments/test.rb
create mode 100644 src/webui/config/routes.rb
create mode 100644 src/webui/doc/README_FOR_APP
create mode 100644 src/webui/lib/tasks/switchtower.rake
create mode 100644 src/webui/public/.htaccess
create mode 100644 src/webui/public/404.html
create mode 100644 src/webui/public/500.html
create mode 100755 src/webui/public/dispatch.cgi
create mode 100755 src/webui/public/dispatch.fcgi
create mode 100755 src/webui/public/dispatch.rb
create mode 100644 src/webui/public/favicon.ico
create mode 100644 src/webui/public/images/accent.png
create mode 100644 src/webui/public/images/bg-gradient.png
create mode 100644 src/webui/public/images/logo-buildservice.png
create mode 100644 src/webui/public/images/opensuse.gif
create mode 100644 src/webui/public/images/rails.png
create mode 100644 src/webui/public/javascripts/controls.js
create mode 100644 src/webui/public/javascripts/dragdrop.js
create mode 100644 src/webui/public/javascripts/effects.js
create mode 100644 src/webui/public/javascripts/prototype.js
create mode 100644 src/webui/public/robots.txt
create mode 100644 src/webui/public/stylesheets/opensuse.css
create mode 100755 src/webui/script/about
create mode 100755 src/webui/script/breakpointer
create mode 100755 src/webui/script/console
create mode 100755 src/webui/script/destroy
create mode 100755 src/webui/script/generate
create mode 100755 src/webui/script/performance/benchmarker
create mode 100755 src/webui/script/performance/profiler
create mode 100755 src/webui/script/plugin
create mode 100755 src/webui/script/process/reaper
create mode 100755 src/webui/script/process/spawner
create mode 100755 src/webui/script/process/spinner
create mode 100755 src/webui/script/runner
create mode 100755 src/webui/script/server
create mode 100644 src/webui/test/fixtures/platforms.yml
create mode 100644 src/webui/test/fixtures/users.yml
create mode 100644 src/webui/test/functional/home_controller_test.rb
create mode 100644 src/webui/test/functional/main_controller_test.rb
create mode 100644 src/webui/test/functional/package_controller_test.rb
create mode 100644 src/webui/test/functional/platform_controller_test.rb
create mode 100644 src/webui/test/functional/project_controller_test.rb
create mode 100644 src/webui/test/test_helper.rb
create mode 100644 src/xml_bindings.txt
diff --git a/src/README.devel b/src/README.devel
new file mode 100644
index 0000000..5f58e8c
--- /dev/null
+++ b/src/README.devel
@@ -0,0 +1,105 @@
+
+
+ Setting up a development environment
+--------------------------------
+To install ruby-on-rails, please install the rubygems package and
+run: "gem install -y rails" to install the rails libs on your system.
+
+The frontend uses a MySQl backend. Please add the database
+"frontend_development" with the scheme from frontend/config/db/create_mysql.sql
+The database credentials can be set in frontend/config/database.yml
+To run the frontends test framework, please add an empty database "frontend_test".
+
+There are 2 scripts in trunk/buildservice/src named 'start' and
+'debug'. They need one parameter, which is one of (back|back_test|front|web).
+'start' starts a WEBrick server, 'debug' starts the debugger
+for the selected buildservice component. The scripts are there so
+the lazy developers don't have to remember the correct ports for
+server and debugger.
+
+
+ Generating the frontends API documentation
+--------------------
+To generate the docu you need the ruby builder lib.
+It can be installed with: "gem install builder"
+The docu then can be generated with the command:
+ docs/architecture/rest_doc --html api.txt
+
+
+
+ Using the debugger
+--------------------
+
+The debugger waits for connections from the corresponding application.
+Such a connection is established as soon as the method 'breakpoint' is
+called from within the application. The breakpoint method suspends
+application flow and transfers control to the debugger, which opens
+an irb shell in the context of the breakpoint call. For more information
+on the debugger, see
+
+http://api.rubyonrails.com/classes/Breakpoint.html#M000833
+
+
+
+ Deployment
+------------
+
+Deploy locations:
+
+- backend
+
+
+- backend-dummy
+
+ server: buildservice.suse.de
+ path: /srv/www/opensuse/backend-dummy/
+
+
+- frontend
+
+ server: buildservice.suse.de (internal), api.opensuse.org (external)
+ path: /srv/www/opensuse/frontend/
+
+
+- webclient
+
+ server: buildservice.suse.de (internal), build.opensuse.org (external)
+ path: /srv/www/opensuse/webclient/
+
+
+
+Prerequisites:
+
+Your public RSA key has to be in the authorized_keys file of user opensuse on
+all servers (currently only api.opensuse.org).
+
+The buildservice uses Switchtower (http://manuals.rubyonrails.com/read/book/17)
+for deployment. Before using the deploy scripts, the switchtower gem has to be
+installed:
+
+%> gem install switchtower
+
+
+
+Preparing a server for the first deploy:
+
+In the four directories trunk/buildservice/srv/(backend-dummy|frontend|webclient|current), call:
+
+%> rake remote_exec ACTION=setup
+
+
+
+Deploying:
+
+If the frontend database schema has not changed since the last
+deploy, just execute the 'deploy' script in trunk/buildservice/src.
+
+If the database schema has changed, use ./deploy as usual. After that, ssh to
+buildserviceapi.suse.de and change the database. The schema is in the directory
+/srv/www/opensuse/frontend/current/db.
+
+After the database is updated, restart the FastCGI processes:
+
+%> cd /srv/www/opensuse/frontend/current
+%> script/process/reaper -d /srv/www/opensuse/frontend/current/public/dispatch.fcgi
+
diff --git a/src/TODO b/src/TODO
new file mode 100644
index 0000000..804f7ba
--- /dev/null
+++ b/src/TODO
@@ -0,0 +1,102 @@
+openSUSE Build Service Todo List
+================================
+
++: High priority
+o: Medium priority
+-: Low priority
+
+Web Client
+----------
+
++ Tests (tom)
++ Hide "new project" action for non-admin users
++ Don't show links to RPMs, if there are no RPMs built yet
++ Properly show build results (abauer)
++ Visual design (garrett)
++ Switch to migrations for database updates
++ Reenable platform editing
+o Split packages in project display page to multiple pages
+o Show projects of user and his role in the projects on user's hp
+o Move user management for project/package/platform to partial (or component?)
+o Editing project targets list
+o Merge add_package and edit_package?
+o Show build status per target
+o Prevent new project names with spaces
+o Handle error when backend can't be reached.
+o Show titles in platform/projects lists.
+o Show global news
+o Show project news
+- Editor spec file
+- Edit persons for platforms
+
+Command Line Client
+-------------------
+
++ checkin, checkout (cwh)
++ show build status (cwh)
+o local build
+
+Frontend
+--------
+
++ Tests (tom)
++ Check permissions (freitag)
++ Adapt result handling to backend (cschum)
++ Tool to check API against specification (cschum)
++ Prevent project, package and platform names containing spaces, slashes or
+ colons
++ Escaping of paths
++ Caching of backend data (freitag)
+ + Query for projects per user
++ Fix error which makes frontend hang
++ Write useful logs
+ + apache-logs for every access (including user) (abauer)
++ Make sure that the API version is only defined at one place.
++ Store additional information for platforms
++ Get file list from directory listing
+o Notification system
+o Get permissions for a given user
+o RSS feed for project news (newly built packages)
+o Global RSS feed for all project news
+- Load balancing for rpm downloads
+- Admin interface for rpm load balancing
+- New user invitation system
+
+Dummy Backend
+-------------
+
+
+Schemas
+-------
+
+o Make types more specific (e.g. dates)
+o Add documentation for attributes
+o Add lists of possible values for build result error codes
+o Add lists of possible values for build result status codes
+
+
+Big Features
+------------
+
++ Building additional packages for existing platforms
+o Transfer changes and packages between projects
+o Trust system
+o Platform creation
+o Link sources
+o Add patches to linked sources
+
+
+Deployment
+----------
+
++ Make sure that the revision number in the about page reflects the global
+ revision of the web app.
+
+
+Production Servers
+------------------
+
++ move database to storage.opensuse.org
++ setup logrotate for server and debug logs
++ setup cronjob to remove session files
+o different session storage? (database or memcached)
diff --git a/src/api/README b/src/api/README
new file mode 100644
index 0000000..cd9d0ff
--- /dev/null
+++ b/src/api/README
@@ -0,0 +1,153 @@
+== Welcome to Rails
+
+Rails is a web-application and persistence framework that includes everything
+needed to create database-backed web-applications according to the
+Model-View-Control pattern of separation. This pattern splits the view (also
+called the presentation) into "dumb" templates that are primarily responsible
+for inserting pre-built data in between HTML tags. The model contains the
+"smart" domain objects (such as Account, Product, Person, Post) that holds all
+the business logic and knows how to persist themselves to a database. The
+controller handles the incoming requests (such as Save New Account, Update
+Product, Show Post) by manipulating the model and directing data to the view.
+
+In Rails, the model is handled by what's called an object-relational mapping
+layer entitled Active Record. This layer allows you to present the data from
+database rows as objects and embellish these data objects with business logic
+methods. You can read more about Active Record in
+link:files/vendor/rails/activerecord/README.html.
+
+The controller and view are handled by the Action Pack, which handles both
+layers by its two parts: Action View and Action Controller. These two layers
+are bundled in a single package due to their heavy interdependence. This is
+unlike the relationship between the Active Record and Action Pack that is much
+more separate. Each of these packages can be used independently outside of
+Rails. You can read more about Action Pack in
+link:files/vendor/rails/actionpack/README.html.
+
+
+== Getting started
+
+1. Run the WEBrick servlet: <tt>ruby script/server</tt> (run with --help for options)
+ ...or if you have lighttpd installed: <tt>ruby script/lighttpd</tt> (it's faster)
+2. Go to http://localhost:3000/ and get "Congratulations, you've put Ruby on Rails!"
+3. Follow the guidelines on the "Congratulations, you've put Ruby on Rails!" screen
+
+
+== Example for Apache conf
+
+
+ ServerName rails
+ DocumentRoot /path/application/public/
+ ErrorLog /path/application/log/server.log
+
+
+ Options ExecCGI FollowSymLinks
+ AllowOverride all
+ Allow from all
+ Order allow,deny
+ </Directory>
+ </VirtualHost>
+
+NOTE: Be sure that CGIs can be executed in that directory as well. So ExecCGI
+should be on and ".cgi" should respond. All requests from 127.0.0.1 go
+through CGI, so no Apache restart is necessary for changes. All other requests
+go through FCGI (or mod_ruby), which requires a restart to show changes.
+
+
+== Debugging Rails
+
+Have "tail -f" commands running on both the server.log, production.log, and
+test.log files. Rails will automatically display debugging and runtime
+information to these files. Debugging info will also be shown in the browser
+on requests from 127.0.0.1.
+
+
+== Breakpoints
+
+Breakpoint support is available through the script/breakpointer client. This
+means that you can break out of execution at any point in the code, investigate
+and change the model, AND then resume execution! Example:
+
+ class WeblogController < ActionController::Base
+ def index
+ @posts = Post.find_all
+ breakpoint "Breaking out from the list"
+ end
+ end
+
+So the controller will accept the action, run the first line, then present you
+with a IRB prompt in the breakpointer window. Here you can do things like:
+
+Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint'
+
+ >> @posts.inspect
+ => "[#nil, \"body\"=>nil, \"id\"=>\"1\"}>,
+ #\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
+ >> @posts.first.title = "hello from a breakpoint"
+ => "hello from a breakpoint"
+
+...and even better is that you can examine how your runtime objects actually work:
+
+ >> f = @posts.first
+ => #nil, "body"=>nil, "id"=>"1"}>
+ >> f.
+ Display all 152 possibilities? (y or n)
+
+Finally, when you're ready to resume execution, you press CTRL-D
+
+
+== Console
+
+You can interact with the domain model by starting the console through script/console.
+Here you'll have all parts of the application configured, just like it is when the
+application is running. You can inspect domain models, change values, and save to the
+database. Starting the script without arguments will launch it in the development environment.
+Passing an argument will specify a different environment, like <tt>console production</tt>.
+
+
+== Description of contents
+
+app
+ Holds all the code that's specific to this particular application.
+
+app/controllers
+ Holds controllers that should be named like weblog_controller.rb for
+ automated URL mapping. All controllers should descend from
+ ActionController::Base.
+
+app/models
+ Holds models that should be named like post.rb.
+ Most models will descend from ActiveRecord::Base.
+
+app/views
+ Holds the template files for the view that should be named like
+ weblog/index.rhtml for the WeblogController#index action. All views use eRuby
+ syntax. This directory can also be used to keep stylesheets, images, and so on
+ that can be symlinked to public.
+
+app/helpers
+ Holds view helpers that should be named like weblog_helper.rb.
+
+config
+ Configuration files for the Rails environment, the routing map, the database, and other dependencies.
+
+components
+ Self-contained mini-applications that can bundle together controllers, models, and views.
+
+lib
+ Application specific libraries. Basically, any kind of custom code that doesn't
+ belong under controllers, models, or helpers. This directory is in the load path.
+
+public
+ The directory available for the web server. Contains subdirectories for images, stylesheets,
+ and javascripts. Also contains the dispatchers and the default HTML files.
+
+script
+ Helper scripts for automation and generation.
+
+test
+ Unit and functional tests along with fixtures.
+
+vendor
+ External libraries that the application depends on. Also includes the plugins subdirectory.
+ This directory is in the load path.
diff --git a/src/api/README_LOGIN b/src/api/README_LOGIN
new file mode 100644
index 0000000..265259c
--- /dev/null
+++ b/src/api/README_LOGIN
@@ -0,0 +1,119 @@
+== Installation
+
+Done generating the login system. but there are still a few things you have to
+do manually. First open your application.rb and add
+
+ require_dependency "login_system"
+
+to the top of the file and include the login system with
+
+ include LoginSystem
+
+The beginning of your ApplicationController.
+It should look something like this :
+
+ require_dependency "login_system"
+
+ class ApplicationController < ActionController::Base
+ include LoginSystem
+ model :user
+
+After you have done the modifications the the AbstractController you can import
+the user model into the database. This model is meant as an example and you
+should extend it. If you just want to get things up and running you can find
+some create table syntax in db/user_model.sql.
+
+The model :user is required when you are hitting problems to the degree of
+"Session could not be restored becuase not all items in it are known"
+
+== Requirements
+
+You need a database table corresponding to the User model.
+
+ mysql syntax:
+ CREATE TABLE users (
+ id int(11) NOT NULL auto_increment,
+ login varchar(80) default NULL,
+ password varchar(40) default NULL,
+ PRIMARY KEY (id)
+ );
+
+ postgres :
+ CREATE TABLE "users" (
+ "id" SERIAL NOT NULL UNIQUE,
+ "login" VARCHAR(80),
+ "password" VARCHAR,
+ PRIMARY KEY("id")
+ ) WITH OIDS;
+
+
+ sqlite:
+ CREATE TABLE 'users' (
+ 'id' INTEGER PRIMARY KEY NOT NULL,
+ 'user' VARCHAR(80) DEFAULT NULL,
+ 'password' VARCHAR(40) DEFAULT NULL
+ );
+
+Of course your user model can have any amount of extra fields. This is just a
+starting point
+
+== How to use it
+
+Now you can go around and happily add "before_filter :login_required" to the
+controllers which you would like to protect.
+
+After integrating the login system with your rails application navigate to your
+new controller's signup method. There you can create a new account. After you
+are done you should have a look at your DB. Your freshly created user will be
+there but the password will be a sha1 hashed 40 digit mess. I find this should
+be the minimum of security which every page offering login&password should give
+its customers. Now you can move to one of those controllers which you protected
+with the before_filter :login_required snippet. You will automatically be re-
+directed to your freshly created login controller and you are asked for a
+password. After entering valid account data you will be taken back to the
+controller which you requested earlier. Simple huh?
+
+== Tips & Tricks
+
+How do I...
+
+ ... access the user who is currently logged in
+
+ A: You can get the user object from the session using @session['user']
+ Example:
+ Welcome <%= @session[:user].name %>
+
+ ... restrict access to only a few methods?
+
+ A: Use before_filters build in scoping.
+ Example:
+ before_filter :login_required, :only => [:myaccount, :changepassword]
+ before_filter :login_required, :except => [:index]
+
+ ... check if a user is logged-in in my views?
+
+ A: @session[:user] will tell you. Here is an example helper which you can use to make this more pretty:
+ Example:
+ def user?
+ !@session[:user].nil?
+ end
+
+ ... return a user to the page they came from before logging in?
+
+ A: The user will be send back to the last url which called the method "store_location"
+ Example:
+ User was at /articles/show/1, wants to log in.
+ in articles_controller.rb, add store_location to the show function and send the user
+ to the login form.
+ After he logs in he will be send back to /articles/show/1
+
+
+You can find more help at http://wiki.rubyonrails.com/rails/show/LoginGenerator
+
+== Changelog
+
+1.1.0 Major security bugfix and modernisation
+1.0.5 Bugfix in generator code
+1.0.2 Updated the readme with more tips&tricks
+1.0.1 Fixed problem in the readme
+1.0.0 First gem release
\ No newline at end of file
diff --git a/src/api/Rakefile b/src/api/Rakefile
new file mode 100644
index 0000000..cffd19f
--- /dev/null
+++ b/src/api/Rakefile
@@ -0,0 +1,10 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/switchtower.rake, and they will automatically be available to Rake.
+
+require(File.join(File.dirname(__FILE__), 'config', 'boot'))
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+require 'tasks/rails'
\ No newline at end of file
diff --git a/src/api/app/controllers/about_controller.rb b/src/api/app/controllers/about_controller.rb
new file mode 100644
index 0000000..594f3e6
--- /dev/null
+++ b/src/api/app/controllers/about_controller.rb
@@ -0,0 +1,7 @@
+class AboutController < ApplicationController
+
+ def index
+ @api_revision = "0.1"
+ end
+
+end
diff --git a/src/api/app/controllers/admin_controller.rb b/src/api/app/controllers/admin_controller.rb
new file mode 100644
index 0000000..2a47544
--- /dev/null
+++ b/src/api/app/controllers/admin_controller.rb
@@ -0,0 +1,29 @@
+class AdminController < ApplicationController
+
+ layout "html"
+
+ def list_sources
+ @files = []
+ read_dir( "data" )
+ end
+
+ hide_action :read_dir
+ def read_dir( dir )
+ d = Dir.new( dir )
+ d.each { |entry|
+ if ( entry == "." || entry == ".." )
+ next
+ end
+ path = dir + "/" + entry
+ @files.push path
+ if File.directory?( path )
+ read_dir( path )
+ end
+ }
+ end
+
+ def say_hello
+ render( :layout => false )
+ end
+
+end
diff --git a/src/api/app/controllers/apidocs_controller.rb b/src/api/app/controllers/apidocs_controller.rb
new file mode 100644
index 0000000..1ce7e51
--- /dev/null
+++ b/src/api/app/controllers/apidocs_controller.rb
@@ -0,0 +1,29 @@
+class ApidocsController < ApplicationController
+
+ @@apidocsbase = File.expand_path(APIDOCS_LOCATION)+"/"
+
+ def index
+ logger.debug "PATH: #{request.path}"
+ if ( request.path !~ /\/$/ )
+ redirect_to "/apidocs/"
+ else
+ filename = @@apidocsbase + "index.html"
+ if ( !File.exist?( filename ) )
+ render_text "Error"
+ else
+ render( :file => filename, :layout => "html" )
+ end
+ end
+ end
+
+ def method_missing symbol, *args
+ file = symbol.id2name
+ if ( file =~ /\.(xml|xsd)$/ )
+ send_file( @@apidocsbase + file, :type => "text/xml",
+ :disposition => "inline" )
+ else
+ super symbol, *args
+ end
+ end
+
+end
diff --git a/src/api/app/controllers/application.rb b/src/api/app/controllers/application.rb
new file mode 100644
index 0000000..17ec2f4
--- /dev/null
+++ b/src/api/app/controllers/application.rb
@@ -0,0 +1,143 @@
+# Filters added to this controller will be run for all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+
+# RAILS_ROOT is not working directory when running under lighttpd, so it has
+# to be added to load path
+$LOAD_PATH.unshift RAILS_ROOT
+require 'components/active_rbac/helpers/rbac_helper'
+require_dependency 'opensuse/permission'
+require_dependency 'opensuse/backend'
+require_dependency 'opensuse/validator'
+
+class ApplicationController < ActionController::Base
+ # Do never use a layout here since that has impact on every
+ # controller in frontend.
+
+ session_options[:prefix] = "ruby_frontend_sess."
+ session_options[:session_key] = "opensuse_frontend_session"
+ @user_permissions = nil
+
+ helper RbacHelper
+
+ before_filter :extract_user, :setup_backend, :validate
+
+ def extract_user
+ @http_user = nil;
+
+ authorization = request.env[ "HTTP_AUTHORIZATION" ]
+
+ logger.debug( "AUTH: #{authorization}" )
+
+ if authorization and authorization =~ /^\s*Basic /
+ authorization.sub!( /^\s*Basic /, '' )
+ # logger.debug( "AUTH2: #{authorization}" )
+
+ userpass = Base64.decode64( authorization ).split(/:/)
+ if userpass
+ login = userpass[0]
+ passwd = userpass[1]
+ end
+ else
+ logger.debug "no authentication string was sent"
+ render_error( :message => "Authentication required", :status => 401 ) and return false
+ end
+
+ if login
+ @http_user = User.find_with_credentials login, passwd
+ if @http_user.nil?
+ render_error( :message => "Unknown user: #{login}\n", :status => 401 ) and return false
+ else
+ logger.debug "USER found: #{@http_user.login}"
+ @user_permissions = Suse::Permission.new( @http_user )
+ end
+ end
+ end
+
+ def setup_backend
+ if @http_user
+ logger.debug "User for source backend config: <#{@http_user.source_host}>"
+ if @http_user.source_host && !@http_user.source_host.empty?
+ Suse::Backend.source_host = @http_user.source_host
+ end
+
+ if @http_user.source_port
+ Suse::Backend.source_port = @http_user.source_port
+ end
+
+ logger.debug "User for rpm backend config: <#{@http_user.rpm_host}>"
+ if @http_user.rpm_host && !@http_user.rpm_host.empty?
+ Suse::Backend.rpm_host = @http_user.rpm_host
+ end
+
+ if @http_user.rpm_port
+ Suse::Backend.rpm_port = @http_user.rpm_port
+ end
+
+ logger.debug "SETUP_SOURCE_BACKEND #{@http_user.source_host}:#{@http_user.source_port}"
+ logger.debug "SETUP_RPM_BACKEND #{@http_user.source_host}:#{@http_user.source_port}"
+ end
+ end
+
+ def validate
+ return true unless request.put?
+ Suse::Validator.new(params).validate(request.raw_post)
+ true
+ end
+
+ def forward_data( path, opt={} )
+ response = Suse::Backend.get( path, opt )
+ send_data( response.body, :type => response.fetch( "content-type" ),
+ :disposition => "inline" )
+ end
+
+ def rescue_action_in_public( exception )
+ #FIXME: not all exceptions are caught by this method
+ case exception
+ when ::Suse::Backend::HTTPError
+ response = exception.message
+ case response
+ when Net::HTTPForbidden
+ message = "Permission Denied"
+ else
+ message = "Backend Error: #{response.code}"
+ end
+ render_error :message => message, :status => response.code
+ return true
+ end
+ render_error :exception => exception
+ end
+
+ def local_request?
+ false
+ end
+
+ def permissions
+ return @user_permissions
+ end
+
+ def render_error( opt = {} )
+ @errorcode = 500
+
+ if opt[:status]
+ @errorcode = opt[:status]
+ if @errorcode.to_i == 401
+ response.headers["WWW-Authenticate"] = 'basic realm="Frontend login"'
+ end
+ end
+
+ @summary = "Internal Server Error"
+ if opt[:message]
+ @summary = opt[:message]
+ end
+
+ if opt[:exception]
+ @exception = opt[:exception ]
+ end
+
+ render :template => 'error', :status => @errorcode
+ end
+
+ def render_ok
+ render :nothing => true
+ end
+end
diff --git a/src/api/app/controllers/main_controller.rb b/src/api/app/controllers/main_controller.rb
new file mode 100644
index 0000000..305e82c
--- /dev/null
+++ b/src/api/app/controllers/main_controller.rb
@@ -0,0 +1,5 @@
+class MainController < ApplicationController
+
+ layout "html"
+
+end
diff --git a/src/api/app/controllers/person_controller.rb b/src/api/app/controllers/person_controller.rb
new file mode 100644
index 0000000..75c41f2
--- /dev/null
+++ b/src/api/app/controllers/person_controller.rb
@@ -0,0 +1,99 @@
+class PersonController < ApplicationController
+
+ def userinfo
+ if !@http_user
+ logger.debug "No user logged in, permission to userinfo denied"
+ @errorcode = 401
+ @summary = "No user logged in, permission to userinfo denied"
+ render :template => 'error', :status => 401
+ else
+ if request.get?
+ if params[:login]
+ logger.debug "Generating for user from parameter #{params[:login]}"
+ @render_user = User.find_by_login( params[:login] )
+ if ! @render_user
+ logger.debug "User is not valid!"
+ #FIXME: proper error returnage needed
+ @errorcode = 442
+ @summary = "Unknown user: #{params[:login]}"
+ render :template => 'error', :status => 442
+ end
+ else
+ logger.debug "Generating user info for logged in user #{@http_user.login}"
+ @render_user = @http_user
+ end
+ # see the corresponding view users.rxml that generates a xml
+ # response for the caller.
+
+ elsif request.put?
+ user = @http_user
+ if params[:login]
+ user = User.find_by_login( params[:login] )
+ if user.login != @http_user.login
+ # TODO: check permission to update someone elses info
+ if @http_user.has_permission "Userinfo_Admin"
+ # ok, may update user info
+ else
+ logger.debug "User has no permission to change userinfo"
+ @errorcode = 442
+ @summary = "no permission to change userinfo for user #{user.login}"
+ render :template => 'error', :status => 401
+ end
+ end
+ end
+
+ if user
+ xml = REXML::Document.new( request.raw_post )
+
+ logger.debug( "XML: #{request.raw_post}" )
+
+ realname = xml.elements["/person/realname"]
+ user.realname = realname.text
+
+ e = xml.elements["/person/source_backend"]
+ if ( e )
+ user.source_host = e.elements['host'].text
+ user.source_port = e.elements['port'].text
+ end
+
+ e = xml.elements["/person/rpm_backend"]
+ if ( e )
+ user.rpm_host = e.elements['host'].text
+ user.rpm_port = e.elements['port'].text
+ end
+
+ update_watchlist( user, xml )
+
+ user.save
+ @render_user = user
+ else
+ logger.debug "No valid user object"
+ end
+ end
+ end
+ end
+
+ def update_watchlist( user, xml )
+ new_watchlist = []
+ old_watchlist = []
+
+ xml.elements.each("/person/watchlist/project") do |e|
+ new_watchlist << e.attributes['name']
+ end
+
+ user.watched_projects.each do |wp|
+ old_watchlist << wp.name
+ end
+ add_to_watchlist = new_watchlist.collect {|i| old_watchlist.include?(i) ? nil : i}.compact
+ remove_from_watchlist = old_watchlist.collect {|i| new_watchlist.include?(i) ? nil : i}.compact
+
+ remove_from_watchlist.each do |name|
+ WatchedProject.find_by_name( name, :conditions => "user_id = #{user.id}" ).destroy
+ end
+
+ add_to_watchlist.each do |name|
+ user.watched_projects << WatchedProject.new( :name => name )
+ end
+ true
+ end
+end
diff --git a/src/api/app/controllers/platform_controller.rb b/src/api/app/controllers/platform_controller.rb
new file mode 100644
index 0000000..294ed91
--- /dev/null
+++ b/src/api/app/controllers/platform_controller.rb
@@ -0,0 +1,60 @@
+require 'opensuse/backend'
+
+class PlatformController < ApplicationController
+
+ def index
+ s = ""
+ out = Builder::XmlMarkup.new( :target => s )
+ out.directory do
+ response = Suse::Backend.get( "/platform/" )
+ directory = REXML::Document.new( response.body )
+ directory.elements.each( "/directory/entry" ) do |entry|
+ project_name = entry.attributes[ "name" ]
+ if ( project_name )
+ entry_response = Suse::Backend.get( "/platform/" + project_name )
+ entry = REXML::Document.new( entry_response.body )
+ entry.elements.each( "/directory/entry" ) do |e|
+ repository_name = e.attributes[ "name" ]
+ if ( repository_name )
+ out.entry( "name" => project_name + "/" + repository_name )
+ end
+ end
+ end
+ end
+ end
+
+ send_data( s, :type => "text/xml", :disposition => "inline" )
+ end
+
+ def project
+ forward_data( "/platform/" + params[:project] )
+ end
+
+ def repository
+ repository = params[ :repository ]
+ project = params[ :project ]
+
+ if ( !repository || !project )
+ redirect_to :index
+ return
+ else
+ path = "/platform/" + project + "/" + repository
+
+ if request.get?
+ forward_data( path )
+ return
+ elsif request.put?
+ response = Suse::Backend.put( path, request.raw_post )
+ case response
+ when Net::HTTPSuccess, Net::HTTPRedirection
+ render_text( "Ok" )
+ return
+ else
+ render_text( "Error: " + response.error! )
+ return
+ end
+ end
+ end
+ end
+
+end
diff --git a/src/api/app/controllers/result_controller.rb b/src/api/app/controllers/result_controller.rb
new file mode 100644
index 0000000..288bb44
--- /dev/null
+++ b/src/api/app/controllers/result_controller.rb
@@ -0,0 +1,107 @@
+require 'rexml/document'
+
+class ResultController < ApplicationController
+
+ def index
+ render_text( "Results Index" )
+ end
+
+ def projectresult
+ @project = params[:project]
+
+ response = Suse::Backend.get_project_result( @project )
+
+ @repository_status = Hash.new
+
+ result = REXML::Document.new( response.body ).root
+ result.elements["/statussumlist"].elements.each do |s|
+ status = s.attributes["status"]
+ if status
+ arch_name = s.attributes["name"]
+ arch_name =~ /.*\/(.*)\/(.*)/
+ repository = $1
+ arch = $2
+ if ( repository != ":all" )
+ @arch_status = @repository_status[ repository ]
+ if ( !@arch_status )
+ @arch_status = Hash.new
+ end
+ @arch_status[ arch ] = status
+ @repository_status[ repository ] = @arch_status
+ end
+
+ if( repository == ":all" && arch == ":all" )
+ @succeeded = s.attributes["succeeded"]
+ @rpms = s.attributes["rpms"]
+ @building = s.attributes["building"]
+ @delayed = s.attributes["delayed"]
+ @status = status
+ end
+ end
+ end
+
+ end
+
+ def packageresult
+ @project = params[:project]
+ @repository = params[:platform]
+ @package = params[:package]
+
+ response = Suse::Backend.get_package_result( @project, @repository, @package )
+
+ @arch_status = Hash.new
+ @arch_rpms = Hash.new
+
+ result = REXML::Document.new( response.body ).root
+ result.elements["/statussumlist"].elements.each do |s|
+ status = s.attributes["status"]
+ if status
+ arch_name = s.attributes["name"]
+ arch_name =~ /.*\/.*\/(.*)/
+ arch = $1
+ @arch_status[ arch ] = status
+
+ rpm_response = Suse::Backend.get_rpmlist( @project, @repository,
+ @package, arch )
+ rpms = Array.new
+ rpm_result = REXML::Document.new( rpm_response.body ).root
+ rpm_result.elements["/rpmlist"].elements.each do |r|
+ rpms.push r.attributes["filename"]
+ end
+
+ @arch_rpms[ arch ] = rpms
+
+ else
+ @succeeded = s.attributes["succeeded"]
+ @failed = s.attributes["failed"]
+ end
+ end
+
+ if @failed == "0"
+ @status = "suceeded"
+ elsif @succeeded == "0"
+ @status = "failed"
+ else
+ @status = "partiallyfailed"
+ end
+
+ end
+
+ def log
+ @project = params[:project]
+ @repository = params[:platform]
+ @package = params[:package]
+ @arch = params[:arch]
+
+ if( params[:nostream] )
+ start = params[:start] or 0
+ response = Suse::Backend.get_log_chunk( @project, @repository, @package, @arch, start )
+ else
+ response = Suse::Backend.get_log( @project, @repository, @package, @arch )
+ end
+ send_data( response.body, :type => "text/plain",
+ :disposition => "inline" )
+
+ end
+
+end
diff --git a/src/api/app/controllers/rpm_controller.rb b/src/api/app/controllers/rpm_controller.rb
new file mode 100644
index 0000000..b92c3ce
--- /dev/null
+++ b/src/api/app/controllers/rpm_controller.rb
@@ -0,0 +1,28 @@
+class RpmController < ApplicationController
+
+ def index
+ render_text( "RPMs Index" )
+ end
+
+ def file
+ repository = params[ :repository ]
+ project = params[ :project ]
+ arch = params[ :arch ]
+ package = params[ :package ]
+ file = params[ :file ]
+
+ if ( !repository || !project || !file || !arch )
+ render_text( "Error in URL to RPM" )
+ return
+ end
+
+ path = "/rpm/" + project + "/" + repository + "/" + arch + "/" + package +
+ "/" + file
+ if request.get?
+ response = Suse::Backend.get_rpm( path )
+ send_data( response.body, :type => response.fetch( "content-type" ),
+ :disposition => "inline" )
+ end
+ end
+
+end
diff --git a/src/api/app/controllers/source_controller.rb b/src/api/app/controllers/source_controller.rb
new file mode 100644
index 0000000..234a436
--- /dev/null
+++ b/src/api/app/controllers/source_controller.rb
@@ -0,0 +1,188 @@
+require "rexml/document"
+
+class SourceController < ApplicationController
+ #TODO: nearly all validations fail, uncomment lines to activate validation
+ #validate_action :index => :directory, :packagelist => :directory, :filelist => :directory
+ #validate_action :project_meta => :project, :package_meta => :package
+
+
+ def index
+ projectlist
+ end
+
+ def projectlist
+ forward_data "/source"
+ end
+
+ def index_project
+ project = params[:project]
+ forward_data "/source/#{project}"
+ end
+
+ def index_package
+ project = params[:project]
+ package = params[:package]
+ if request.get?
+ forward_data "/source/#{project}/#{package}"
+ elsif request.post?
+ specfile_path = "/source/#{project}/#{package}/#{package}.spec"
+ begin
+ Suse::Backend.get( specfile_path )
+ render_error "status" => 403, "summary" => "SPEC file already exists."
+ rescue Suse::Backend::NotFoundError
+ specfile = File.read "#{RAILS_ROOT}/files/specfiletemplate"
+ Suse::Backend.put_source( specfile_path, specfile )
+ end
+ render_ok
+ end
+ end
+
+ def project_meta
+ project = params[:project]
+ path = "/source/#{project}/_meta"
+
+ request_data = request.raw_post
+
+ if request.get?
+ forward_data path
+ elsif request.put?
+ # Need permission
+ logger.debug "Checking permission for the put"
+ allowed = false
+ begin
+ # Try to fetch the project to see if it already exists
+ response = Suse::Backend.get( path )
+
+ # Being here means that the project already exists
+ allowed = permissions.project_change? project
+ rescue Suse::Backend::NotFoundError
+ # Ok, the project is new
+ allowed = permissions.global_project_create
+
+ if allowed
+ # This is a new project. Add the logged in user as maintainer
+ request_data = check_and_add_maintainer request_data, "project"
+ logger.debug "Added maintainer to new project, xml is now #{request_data}"
+ else
+ # User is not allowed by global permission.
+ logger.debug "Not allowed to create new packages"
+ end
+ end
+
+ logger.debug response
+
+ if allowed
+ response = Suse::Backend.put_source path, request_data
+ render_ok
+ else
+ logger.debug "No permissions to PUT on #{path}"
+ render_error( :message => "Permission Denied", :status => 403 )
+ end
+ else
+ #neither put nor post
+ #TODO: return correct error code
+ render_error :message => "Illegal request: POST #{path}", :status => 500
+ end
+ end
+
+ def package_meta
+ project = params[:project]
+ package = params[:package]
+ path = "/source/#{project}/#{package}/_meta"
+
+ if request.get?
+ response = Suse::Backend.get( path )
+
+ result = REXML::Document.new( response.body ).root
+ package_element = result.elements["/package"]
+ @name = package_element.attributes["name"]
+ @description = package_element.elements["description"].text
+ @title = package_element.elements["title"].text
+
+ @persons = Array.new
+ result.each_element('person') do |p|
+ person = Hash.new
+ person[ "userid" ] = p.attributes["userid"]
+ person[ "role" ] = p.attributes["role"]
+ @persons.push person
+ end
+
+ @files = Array.new
+ result.each_element('file') do |p|
+ file = Hash.new
+ file[ "filetype" ] = p.attributes["filetype"]
+ file[ "filename" ] = p.attributes["filename"]
+ @files.push file
+ end
+ elsif request.put?
+ allowed = false
+ request_data = request.raw_post
+ begin
+ # Try to fetch the package to see if it already exists
+ response = Suse::Backend.get( path )
+
+ # Being here means that the project already exists
+ allowed = permissions.package_change? project, package
+ rescue Suse::Backend::NotFoundError
+ # Ok, the project is new
+ allowed = permissions.package_create?( project )
+
+ if allowed
+ request_data = check_and_add_maintainer request_data, "package"
+ else
+ # User is not allowed by global permission.
+ logger.debug "Not allowed to create new packages"
+ end
+ end
+
+ if allowed
+ Suse::Backend.put_source path, request_data
+ render_ok
+ else
+ logger.debug "No permission to PUT on #{path}"
+ render_error( :message => "Permission Denied on package", :status => 403 )
+ end
+ else
+ # neither put nor post
+ #TODO: return correct error code
+ render_error :message => "Illegal request: POST #{path}", :status => 500
+ end
+ end
+
+ def file
+ project = params[ :project ]
+ package = params[ :package ]
+ file = params[ :file ]
+
+ path = "/source/#{project}/#{package}/#{file}"
+
+ if request.get?
+ forward_data path
+ elsif request.put?
+ allowed = permissions.package_change? project, package
+ if allowed
+ Suse::Backend.put_source path, request.raw_post
+ render_ok
+ else
+ render_error :message => "Permission denied on package write file", :status => 403
+ end
+ end
+ end
+
+ private
+
+ def check_and_add_maintainer( data, topelem )
+ doc = REXML::Document.new( data )
+ # logger.debug "The XML Document: " + doc.to_s
+ root = doc.root
+ elem = doc.elements["#{topelem}/person[@role='maintainer']"]
+
+ unless elem
+ person_elem = doc.elements[topelem].add_element "person"
+
+ person_elem.attributes["userid"] = @http_user.login
+ person_elem.attributes["role"] = "maintainer"
+ end
+ return doc.to_s
+ end
+end
diff --git a/src/api/app/helpers/about_helper.rb b/src/api/app/helpers/about_helper.rb
new file mode 100644
index 0000000..68e69ae
--- /dev/null
+++ b/src/api/app/helpers/about_helper.rb
@@ -0,0 +1,2 @@
+module AboutHelper
+end
diff --git a/src/api/app/helpers/admin_helper.rb b/src/api/app/helpers/admin_helper.rb
new file mode 100644
index 0000000..d5c6d35
--- /dev/null
+++ b/src/api/app/helpers/admin_helper.rb
@@ -0,0 +1,2 @@
+module AdminHelper
+end
diff --git a/src/api/app/helpers/apidocs_helper.rb b/src/api/app/helpers/apidocs_helper.rb
new file mode 100644
index 0000000..f7e8190
--- /dev/null
+++ b/src/api/app/helpers/apidocs_helper.rb
@@ -0,0 +1,2 @@
+module ApidocsHelper
+end
diff --git a/src/api/app/helpers/application_helper.rb b/src/api/app/helpers/application_helper.rb
new file mode 100644
index 0000000..0403584
--- /dev/null
+++ b/src/api/app/helpers/application_helper.rb
@@ -0,0 +1,4 @@
+# Methods added to this helper will be available to all templates in the application.
+module ApplicationHelper
+
+end
diff --git a/src/api/app/helpers/main_helper.rb b/src/api/app/helpers/main_helper.rb
new file mode 100644
index 0000000..826effe
--- /dev/null
+++ b/src/api/app/helpers/main_helper.rb
@@ -0,0 +1,2 @@
+module MainHelper
+end
diff --git a/src/api/app/helpers/person_helper.rb b/src/api/app/helpers/person_helper.rb
new file mode 100644
index 0000000..f5c74cd
--- /dev/null
+++ b/src/api/app/helpers/person_helper.rb
@@ -0,0 +1,2 @@
+module PersonHelper
+end
diff --git a/src/api/app/helpers/platform_helper.rb b/src/api/app/helpers/platform_helper.rb
new file mode 100644
index 0000000..20396a1
--- /dev/null
+++ b/src/api/app/helpers/platform_helper.rb
@@ -0,0 +1,2 @@
+module PlatformHelper
+end
diff --git a/src/api/app/helpers/result_helper.rb b/src/api/app/helpers/result_helper.rb
new file mode 100644
index 0000000..70e46e6
--- /dev/null
+++ b/src/api/app/helpers/result_helper.rb
@@ -0,0 +1,2 @@
+module ResultHelper
+end
diff --git a/src/api/app/helpers/rpm_helper.rb b/src/api/app/helpers/rpm_helper.rb
new file mode 100644
index 0000000..36e7daf
--- /dev/null
+++ b/src/api/app/helpers/rpm_helper.rb
@@ -0,0 +1,2 @@
+module RpmHelper
+end
diff --git a/src/api/app/helpers/source_helper.rb b/src/api/app/helpers/source_helper.rb
new file mode 100644
index 0000000..2f7efc3
--- /dev/null
+++ b/src/api/app/helpers/source_helper.rb
@@ -0,0 +1,2 @@
+module SourceHelper
+end
diff --git a/src/api/app/models/watched_project.rb b/src/api/app/models/watched_project.rb
new file mode 100644
index 0000000..d472b5e
--- /dev/null
+++ b/src/api/app/models/watched_project.rb
@@ -0,0 +1,3 @@
+class WatchedProject < ActiveRecord::Base
+ belongs_to :user
+end
diff --git a/src/api/app/views/about/index.rxml b/src/api/app/views/about/index.rxml
new file mode 100644
index 0000000..ecd8e14
--- /dev/null
+++ b/src/api/app/views/about/index.rxml
@@ -0,0 +1,6 @@
+xml.about do
+ xml.title "openSUSE API"
+ xml.description "API to the openSUSE Build Service"
+ xml.revision @api_revision
+ xml.documentation :type => "text/html", :url => apidocs_url( :controller => "apidocs" )
+end
diff --git a/src/api/app/views/admin/index.rhtml b/src/api/app/views/admin/index.rhtml
new file mode 100644
index 0000000..5c87bb6
--- /dev/null
+++ b/src/api/app/views/admin/index.rhtml
@@ -0,0 +1,11 @@
+<h2>Administrator Tasks</h2>
+
+
+ <ul style="list-style: none; border: 1px solid #e0e0e0; padding: 1em; background: #f0f0f0;">
+ <li><%= link_to 'User Management', :controller => '/active_rbac/user' %></li>
+ <li><%= link_to 'Group Management', :controller => '/active_rbac/group' %></li>
+ <li><%= link_to 'Role Management', :controller => '/active_rbac/role' %></li>
+ <li><%= link_to 'Permission Management', :controller => '/active_rbac/static_permission' %></li>
+ </ul>
+
+
diff --git a/src/api/app/views/admin/list_sources.rhtml b/src/api/app/views/admin/list_sources.rhtml
new file mode 100644
index 0000000..b870aa5
--- /dev/null
+++ b/src/api/app/views/admin/list_sources.rhtml
@@ -0,0 +1,5 @@
+<h2>All Sources</h2>
+
+<% for file in @files %>
+<%= file %>
+<% end %>
diff --git a/src/api/app/views/admin/say_hello.rhtml b/src/api/app/views/admin/say_hello.rhtml
new file mode 100644
index 0000000..8006044
--- /dev/null
+++ b/src/api/app/views/admin/say_hello.rhtml
@@ -0,0 +1 @@
+<em>Hello from Ajax!</em> (Session ID is <%= session.session_id %>)
diff --git a/src/api/app/views/error.rxml b/src/api/app/views/error.rxml
new file mode 100644
index 0000000..3656c92
--- /dev/null
+++ b/src/api/app/views/error.rxml
@@ -0,0 +1,16 @@
+xml.instruct!
+xml.error do
+ xml.code( @errorcode )
+ xml.summary( @summary )
+ if( @exception )
+ xml.exception do
+ xml.type( @exception.class.name )
+ xml.message( @exception.message )
+ xml.backtrace do
+ @exception.backtrace.each do |line|
+ xml.line( line )
+ end
+ end
+ end
+ end
+end
diff --git a/src/api/app/views/layouts/html.rhtml b/src/api/app/views/layouts/html.rhtml
new file mode 100644
index 0000000..06134ac
--- /dev/null
+++ b/src/api/app/views/layouts/html.rhtml
@@ -0,0 +1,36 @@
+<html>
+<head>
+ <title>openSUSE Build Service Frontend</title>
+ <%= stylesheet_link_tag "opensuse", :media => "all" %>
+</head>
+<body>
+<div id="banner">
+ <div id="innerbanner">
+ <div id="logo"><img src="/images/opensuse.gif"/></div>
+ <div id="title">Frontend</div>
+ </div>
+</div>
+
+ <div id="main">
+ <% if flash[:note] %>
+ <div id="notice"><%= flash[:note] %></div>
+ <% end %>
+ <% if flash[:error] %>
+ <div id="error"><%= flash[:error] %></div>
+ <% end %>
+ <%= @content_for_layout %>
+ </div>
+ <div id="bottom">
+ <a href="http://build.opensuse.org">Build Service Web Client</a> |
+ <%= link_to "Frontend Startpage", :controller => "main",
+ :action => "index" %> |
+ <a href="http://www.opensuse.org">openSUSE Home</a>
+ <br/>
+ Logged in as <%= current_user.login %>
+ <% if current_user.login == "Anonymous" %>
+ <%= link_to "Login", :controller => "login", :action => "login" %>
+ <% else %>
+ <%= link_to "Logout", :controller => "login", :action => "logout" %>
+ <% end %>
+
+ </div>
diff --git a/src/api/app/views/main/index.rhtml b/src/api/app/views/main/index.rhtml
new file mode 100644
index 0000000..eebda96
--- /dev/null
+++ b/src/api/app/views/main/index.rhtml
@@ -0,0 +1,19 @@
+<p>
+<%= link_to "openSUSE API Documentation", { :controller => "apidocs" } %>
+</p>
+
+<% if current_user.has_permission( "Permission_Admin" ) %>
+<p>
+ <%= link_to "Admin Interface", { :controller => "admin" } %>
+</p>
+<% end %>
+
+<p>
+<% if current_user.login == "Anonymous" %>
+ <%= link_to "Create Account", { :controller => "register" } %>
+<% else %>
+ <%= link_to "User Management", { :controller => "arbac/user", :action => "list" } %>
+<% end %>
+</p>
+
+<p><a href="http://build.opensuse.org">Go back to openSUSE Build Service web client</a></p>
diff --git a/src/api/app/views/person/userinfo.rxml b/src/api/app/views/person/userinfo.rxml
new file mode 100644
index 0000000..ffd817b
--- /dev/null
+++ b/src/api/app/views/person/userinfo.rxml
@@ -0,0 +1,23 @@
+xml.person do
+ xml.login @render_user.login
+ xml.email @render_user.email
+ xml.realname @render_user.realname
+
+ xml.source_backend do
+ xml.host @render_user.source_host
+ xml.port @render_user.source_port
+ end
+
+ xml.rpm_backend do
+ xml.host @render_user.rpm_host
+ xml.port @render_user.rpm_port
+ end
+
+ if( @render_user.watched_projects.count > 0 )
+ xml.watchlist do
+ @render_user.watched_projects.each do |wp|
+ xml.project :name => wp.name
+ end
+ end
+ end
+end
diff --git a/src/api/app/views/result/packageresult.rxml b/src/api/app/views/result/packageresult.rxml
new file mode 100644
index 0000000..6d5a370
--- /dev/null
+++ b/src/api/app/views/result/packageresult.rxml
@@ -0,0 +1,16 @@
+xml.packageresult( "project" => @project, "repository" => @repository,
+ "package" => @package ) do
+ xml.date( Time.now )
+ xml.status( "code" => @status ) do
+ xml.packagecount( @succeeded, "state" => "succeeded" )
+ xml.packagecount( @failed, "state" => "failed" )
+ end
+ @arch_status.each do | a, s |
+ xml.archresult( "arch" => a ) do
+ xml.status( "code" => s )
+ @arch_rpms[ a ].each do |r|
+ xml.rpm( "filename" => r )
+ end
+ end
+ end
+end
diff --git a/src/api/app/views/result/projectresult.rxml b/src/api/app/views/result/projectresult.rxml
new file mode 100644
index 0000000..f4d1167
--- /dev/null
+++ b/src/api/app/views/result/projectresult.rxml
@@ -0,0 +1,18 @@
+xml.projectresult( "project" => @project ) do
+ xml.date( Time.now )
+ xml.status( "code" => @status ) do
+ xml.packagecount( @succeeded, "state" => "succeeded" )
+ xml.packagecount( @rpms, "state" => "rpms" )
+ xml.packagecount( @building, "state" => "building" )
+ xml.packagecount( @delayed, "state" => "delayed" )
+ end
+ @repository_status.each do | r, arch_status |
+ xml.repositoryresult( "name" => r ) do
+ arch_status.each do | a, s |
+ xml.archresult( "arch" => a ) do
+ xml.status( "code" => s )
+ end
+ end
+ end
+ end
+end
diff --git a/src/api/app/views/source/_meta.rhtml b/src/api/app/views/source/_meta.rhtml
new file mode 100644
index 0000000..66c4f95
--- /dev/null
+++ b/src/api/app/views/source/_meta.rhtml
@@ -0,0 +1,10 @@
+<body bgcolor="a00000">
+<h1>Meta</h1>
+Request: <%= request.method %>
+<br/>
+Parameters: <%= debug(params) %>
+<br/>
+Path: <%= request.path %>
+<br/>
+Project: <%= params['project'] %>
+</body>
diff --git a/src/api/app/views/source/package_meta.rxml b/src/api/app/views/source/package_meta.rxml
new file mode 100644
index 0000000..324093f
--- /dev/null
+++ b/src/api/app/views/source/package_meta.rxml
@@ -0,0 +1,10 @@
+xml.package( "name" => @name ) do
+ xml.title @title
+ xml.description @description
+ @persons.each do |p|
+ xml.person( "userid" => p["userid"], "role" => p["role"] )
+ end
+ @files.each do |f|
+ xml.file( "filetype" => f["filetype"], "filename" => f["filename"] )
+ end
+end
diff --git a/src/api/components/active_rbac/CHANGELOG b/src/api/components/active_rbac/CHANGELOG
new file mode 100644
index 0000000..5c064cf
--- /dev/null
+++ b/src/api/components/active_rbac/CHANGELOG
@@ -0,0 +1,27 @@
+*SVN*
+
+*0.2.1*
+
+* Fixing documentation error (#81)
+* Fixing documentation of the ImportCmsSchema migration (#67)
+
+*0.2*
+
+* Adding "salt" to the user table and passwords are salted now.
+* Changing fixtures to use "--- !omap" instead of "--- !!omap" which seems to make them workw ith 0.14.2 RoR.
+* Fixing a bug related to custom "parent=" methods in Role and Group.
+* Making active_rbac compatible to RoR 0.14.2 (1.0RC3)
+* Adding ComponentController that solves the "configuration vanishes after reload" issue and makes configuration handling more consistent.
+* Merged the GET/POST differentiation of RegistrationController and LoginController. The actions available are now: login, logout for LoginController and register, lostpassword and confirm for RegistrationController.
+* Using Unicode explicitely in the creation SQL scripts for MySQL now.
+* We are using transactional fixtures now.
+* Renamed UserTest in user_registration_test.rb to UserRegistrationTest.rb. "rake test_components" works now properly.
+* Adding HOWTO: How To Allow User Login With Other States
+* Developers can now override User.state_allows_login?(state) to implement their own login logic.
+* Adding HOWTO: How To Change The State Workflow
+* Adding HOWTO: How To Add Fields To The Registration Form
+* Adding HOWTO file
+* Adding support for additional fields to the configuration class.
+* Moving constant User::STATES.states to the method User.states
+
+*0.1*
diff --git a/src/api/components/active_rbac/component_controller.rb b/src/api/components/active_rbac/component_controller.rb
new file mode 100644
index 0000000..a66c2ad
--- /dev/null
+++ b/src/api/components/active_rbac/component_controller.rb
@@ -0,0 +1,24 @@
+require_dependency 'active_rbac/configuration'
+
+# All controllers in ActiveRBAC extend this controller. Currently, it only
+# provides the method config to access ActiveRBAC's configuration.
+class ActiveRbac::ComponentController < ApplicationController
+
+ protected
+
+ # This method returns the config class. See this
+ # class' documentation about the details of the various configuration
+ # options.
+ #
+ # Example:
+ #
+ # class ActiveRbac::GroupController < ActiveRbac::ComponentController
+ # layout config.controller[:layout]
+ # end
+ def self.config
+ ActiveRbac::Configuration
+ end
+
+ # An alias to self.config
+ def config; self.class.config; end
+end
\ No newline at end of file
diff --git a/src/api/components/active_rbac/configuration.rb b/src/api/components/active_rbac/configuration.rb
new file mode 100644
index 0000000..e2cfe67
--- /dev/null
+++ b/src/api/components/active_rbac/configuration.rb
@@ -0,0 +1,57 @@
+# This class is a container for the ActiveRBAC components configuration setup.
+# There is an accessor method for each "aspect" of this component that returns a
+# hash representing a tree. You can access the following values.
+#
+# * mailer The configuration hash for the mailer classes.
+# * mailer[:template_root] The template path the mailer will look in.
+# * mailer[:subjects] A hash of the subjects to use. Currently used: _confirm_registration_, _lost_password_
+# * mailer[:headers] A hash with additional headers to set in the emails.
+# * controller The configuration for the controllers.
+# * controller[:layout] The path to the layout to use. Defaults to '../app/views/layouts/application'.
+#
+# == Configuration
+#
+# If you want to change the configuration, you have to put it into
+# "config/active_rbac_config.rb". An example:
+#
+# ActiveRbac::Configuration.mailer[:from] = 'foo '
+class ActiveRbac::Configuration
+ @@mailer = {}
+
+ @@mailer[:template_root] = 'components'
+ @@mailer[:from] = 'ActiveRBAC '
+
+ @@mailer[:subjects] = {}
+ @@mailer[:subjects][:confirm_registration] = 'Please confirm your registration'
+ @@mailer[:subjects][:lost_password] = 'Your new password'
+
+ # Additional headers to set besides Subject: and To:
+ @@mailer[:headers] = {}
+
+ @@controller = {}
+ @@controller[:layout] = '../app/views/layouts/html'
+ @@controller[:registration] = {}
+ @@controller[:registration][:signup_fields] = []
+
+ @@model = {}
+ @@model[:default_hash_type] = 'md5'
+
+ @@signup_fields = []
+
+ class << self
+ def mailer # :nodoc:
+ @@mailer
+ end
+
+ def controller # :nodoc:
+ @@controller
+ end
+
+ def model # :nodoc:
+ @@model
+ end
+ end
+end
+
+# Require the configuration for the active_rbac component
+require_dependency 'config/active_rbac_config'
diff --git a/src/api/components/active_rbac/db/create.mssql.sql b/src/api/components/active_rbac/db/create.mssql.sql
new file mode 100644
index 0000000..0c9fbe6
--- /dev/null
+++ b/src/api/components/active_rbac/db/create.mssql.sql
@@ -0,0 +1,374 @@
+-- [ActiveRBAC 0.1]
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_groups_groups_parent]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[groups] DROP CONSTRAINT FK_groups_groups_parent
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_groups_roles_groups]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[groups_roles] DROP CONSTRAINT FK_groups_roles_groups
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_groups_users_groups]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[groups_users] DROP CONSTRAINT FK_groups_users_groups
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_groups_roles_roles]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[groups_roles] DROP CONSTRAINT FK_groups_roles_roles
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_roles_roles_parent]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[roles] DROP CONSTRAINT FK_roles_roles_parent
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_roles_static_permissions_roles]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[roles_static_permissions] DROP CONSTRAINT FK_roles_static_permissions_roles
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_roles_users_roles]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[roles_users] DROP CONSTRAINT FK_roles_users_roles
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_roles_static_permissions_static_permissions]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[roles_static_permissions] DROP CONSTRAINT FK_roles_static_permissions_static_permissions
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_groups_users_users]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[groups_users] DROP CONSTRAINT FK_groups_users_users
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_roles_users_users]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[roles_users] DROP CONSTRAINT FK_roles_users_users
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[FK_user_registrations_users]') and OBJECTPROPERTY(id, N'IsForeignKey') = 1)
+ALTER TABLE [dbo].[user_registrations] DROP CONSTRAINT FK_user_registrations_users
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[groups]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table [dbo].[groups]
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[groups_roles]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table [dbo].[groups_roles]
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[groups_users]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table [dbo].[groups_users]
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[roles]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table [dbo].[roles]
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[roles_static_permissions]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table [dbo].[roles_static_permissions]
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[roles_users]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table [dbo].[roles_users]
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[static_permissions]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table [dbo].[static_permissions]
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[user_registrations]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table [dbo].[user_registrations]
+GO
+
+if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[users]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
+drop table [dbo].[users]
+GO
+
+CREATE TABLE [dbo].[groups] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [created_at] [datetime] NOT NULL ,
+ [updated_at] [datetime] NOT NULL ,
+ [title] [varchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
+ [parent_id] [int] NULL
+) ON [PRIMARY]
+GO
+
+CREATE TABLE [dbo].[groups_roles] (
+ [group_id] [int] NOT NULL ,
+ [role_id] [int] NOT NULL ,
+ [created_at] [datetime] NOT NULL
+) ON [PRIMARY]
+GO
+
+CREATE TABLE [dbo].[groups_users] (
+ [group_id] [int] NULL ,
+ [user_id] [int] NULL ,
+ [created_at] [datetime] NULL
+) ON [PRIMARY]
+GO
+
+CREATE TABLE [dbo].[roles] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [created_at] [datetime] NOT NULL ,
+ [updated_at] [datetime] NOT NULL ,
+ [title] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
+ [parent_id] [int] NULL
+) ON [PRIMARY]
+GO
+
+CREATE TABLE [dbo].[roles_static_permissions] (
+ [static_permission_id] [int] NOT NULL ,
+ [role_id] [int] NOT NULL ,
+ [created_at] [datetime] NOT NULL
+) ON [PRIMARY]
+GO
+
+CREATE TABLE [dbo].[roles_users] (
+ [user_id] [int] NOT NULL ,
+ [role_id] [int] NOT NULL ,
+ [created_at] [datetime] NOT NULL
+) ON [PRIMARY]
+GO
+
+CREATE TABLE [dbo].[static_permissions] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [title] [varchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
+ [created_at] [datetime] NOT NULL ,
+ [updated_at] [datetime] NOT NULL
+) ON [PRIMARY]
+GO
+
+CREATE TABLE [dbo].[user_registrations] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [user_id] [int] NOT NULL ,
+ [token] [text] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
+ [created_at] [datetime] NOT NULL ,
+ [expires_at] [datetime] NOT NULL
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
+GO
+
+CREATE TABLE [dbo].[users] (
+ [id] [int] IDENTITY (1, 1) NOT NULL ,
+ [created_at] [datetime] NOT NULL ,
+ [updated_at] [datetime] NOT NULL ,
+ [last_logged_in_at] [datetime] NOT NULL ,
+ [login_failure_count] [int] NOT NULL ,
+ [login] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
+ [email] [varchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
+ [password] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
+ [password_hash_type] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
+ [password_salt] [char] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
+ [state] [int] NOT NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[groups] WITH NOCHECK ADD
+ CONSTRAINT [PK_groups] PRIMARY KEY CLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[roles] WITH NOCHECK ADD
+ CONSTRAINT [PK_roles] PRIMARY KEY CLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[static_permissions] WITH NOCHECK ADD
+ CONSTRAINT [PK_static_permissions] PRIMARY KEY CLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[user_registrations] WITH NOCHECK ADD
+ CONSTRAINT [PK_user_registrations] PRIMARY KEY CLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[users] WITH NOCHECK ADD
+ CONSTRAINT [PK_users] PRIMARY KEY CLUSTERED
+ (
+ [id]
+ ) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[groups] ADD
+ CONSTRAINT [UC_groups_title] UNIQUE NONCLUSTERED
+ (
+ [title]
+ ) ON [PRIMARY]
+GO
+
+ CREATE INDEX [IX_groups_parent_id] ON [dbo].[groups]([parent_id]) ON [PRIMARY]
+GO
+
+ CREATE UNIQUE INDEX [IX_groups_roles_all] ON [dbo].[groups_roles]([group_id], [role_id]) ON [PRIMARY]
+GO
+
+ CREATE INDEX [IX_groups_users_all] ON [dbo].[groups_users]([group_id], [user_id]) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[roles] ADD
+ CONSTRAINT [UC_roles_title] UNIQUE NONCLUSTERED
+ (
+ [title]
+ ) ON [PRIMARY]
+GO
+
+ CREATE INDEX [IX_roles_parent_id] ON [dbo].[roles]([parent_id]) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[roles_static_permissions] ADD
+ CONSTRAINT [UC_roles_static_permissions_roles] UNIQUE NONCLUSTERED
+ (
+ [static_permission_id],
+ [role_id]
+ ) ON [PRIMARY]
+GO
+
+ CREATE UNIQUE INDEX [IX_roles_static_permissions_roles] ON [dbo].[roles_static_permissions]([static_permission_id], [role_id]) ON [PRIMARY]
+GO
+
+ CREATE INDEX [IX_roles_static_permissions] ON [dbo].[roles_static_permissions]([static_permission_id]) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[roles_users] ADD
+ CONSTRAINT [UC_roles_users] UNIQUE NONCLUSTERED
+ (
+ [user_id],
+ [role_id]
+ ) ON [PRIMARY]
+GO
+
+ CREATE INDEX [IX_roles_users_all] ON [dbo].[roles_users]([user_id], [role_id]) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[static_permissions] ADD
+ CONSTRAINT [UC_static_permissions_title] UNIQUE NONCLUSTERED
+ (
+ [title]
+ ) ON [PRIMARY]
+GO
+
+ CREATE UNIQUE INDEX [IX_static_permissions_title] ON [dbo].[static_permissions]([title]) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[user_registrations] ADD
+ CONSTRAINT [UC_user_registrations_user_id] UNIQUE NONCLUSTERED
+ (
+ [user_id]
+ ) ON [PRIMARY]
+GO
+
+ CREATE INDEX [IX_user_registrations_user_id] ON [dbo].[user_registrations]([user_id]) ON [PRIMARY]
+GO
+
+ CREATE INDEX [IX_user_registrations_expires_at] ON [dbo].[user_registrations]([expires_at]) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[users] ADD
+ CONSTRAINT [DF_users_login_failure_count] DEFAULT (0) FOR [login_failure_count],
+ CONSTRAINT [DF_users_state] DEFAULT (1) FOR [state],
+ CONSTRAINT [UC_users_login] UNIQUE NONCLUSTERED
+ (
+ [login]
+ ) ON [PRIMARY]
+GO
+
+ CREATE INDEX [IX_users_login] ON [dbo].[users]([login]) ON [PRIMARY]
+GO
+
+ CREATE INDEX [IX_users_password] ON [dbo].[users]([password]) ON [PRIMARY]
+GO
+
+ALTER TABLE [dbo].[groups] ADD
+ CONSTRAINT [FK_groups_groups_parent] FOREIGN KEY
+ (
+ [parent_id]
+ ) REFERENCES [dbo].[groups] (
+ [id]
+ )
+GO
+
+ALTER TABLE [dbo].[groups_roles] ADD
+ CONSTRAINT [FK_groups_roles_groups] FOREIGN KEY
+ (
+ [group_id]
+ ) REFERENCES [dbo].[groups] (
+ [id]
+ ) ON DELETE CASCADE ,
+ CONSTRAINT [FK_groups_roles_roles] FOREIGN KEY
+ (
+ [role_id]
+ ) REFERENCES [dbo].[roles] (
+ [id]
+ ) ON DELETE CASCADE
+GO
+
+ALTER TABLE [dbo].[groups_users] ADD
+ CONSTRAINT [FK_groups_users_groups] FOREIGN KEY
+ (
+ [group_id]
+ ) REFERENCES [dbo].[groups] (
+ [id]
+ ) ON DELETE CASCADE ,
+ CONSTRAINT [FK_groups_users_users] FOREIGN KEY
+ (
+ [user_id]
+ ) REFERENCES [dbo].[users] (
+ [id]
+ ) ON DELETE CASCADE
+GO
+
+ALTER TABLE [dbo].[roles] ADD
+ CONSTRAINT [FK_roles_roles_parent] FOREIGN KEY
+ (
+ [parent_id]
+ ) REFERENCES [dbo].[roles] (
+ [id]
+ ) NOT FOR REPLICATION
+GO
+
+alter table [dbo].[roles] nocheck constraint [FK_roles_roles_parent]
+GO
+
+ALTER TABLE [dbo].[roles_static_permissions] ADD
+ CONSTRAINT [FK_roles_static_permissions_roles] FOREIGN KEY
+ (
+ [role_id]
+ ) REFERENCES [dbo].[roles] (
+ [id]
+ ) ON DELETE CASCADE ,
+ CONSTRAINT [FK_roles_static_permissions_static_permissions] FOREIGN KEY
+ (
+ [static_permission_id]
+ ) REFERENCES [dbo].[static_permissions] (
+ [id]
+ ) ON DELETE CASCADE
+GO
+
+ALTER TABLE [dbo].[roles_users] ADD
+ CONSTRAINT [FK_roles_users_roles] FOREIGN KEY
+ (
+ [role_id]
+ ) REFERENCES [dbo].[roles] (
+ [id]
+ ) ON DELETE CASCADE ,
+ CONSTRAINT [FK_roles_users_users] FOREIGN KEY
+ (
+ [user_id]
+ ) REFERENCES [dbo].[users] (
+ [id]
+ ) ON DELETE CASCADE
+GO
+
+ALTER TABLE [dbo].[user_registrations] ADD
+ CONSTRAINT [FK_user_registrations_users] FOREIGN KEY
+ (
+ [user_id]
+ ) REFERENCES [dbo].[users] (
+ [id]
+ ) ON DELETE CASCADE ON UPDATE CASCADE
+GO
+
diff --git a/src/api/components/active_rbac/db/create.mysql.sql b/src/api/components/active_rbac/db/create.mysql.sql
new file mode 100644
index 0000000..2ae02c6
--- /dev/null
+++ b/src/api/components/active_rbac/db/create.mysql.sql
@@ -0,0 +1,130 @@
+# [ActiveRBAC 0.1]
+
+# This is database creation SQL script in MySQL dialect.
+
+#----------------------------
+# Table structure for groups
+#----------------------------
+CREATE TABLE `groups` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `created_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ `updated_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ `title` varchar(200) NOT NULL default '',
+ `parent_id` int(10) unsigned default NULL,
+ PRIMARY KEY (`id`),
+ KEY `groups_parent_id_index` (`parent_id`),
+ CONSTRAINT `groups_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `groups` (`id`) ON UPDATE NO ACTION
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+#----------------------------
+# Table structure for roles
+#----------------------------
+CREATE TABLE `roles` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `created_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ `updated_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ `title` varchar(100) NOT NULL default '',
+ `parent_id` int(10) unsigned default NULL,
+ PRIMARY KEY (`id`),
+ KEY `roles_parent_id_index` (`parent_id`),
+ CONSTRAINT `roles_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `roles` (`id`) ON UPDATE NO ACTION
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+#----------------------------
+# Table structure for static_permissions
+#----------------------------
+CREATE TABLE `static_permissions` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `title` varchar(200) NOT NULL default '',
+ `created_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ `updated_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `static_permissions_title_index` (`title`)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+#----------------------------
+# Table structure for users
+#----------------------------
+CREATE TABLE `users` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `created_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ `updated_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ `last_logged_in_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ `login_failure_count` int(10) unsigned NOT NULL default '0',
+ `login` varchar(100) NOT NULL default '',
+ `email` varchar(200) NOT NULL default '',
+ `password` varchar(100) NOT NULL default '',
+ `password_hash_type` varchar(20) NOT NULL default '',
+ `password_salt` char(10) NOT NULL default '1234512345',
+ `state` int(10) unsigned NOT NULL default '1',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `users_login_index` (`login`),
+ KEY `users_password_index` (`password`)
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+#----------------------------
+# Table structure for groups_roles
+#----------------------------
+CREATE TABLE `groups_roles` (
+ `group_id` int(10) unsigned NOT NULL default '0',
+ `role_id` int(10) unsigned NOT NULL default '0',
+ `created_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ UNIQUE KEY `groups_roles_all_index` (`group_id`,`role_id`),
+ KEY `role_id` (`role_id`),
+ CONSTRAINT `groups_roles_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
+ CONSTRAINT `groups_roles_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+#----------------------------
+# Table structure for groups_users
+#----------------------------
+CREATE TABLE `groups_users` (
+ `group_id` int(10) unsigned NOT NULL default '0',
+ `user_id` int(10) unsigned NOT NULL default '0',
+ `created_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ PRIMARY KEY (`group_id`,`user_id`),
+ UNIQUE KEY `groups_users_all_index` (`group_id`,`user_id`),
+ KEY `user_id` (`user_id`),
+ CONSTRAINT `groups_users_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
+ CONSTRAINT `groups_users_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+#----------------------------
+# Table structure for roles_static_permissions
+#----------------------------
+CREATE TABLE `roles_static_permissions` (
+ `role_id` int(10) unsigned NOT NULL default '0',
+ `static_permission_id` int(10) unsigned NOT NULL default '0',
+ `created_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ UNIQUE KEY `roles_static_permissions_all_index` (`static_permission_id`,`role_id`),
+ KEY `role_id` (`role_id`),
+ CONSTRAINT `roles_static_permissions_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
+ CONSTRAINT `roles_static_permissions_ibfk_2` FOREIGN KEY (`static_permission_id`) REFERENCES `static_permissions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+#----------------------------
+# Table structure for roles_users
+#----------------------------
+CREATE TABLE `roles_users` (
+ `user_id` int(10) unsigned NOT NULL default '0',
+ `role_id` int(10) unsigned NOT NULL default '0',
+ `created_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ UNIQUE KEY `roles_users_all_index` (`user_id`,`role_id`),
+ KEY `role_id` (`role_id`),
+ CONSTRAINT `roles_users_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
+) ENGINE=InnoDB CHARACTER SET utf8;
+
+#----------------------------
+# Table structure for user_registrations
+#----------------------------
+CREATE TABLE `user_registrations` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `user_id` int(10) unsigned NOT NULL default '0',
+ `token` text NOT NULL,
+ `created_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ `expires_at` timestamp NOT NULL default '0000-00-00 00:00:00',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `user_registrations_user_id_index` (`user_id`),
+ KEY `user_registrations_expires_at_index` (`expires_at`),
+ CONSTRAINT `user_registrations_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
+) ENGINE=InnoDB CHARACTER SET utf8;
\ No newline at end of file
diff --git a/src/api/components/active_rbac/db/create.postgresql.sql b/src/api/components/active_rbac/db/create.postgresql.sql
new file mode 100644
index 0000000..9173d9e
--- /dev/null
+++ b/src/api/components/active_rbac/db/create.postgresql.sql
@@ -0,0 +1,147 @@
+-- [ActiveRBAC 0.1]
+
+-- This is the database creation SQL script in PostgreSQL dialect. It
+-- has been tested with PostgreSQL 7.4.
+
+CREATE TABLE users (
+ id BIGSERIAL NOT NULL,
+ -- Some statistics about the user data
+ created_at TIMESTAMP NOT NULL,
+ updated_at TIMESTAMP NOT NULL,
+ last_logged_in_at TIMESTAMP NOT NULL,
+ login_failure_count INT NOT NULL,
+ -- Important information: login name, email and encrypted password
+ login CHARACTER VARYING (100) NOT NULL,
+ email CHARACTER VARYING (200) NOT NULL,
+ password CHARACTER VARYING (100) NOT NULL,
+ -- What hashing method did we use to hash the password? SHA-1, MD5, etc.?
+ password_hash_type CHARACTER VARYING (20) NOT NULL,
+ -- The salt used for this password
+ password_salt CHARACTER (10) NOT NULL,
+
+ -- The account's state. The stock types are "1: unconfirmed", "2: confirmed"
+ -- "3: locked", "4: deleted", "4: confirmed, lost password"
+ state INTEGER NOT NULL DEFAULT 1,
+
+ PRIMARY KEY (id),
+ UNIQUE (login)
+);
+
+CREATE INDEX users_login_index ON users (login);
+CREATE INDEX users_password_index ON users (password);
+
+
+-- This table holds the "user registration" data, i.e. the token the
+-- user needs to know to confirm his registration.
+CREATE TABLE user_registrations (
+ id BIGSERIAL NOT NULL, -- superflous, but AR needs it
+ user_id BIGINT NOT NULL,
+ token TEXT NOT NULL,
+ created_at TIMESTAMP NOT NULL,
+ expires_at TIMESTAMP NOT NULL,
+
+ PRIMARY KEY (id),
+ FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
+ UNIQUE (user_id)
+);
+
+CREATE INDEX user_registrations_user_id_index ON user_registrations (user_id);
+CREATE INDEX user_registration_expires_at_index ON user_registrations (expires_at);
+
+
+CREATE TABLE roles (
+ id BIGSERIAL NOT NULL,
+ created_at TIMESTAMP NOT NULL,
+ updated_at TIMESTAMP NOT NULL,
+ title CHARACTER VARYING (100) NOT NULL,
+ parent_id BIGINT NULL,
+
+ PRIMARY KEY (id),
+ UNIQUE(title),
+ FOREIGN KEY (parent_id) REFERENCES roles (id) ON DELETE RESTRICT
+);
+
+CREATE INDEX roles_parent_index ON roles (parent_id);
+
+
+CREATE TABLE roles_users (
+ user_id BIGINT NOT NULL,
+ role_id BIGINT NOT NULL,
+ created_at TIMESTAMP NOT NULL,
+
+ FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
+ FOREIGN KEY (role_id) REFERENCES roles (id) ON DELETE CASCADE,
+
+ UNIQUE (user_id, role_id)
+);
+
+CREATE INDEX roles_users_all_index ON roles_users (user_id, role_id);
+
+
+CREATE TABLE groups (
+ id BIGSERIAL NOT NULL,
+ created_at TIMESTAMP NOT NULL,
+ updated_at TIMESTAMP NOT NULL,
+ title CHARACTER VARYING NOT NULL,
+ parent_id BIGINT NULL,
+
+ PRIMARY KEY (id),
+ UNIQUE (title),
+ FOREIGN KEY (parent_id) REFERENCES groups (id) ON DELETE RESTRICT
+);
+
+CREATE INDEX groups_parent_index ON groups (parent_id);
+
+CREATE TABLE groups_users (
+ group_id BIGINT NOT NULL,
+ user_id BIGINT NOT NULL,
+ created_at TIMESTAMP NOT NULL,
+
+ FOREIGN KEY (group_id) REFERENCES groups (id) ON DELETE CASCADE,
+ FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
+
+ UNIQUE (group_id, user_id)
+);
+
+CREATE INDEX groups_users_all_index ON groups_users (group_id, user_id);
+
+
+CREATE TABLE groups_roles (
+ group_id BIGINT NOT NULL,
+ role_id BIGINT NOT NULL,
+ created_at TIMESTAMP NOT NULL,
+
+ FOREIGN KEY (group_id) REFERENCES groups (id) ON DELETE CASCADE,
+ FOREIGN KEY (role_id) REFERENCES roles (id) ON DELETE CASCADE,
+
+ UNIQUE (group_id, role_id)
+);
+
+CREATE INDEX groups_roles_all_index ON groups_roles (group_id, role_id);
+
+
+CREATE TABLE static_permissions (
+ id BIGSERIAL NOT NULL,
+ title VARCHAR(200) NOT NULL,
+ created_at TIMESTAMP NOT NULL,
+ updated_at TIMESTAMP NOT NULL,
+
+ PRIMARY KEY (id),
+ UNIQUE (title)
+);
+
+CREATE INDEX static_permissions_title_index ON static_permissions (title);
+
+
+CREATE TABLE roles_static_permissions (
+ static_permission_id BIGINT NOT NULL,
+ role_id BIGINT NOT NULL,
+ created_at TIMESTAMP NOT NULL,
+
+ FOREIGN KEY (static_permission_id) REFERENCES static_permissions (id) ON DELETE CASCADE,
+ FOREIGN KEY (role_id) REFERENCES roles (id) ON DELETE CASCADE,
+
+ UNIQUE (static_permission_id, role_id)
+);
+
+CREATE INDEX roles_static_permissions_all_index ON roles_static_permissions (static_permission_id, role_id);
\ No newline at end of file
diff --git a/src/api/components/active_rbac/exceptions.rb b/src/api/components/active_rbac/exceptions.rb
new file mode 100644
index 0000000..69741ca
--- /dev/null
+++ b/src/api/components/active_rbac/exceptions.rb
@@ -0,0 +1,15 @@
+# The RecursionInTree exception is thrown when a group's or role's descendant
+# is assigned as parent.
+class RecursionInTree < ActiveRecord::ActiveRecordError
+end
+
+# The CantDeleteWithChildren exception is thrown when a group or role
+# that still has children is to be destroyed.
+class CantDeleteWithChildren < ActiveRecord::ActiveRecordError
+end
+
+# The MultipleRegistration exception is thrown when create_user_registration
+# is called on a User instance that already has a user_registration record
+# assigned.
+class MultipleRegistrationTokens < ActiveRecord::ActiveRecordError
+end
\ No newline at end of file
diff --git a/src/api/components/active_rbac/group.rb b/src/api/components/active_rbac/group.rb
new file mode 100644
index 0000000..dc67c82
--- /dev/null
+++ b/src/api/components/active_rbac/group.rb
@@ -0,0 +1,135 @@
+require 'exceptions'
+
+# The Group class represents a group record in the database and thus a group
+# in the ActiveRbac model. Groups are arranged in trees and have a title.
+# Groups have an arbitrary number of roles and users assigned to them. Child
+# groups inherit all roles from their parents.
+class Group < ActiveRecord::Base
+ # groups are arranged in a tree
+ acts_as_tree :order => 'title'
+ # groups have a n:m relation to user
+ has_and_belongs_to_many :users, :uniq => true
+ # groups have a n:m relation to groups
+ has_and_belongs_to_many :roles, :uniq => true
+ # we want to protect the parent and user attribute from bulk assigning
+ attr_protected :parent, :users, :roles
+
+ # This method returns the whole inheritance tree upwards, i.e. this group
+ # and all parents as a list.
+ def ancestors_and_self
+ result = [self]
+
+ if parent != nil
+ result << parent.ancestors_and_self
+ end
+
+ return result.flatten
+ end
+
+ # This method returns itself, all children and all children of its children
+ # in a flat list.
+ def descendants_and_self
+ result = [self]
+
+ for child in children
+ result << child.descendants_and_self
+ end
+
+ return result.flatten
+ end
+
+ # This method returns all roles assigned to this group or any of its
+ # ancessors.
+ def all_roles
+ result = []
+
+ self.roles.each do |role|
+ result << role.ancestors_and_self
+ end
+
+ result << parent.all_roles unless parent.nil?
+
+ result.flatten!
+ result.uniq!
+
+ return result
+ end
+
+ # This method returns all users that have been assigned to this role. It
+ # will all users directly assigned to this group and all users assigned to
+ # children of this group.
+ def all_users
+ result = []
+
+ self.descendants_and_self.each { |group| result << group.users }
+
+ result.flatten!
+ result.uniq!
+
+ return result
+ end
+
+ # This method returns all permission granted to this group by its roles or
+ # its parents.
+ def all_static_permissions
+ result = []
+
+ self.all_roles.each { |role| result << role.all_static_permissions }
+
+ result.flatten!
+ result.uniq!
+
+ return result
+ end
+
+ # We're overriding "parent=" below. So we alias the one from the acts_as_tree
+ # mixin to "old_parent=".
+ alias_method :old_parent=, :parent=
+
+ # We protect the parent attribute here. If a group is given as a parent, that
+ # is a descendant from this group, we raise a RecursionInTree error and stop
+ # assignment.
+ def parent=(value)
+ if descendants_and_self.include?(value)
+ raise RecursionInTree, "Trying to set parent to descendant", caller
+ else
+ self.old_parent = value
+ end
+ end
+
+ # This method blocks destroying a role if it still has children. This method
+ # raises a CantDeleteWithChildren exception if this error occurs. It is an
+ # ActiveRecord event hook.
+ def before_destroy
+ raise CantDeleteWithChildren unless children.empty?
+ end
+
+ # Overriding this method to make "title" visible as "Name". This is called in
+ # forms to create error messages.
+ def human_attribute_name (attr)
+ return case attr
+ when 'title' then 'Name'
+ else super.human_attribute_name attr
+ end
+ end
+
+ protected
+
+ # We want to validate a group's title pretty thoroughly.
+ validates_uniqueness_of :title,
+ :message => 'is the name of an already existing group.'
+ validates_format_of :title,
+ :with => %r{^[\w \$\^\-\.#\*\+&'"]*$},
+ :message => 'must not contain invalid characters.'
+ validates_length_of :title,
+ :in => 2..100, :allow_nil => true,
+ :too_long => 'must have less than 100 characters.',
+ :too_short => 'must have more than two characters.',
+ :allow_nil => false
+
+ # Implement ActiveRecords' validate method here to enforce that parents in
+ # tree are actually groups.
+ def validate
+ errors.add(:parent, "must be a valid group.") unless parent.instance_of? Group or parent.nil?
+ end
+end
diff --git a/src/api/components/active_rbac/group/_form.rhtml b/src/api/components/active_rbac/group/_form.rhtml
new file mode 100644
index 0000000..8914cfd
--- /dev/null
+++ b/src/api/components/active_rbac/group/_form.rhtml
@@ -0,0 +1,44 @@
+<%= error_messages_for 'group' %>
+
+<!--[form:group]-->
+<dl>
+ <dt><label for="group_title">Group's Name</label></dt>
+ <dd><%= text_field 'group', 'title' %></dd>
+
+ <dt><label>Group's Parent</label></dt>
+ <dd>
+ <% unless @group.errors[:parent].nil? %><div class="fieldWithErrors"><% end %>
+ <ul class="groupTree">
+ <li>
+ <% if @group.parent.nil? %>
+ <input id="group_parent_self" type="radio" name="group[parent]" value="" checked="checked" />
+ <% else %>
+ <input id="group_parent_self" type="radio" name="group[parent]" value="" />
+ <% end %>
+ <label for="group_parent_self">no parent (direct root child)</label>
+ <%= groups = Group.find_all
+ groups.delete_if { |r| @group.descendants_and_self.include?(r) }
+ node_tree(groups) do |group|
+ result = " " if @group.parent == group
+ result = " " if @group.parent != group
+
+ result += "