├── test ├── __init__.py ├── test_all.py ├── test_doctests.py ├── bug_239238.py ├── webtest.py └── test_dbstore.py ├── .gitignore ├── infogami ├── core │ ├── __init__.py │ ├── i18n │ │ ├── type │ │ │ ├── page │ │ │ │ └── strings.en │ │ │ ├── template │ │ │ │ └── strings.en │ │ │ ├── i18n │ │ │ │ └── strings.en │ │ │ ├── macro │ │ │ │ └── strings.en │ │ │ ├── property │ │ │ │ └── strings.en │ │ │ ├── user │ │ │ │ └── strings.en │ │ │ └── type │ │ │ │ └── strings.en │ │ ├── mode │ │ │ ├── view │ │ │ │ └── strings.en │ │ │ ├── history │ │ │ │ └── strings.en │ │ │ ├── diff │ │ │ │ └── strings.en │ │ │ └── edit │ │ │ │ └── strings.en │ │ ├── macros │ │ │ └── RecentChanges │ │ │ │ └── strings.en │ │ ├── account │ │ │ ├── forgot_password │ │ │ │ └── strings.en │ │ │ ├── login │ │ │ │ └── strings.en │ │ │ ├── register │ │ │ │ └── strings.en │ │ │ └── preferences │ │ │ │ └── strings.en │ │ ├── strings.en │ │ └── utils │ │ │ └── date │ │ │ └── strings.en │ ├── templates │ │ ├── reset_password.html │ │ ├── type │ │ │ ├── page │ │ │ │ ├── view.html │ │ │ │ └── edit.html │ │ │ ├── property │ │ │ │ ├── repr.html │ │ │ │ └── input.html │ │ │ ├── text │ │ │ │ ├── input.html │ │ │ │ └── diff.html │ │ │ ├── backreference │ │ │ │ ├── repr.html │ │ │ │ └── input.html │ │ │ ├── type │ │ │ │ └── input.html │ │ │ ├── user │ │ │ │ └── view.html │ │ │ ├── rawtext │ │ │ │ └── view.html │ │ │ └── boolean │ │ │ │ └── input.html │ │ ├── deleted.html │ │ ├── notfound.html │ │ ├── recentchanges.html │ │ ├── passwordsent.html │ │ ├── login_preferences.html │ │ ├── permission_denied.html │ │ ├── register.html │ │ ├── forgot_password.html │ │ ├── default_repr.html │ │ ├── preferences.html │ │ ├── permission.html │ │ ├── login.html │ │ ├── editpage.html │ │ ├── viewpage.html │ │ ├── password_mailer.html │ │ ├── default_diff.html │ │ ├── default_input.html │ │ ├── default_view.html │ │ ├── feed.html │ │ ├── diff.html │ │ ├── history.html │ │ ├── site.html │ │ ├── sitepreferences.html │ │ └── default_edit.html │ ├── files │ │ ├── indicator.gif │ │ ├── js │ │ │ ├── repetition │ │ │ │ ├── readme.txt │ │ │ │ ├── repetition-model-msie_init.js │ │ │ │ └── repetition-model-wrapper.js │ │ │ ├── autocomplete.js │ │ │ └── jquery │ │ │ │ ├── jquery.bgiframe.min.js │ │ │ │ └── jquery.dimensions.pack.js │ │ ├── jquery.autocomplete.css │ │ ├── style.css │ │ └── diff.css │ ├── macros │ │ ├── Hello.html │ │ ├── PageList.html │ │ ├── TypeChanger.html │ │ ├── ThingReference.html │ │ └── RecentChanges.html │ ├── pages │ │ ├── type.page │ │ ├── pagelist.page │ │ └── __root__.page │ ├── types │ │ ├── page.type │ │ └── rawtext.type │ ├── diff.py │ ├── db.py │ ├── forms.py │ ├── dbupgrade.py │ └── helpers.py ├── plugins │ ├── __init__.py │ ├── links │ │ ├── __init__.py │ │ ├── templates │ │ │ └── backlinks.html │ │ ├── code.py │ │ ├── db.py │ │ └── view.py │ ├── review │ │ ├── __init__.py │ │ ├── templates │ │ │ ├── parallel_modification.html │ │ │ ├── review.html │ │ │ └── changes.html │ │ ├── i18n │ │ │ └── strings.en │ │ ├── db.py │ │ ├── view.py │ │ └── code.py │ ├── wikitemplates │ │ ├── __init__.py │ │ ├── templates │ │ │ ├── type │ │ │ │ ├── macro │ │ │ │ │ └── view.html │ │ │ │ └── template │ │ │ │ │ ├── view.html │ │ │ │ │ └── edit.html │ │ │ └── template_preferences.html │ │ ├── pages │ │ │ ├── macros.page │ │ │ └── templates.page │ │ ├── types │ │ │ ├── macro.type │ │ │ └── template.type │ │ ├── forms.py │ │ └── db.py │ ├── api │ │ └── __init__.py │ ├── i18n │ │ ├── __init__.py │ │ ├── types │ │ │ └── i18n.type │ │ ├── templates │ │ │ ├── type │ │ │ │ └── i18n │ │ │ │ │ ├── view.html │ │ │ │ │ └── edit.html │ │ │ └── i18n.html │ │ ├── db.py │ │ └── code.py │ └── pages │ │ └── __init__.py ├── utils │ ├── __init__.py │ ├── markdown │ │ └── __init__.py │ ├── types.py │ ├── context.py │ ├── tests │ │ └── test_app.py │ ├── flash.py │ ├── stats.py │ ├── features.py │ └── storage.py ├── infobase │ ├── tests │ │ ├── __init__.py │ │ ├── test_server.py │ │ ├── test_seq.py │ │ ├── test_doctests.py │ │ ├── pytest_wildcard.py │ │ ├── utils.py │ │ ├── test_logreader.py │ │ ├── test_account.py │ │ └── test_writequery.py │ ├── _dbstore │ │ ├── __init__.py │ │ ├── sequence.py │ │ ├── indexer.py │ │ ├── schema.py │ │ └── schema.sql │ ├── config.py │ ├── __init__.py │ ├── _json.py │ ├── multiple_insert.py │ ├── logger.py │ ├── utils.py │ └── cache.py ├── conftest.py ├── config.py └── __init__.py ├── requirements.txt ├── migration └── Readme.txt ├── tests ├── __init__.py ├── Readme.md ├── test_doctests.py └── test_infogami │ ├── test_account.py │ ├── __init__.py │ └── test_pages.py ├── requirements_test.txt ├── .github ├── dependabot.yml └── workflows │ ├── openlibrary_tests.yml │ └── python_tests.yml ├── sample_infogami.yml ├── scripts ├── _init_path.py ├── run_python_linters.sh ├── run_python_tests.sh ├── pytests_failing_on_py2_and_py3.sh ├── server ├── infobase_server ├── pytests_failing_on_py3_only.sh ├── run_doctests.sh └── test ├── sample_infobase.yml ├── setup.py ├── .git-blame-ignore-revs ├── sample_run.py ├── pyproject.toml └── README.md /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /infogami/core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infogami/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infogami/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infogami/infobase/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infogami/infobase/tests/test_server.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infogami/plugins/links/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infogami/plugins/review/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | markdown 2 | requests 3 | simplejson 4 | web.py 5 | -------------------------------------------------------------------------------- /infogami/core/i18n/type/page/strings.en: -------------------------------------------------------------------------------- 1 | body = 'Body' 2 | title = 'Title' -------------------------------------------------------------------------------- /infogami/core/i18n/type/template/strings.en: -------------------------------------------------------------------------------- 1 | body = 'Body' 2 | title = 'Title' -------------------------------------------------------------------------------- /infogami/infobase/_dbstore/__init__.py: -------------------------------------------------------------------------------- 1 | """DB engine for infobase. 2 | """ 3 | -------------------------------------------------------------------------------- /infogami/plugins/api/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Infogami read/write API. 3 | """ 4 | -------------------------------------------------------------------------------- /infogami/utils/markdown/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Markdown extensions. 3 | """ 4 | -------------------------------------------------------------------------------- /infogami/core/i18n/type/i18n/strings.en: -------------------------------------------------------------------------------- 1 | add_new_key = 'Add new key' 2 | add = 'Add' -------------------------------------------------------------------------------- /infogami/plugins/i18n/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Internationalization support. 3 | """ 4 | -------------------------------------------------------------------------------- /infogami/core/i18n/type/macro/strings.en: -------------------------------------------------------------------------------- 1 | macro = 'Macro' 2 | description = 'Description' -------------------------------------------------------------------------------- /migration/Readme.txt: -------------------------------------------------------------------------------- 1 | 2 | Data migration scripts from one version of Infogami to other. 3 | 4 | -------------------------------------------------------------------------------- /infogami/plugins/pages/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Plugin to push and pull pages from infogami. 3 | """ 4 | -------------------------------------------------------------------------------- /infogami/core/i18n/mode/view/strings.en: -------------------------------------------------------------------------------- 1 | edit = 'Edit' 2 | last_modified = 'Last Modified' 3 | history = 'History' -------------------------------------------------------------------------------- /infogami/core/templates/reset_password.html: -------------------------------------------------------------------------------- 1 | $def with (f) 2 | 3 |
4 | $:f.render() 5 |
6 | -------------------------------------------------------------------------------- /infogami/core/files/indicator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetarchive/infogami/HEAD/infogami/core/files/indicator.gif -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # insert current dir to path to import web and infogami 4 | sys.path.insert(0, ".") 5 | -------------------------------------------------------------------------------- /infogami/core/templates/type/page/view.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $var title: $page.title 4 | 5 |

$:format(page.body)

6 | -------------------------------------------------------------------------------- /requirements_test.txt: -------------------------------------------------------------------------------- 1 | -r requirements.txt 2 | black 3 | codespell 4 | mypy 5 | psycopg2 6 | pytest 7 | ruff==0.7.3 8 | setuptools 9 | -------------------------------------------------------------------------------- /infogami/core/macros/Hello.html: -------------------------------------------------------------------------------- 1 | $def with (name="World", times=1) 2 | 3 | $for i in range(times): 4 | Hello, $name!
5 | -------------------------------------------------------------------------------- /infogami/core/i18n/type/property/strings.en: -------------------------------------------------------------------------------- 1 | is_unique = 'Unique' 2 | type = 'Expected type' 3 | description = 'Description' 4 | name = 'Name' -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/templates/type/macro/view.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $var title: $page.description 4 | 5 |
$page.macro
6 | -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/templates/type/template/view.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $var title: $page.title 4 | 5 |
$page.body
6 | -------------------------------------------------------------------------------- /infogami/core/i18n/mode/history/strings.en: -------------------------------------------------------------------------------- 1 | compare = 'Compare' 2 | edit = 'Edit' 3 | who = 'Who' 4 | when = 'When' 5 | history = 'History' 6 | view = 'View' -------------------------------------------------------------------------------- /infogami/core/templates/type/property/repr.html: -------------------------------------------------------------------------------- 1 | $def with (p, property=None) 2 | ${p.name}${(p.unique and " ") or []} of type $:thingrepr(p.expected_type) 3 | -------------------------------------------------------------------------------- /infogami/core/templates/type/text/input.html: -------------------------------------------------------------------------------- 1 | $def with (value, property) 2 | 3 | -------------------------------------------------------------------------------- /tests/Readme.md: -------------------------------------------------------------------------------- 1 | # Infogami test suite 2 | 3 | How to setup: 4 | 5 | TODO 6 | 7 | How to run all tests: 8 | 9 | $ functest tests/ 10 | -------------------------------------------------------------------------------- /infogami/core/i18n/type/user/strings.en: -------------------------------------------------------------------------------- 1 | users_activity = "%s's wiki activity" 2 | displayname = 'Display Name' 3 | description = 'Description' 4 | email = 'E-Mail' -------------------------------------------------------------------------------- /infogami/plugins/review/templates/parallel_modification.html: -------------------------------------------------------------------------------- 1 | $def with () 2 | 3 | $_.REVIEW_FAILED_ERROR 4 | 5 | Go to $_.UNREVIEWED_CHANGES. 6 | -------------------------------------------------------------------------------- /infogami/core/pages/type.page: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/type', 3 | 'type': {'key': '/type/page'}, 4 | 'title': 'Types', 5 | 'body': '{{PageList("/type")}}' 6 | } 7 | 8 | -------------------------------------------------------------------------------- /infogami/core/templates/type/backreference/repr.html: -------------------------------------------------------------------------------- 1 | $def with (p, property=None) 2 | $p.name - back-reference to $p.property_name property of $:thingrepr(p.expected_type) 3 | 4 | -------------------------------------------------------------------------------- /infogami/core/pages/pagelist.page: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/pagelist', 3 | 'type': {'key': '/type/page'}, 4 | 'title': 'Page List', 5 | 'body': '{{PageList("/")}}' 6 | } 7 | 8 | -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/pages/macros.page: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/macros', 3 | 'type': '/type/page', 4 | 'title': 'Macros', 5 | 'body': '{{PageList("/macros")}}' 6 | } 7 | 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "13:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /infogami/core/templates/deleted.html: -------------------------------------------------------------------------------- 1 | $var title: 2 | 3 |

This page no longer exists. 4 |

5 | 6 | [create] 7 | [history] 8 | -------------------------------------------------------------------------------- /infogami/core/files/js/repetition/readme.txt: -------------------------------------------------------------------------------- 1 | - Latest version, 2 | - implementation details, 3 | - usage information 4 | - and a test suite 5 | found at -------------------------------------------------------------------------------- /infogami/core/i18n/type/type/strings.en: -------------------------------------------------------------------------------- 1 | properties = 'Properties' 2 | backreferences = 'Back-references' 3 | name = 'Name' 4 | is_primitive = 'Is this a primitive type?' 5 | description = 'Description' -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/pages/templates.page: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/templates', 3 | 'type': '/type/page', 4 | 'title': 'Templates', 5 | 'body': '{{PageList("/templates")}}' 6 | } 7 | 8 | -------------------------------------------------------------------------------- /sample_infogami.yml: -------------------------------------------------------------------------------- 1 | 2 | db_parameters: 3 | engine: "postgres" 4 | database: "infogami" 5 | username: "anand" 6 | password: "" 7 | 8 | plugins: 9 | - links 10 | - api 11 | -------------------------------------------------------------------------------- /scripts/_init_path.py: -------------------------------------------------------------------------------- 1 | """Utility to setup sys.path.""" 2 | 3 | import sys 4 | from pathlib import Path 5 | 6 | INFOGAMI_PATH = str(Path(__file__).resolve().parent.parent) 7 | sys.path.insert(0, INFOGAMI_PATH) 8 | -------------------------------------------------------------------------------- /infogami/core/i18n/macros/RecentChanges/strings.en: -------------------------------------------------------------------------------- 1 | recent_changes = 'Recent Changes' 2 | what = 'What' 3 | edit = 'edit' 4 | who = 'Who' 5 | when = 'When' 6 | actions = 'Actions' 7 | path = 'Path' 8 | diff = 'diff' 9 | view = 'view' -------------------------------------------------------------------------------- /infogami/core/templates/notfound.html: -------------------------------------------------------------------------------- 1 | $def with (path, create = True) 2 | 3 | $var title: $path 4 | 5 |

6 | $_.page_does_not_exist. 7 | $if create: 8 | $_.create 9 |

10 | -------------------------------------------------------------------------------- /infogami/core/templates/type/type/input.html: -------------------------------------------------------------------------------- 1 | $def with (value, property) 2 | 3 | $ regular = property.get('kind') == "regular" 4 | $ key = value.get('key') 5 | $:Dropdown(property.name, [""] + get_types(regular=regular), value=key or "").render() 6 | -------------------------------------------------------------------------------- /infogami/core/templates/recentchanges.html: -------------------------------------------------------------------------------- 1 | $def with () 2 | 3 | $var title: Recent Changes 4 | 5 | $ type = query_param('type', None) 6 | $ author = query_param('author', None) 7 | 8 | $:macros.RecentChanges(author=author, type=type) 9 | 10 | -------------------------------------------------------------------------------- /test/test_all.py: -------------------------------------------------------------------------------- 1 | from test import webtest 2 | 3 | 4 | def suite(): 5 | modules = ["test_doctests", "test_dbstore", "test_infobase"] 6 | return webtest.suite(modules) 7 | 8 | 9 | if __name__ == "__main__": 10 | webtest.main() 11 | -------------------------------------------------------------------------------- /infogami/core/templates/passwordsent.html: -------------------------------------------------------------------------------- 1 | $def with (email) 2 | 3 | $var title: Forgot password 4 | 5 | We have sent an email to $email with instructions to reset password. 6 | Please check your email and follow the instructions to reset your password. 7 | 8 | -------------------------------------------------------------------------------- /infogami/core/i18n/mode/diff/strings.en: -------------------------------------------------------------------------------- 1 | added = 'Added' 2 | unmodified = 'Unmodified' 3 | differences = 'Differences' 4 | modified = 'Modified' 5 | diff_title = 'Differences of %s' 6 | diff = 'Diff' 7 | removed = 'Removed' 8 | legend = 'Legend' 9 | revision = 'Revision' -------------------------------------------------------------------------------- /infogami/core/templates/login_preferences.html: -------------------------------------------------------------------------------- 1 | $def with (form) 2 | 3 | $var title: $_.get('account/preferences', 'login_preferences') 4 | 5 |
6 | $:form.render() 7 | 8 |
9 | -------------------------------------------------------------------------------- /infogami/plugins/i18n/types/i18n.type: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/type/i18n', 3 | 'type': {'key': '/type/type'}, 4 | 'name': 'i18n strings', 5 | 'description': 'Type for storing internationalization strings', 6 | 'kind': 'regular', 7 | 'properties': [] 8 | } 9 | 10 | -------------------------------------------------------------------------------- /infogami/conftest.py: -------------------------------------------------------------------------------- 1 | collect_ignore = ['failing'] 2 | 3 | 4 | def pytest_addoption(parser): 5 | parser.addoption("--runall", action="store_true", default=False) 6 | 7 | 8 | def pytest_configure(config): 9 | if config.getvalue("runall"): 10 | collect_ignore[:] = [] 11 | -------------------------------------------------------------------------------- /infogami/core/i18n/account/forgot_password/strings.en: -------------------------------------------------------------------------------- 1 | forgot_password = 'Forgot Password' 2 | email_not_registered = 'This email address is not registered.' 3 | forgot_password_statement = 'Please enter your email address. We will generate a new password and email it to you. ' 4 | email = 'E-Mail' -------------------------------------------------------------------------------- /infogami/core/templates/permission_denied.html: -------------------------------------------------------------------------------- 1 | $def with (path, error) 2 | 3 | $var title: Permission Denied 4 | 5 | $error 6 | 7 |

8 | 9 | $if not ctx.user: 10 | You may Login if you have the required permissions. 11 | -------------------------------------------------------------------------------- /infogami/plugins/links/templates/backlinks.html: -------------------------------------------------------------------------------- 1 | $def with (pages) 2 | 3 | $var title: $_.BACKLINKS 4 | 5 |

[$_.VIEW][$_.EDIT]

6 | 7 | 11 | -------------------------------------------------------------------------------- /infogami/core/templates/register.html: -------------------------------------------------------------------------------- 1 | $def with (f) 2 | 3 | $ _ = i18n.get_namespace('/account/register') 4 | 5 | $var title: $_.create_new_account 6 | 7 |
8 | $:f.render() 9 | 10 |
11 | -------------------------------------------------------------------------------- /infogami/core/templates/forgot_password.html: -------------------------------------------------------------------------------- 1 | $def with (f) 2 | 3 | $ _ = i18n.get_namespace('/account/forgot_password') 4 | 5 | $var title: $_.forgot_password 6 | 7 | $_.forgot_password_statement 8 | 9 |
10 | $:f.render()
11 | 12 |
13 | -------------------------------------------------------------------------------- /infogami/core/templates/type/user/view.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $var title: $page.displayname 4 | 5 |

$:format(page.description)

6 | 7 |
8 | 9 | $_.get('/type/user', 'users_activity')(page.displayname): 10 |

11 | $:macros.RecentChanges(author=page, limit=10) 12 |

13 | -------------------------------------------------------------------------------- /infogami/plugins/i18n/templates/type/i18n/view.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $var title: strings 4 | 5 | 6 | $ lang = page.key.split('.')[-1] 7 | $ namespace = find_i18n_namespace(page.key) 8 | 9 | $for key in _.getkeys(namespace, lang): 10 | 11 |
$key$page.get('string_' + key, '-')
12 | -------------------------------------------------------------------------------- /infogami/plugins/review/templates/review.html: -------------------------------------------------------------------------------- 1 | $def with (path, diff, a, b, c) 2 | 3 | $var title: $_.REVIEW $path 4 | 5 |

6 |

7 | 8 | 9 |
10 |

11 | 12 | $:diff 13 | -------------------------------------------------------------------------------- /infogami/plugins/review/i18n/strings.en: -------------------------------------------------------------------------------- 1 | 2 | UNREVIEWED_CHANGES = "Unreviewed Changes" 3 | PATH = "path" 4 | REVIEWED = "Reviewed" 5 | LATEST = "Latest" 6 | REVIEW = "Review" 7 | NO_NEW_CHANGES_TO_REVIEW = "No new changes to review." 8 | 9 | REVIEW_FAILED_ERROR = "Sorry, someone made a change to the page while you were reviewing." 10 | -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/templates/template_preferences.html: -------------------------------------------------------------------------------- 1 | $def with (form) 2 | 3 | $ _ = i18n.get_namespace('/account/preferences') 4 | 5 | $var title: $_.template_preferences 6 | 7 |
8 | $:form.render() 9 | 10 |
11 | -------------------------------------------------------------------------------- /infogami/core/i18n/strings.en: -------------------------------------------------------------------------------- 1 | page_does_not_exist = 'This page does not exist' 2 | preferences = 'Preferences' 3 | create = 'Create' 4 | logout = 'Log out' 5 | welcome_user = 'Welcome %s!' 6 | site_title = 'Infogami' 7 | login = 'Log in ' 8 | powered_by_infogami = 'Powered by Infogami' 9 | site_subtitle = '' 10 | -------------------------------------------------------------------------------- /infogami/core/i18n/account/login/strings.en: -------------------------------------------------------------------------------- 1 | username = 'Username' 2 | remember_me = 'Remember me' 3 | forgot_password = 'Forgot your username or password?' 4 | create_new_account = "Otherwise, create a new account -- it just takes a second." 5 | login = 'Log in' 6 | password = 'Password' 7 | login_stmt = 'If you already have an account, log in' -------------------------------------------------------------------------------- /infogami/core/templates/type/rawtext/view.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $var title: $page.title 4 | 5 | $ format = query_param('format') 6 | $if format == 'raw': 7 | $var content_type: $page.content_type 8 | $var rawtext: $page.body 9 | $else: 10 |
View as rawtext.
11 |
$page.body
12 | -------------------------------------------------------------------------------- /scripts/run_python_linters.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Used for GitHub Actions 3 | set -e -v 4 | 5 | # Run linters and formatters 6 | black --skip-string-normalization . 7 | codespell \ 8 | --exclude-file=infogami/core/files/js/repetition/repetition-model.js 9 | ruff check . # See pyproject.toml for args 10 | mypy --install-types --non-interactive . 11 | -------------------------------------------------------------------------------- /infogami/core/i18n/account/register/strings.en: -------------------------------------------------------------------------------- 1 | confirm_password = 'Confirm Password' 2 | username = 'Username' 3 | display_name = 'Display Name' 4 | register = 'Register' 5 | username_already_exists = 'Username already exists' 6 | create_new_account = 'Create A New Account' 7 | passwords_did_not_match = 'Passwords did not match' 8 | password = 'Password' 9 | email = 'E-Mail' -------------------------------------------------------------------------------- /infogami/core/pages/__root__.page: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/', 3 | 'type': {'key': '/type/page'}, 4 | 'title': 'Welcome', 5 | 'body': 'Infogami is a free, easy-to-use, structured wiki.\n' 6 | 'Visit [Infogami Developer Site](http://infogami.org/dev/) for more details.\n\n' 7 | '* [[pagelist]]\n' 8 | '* [[recentchanges]]\n' 9 | } 10 | -------------------------------------------------------------------------------- /scripts/run_python_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Used for GitHub Actions 3 | set -e 4 | 5 | # web.py needs to find the database on a host named postgres 6 | echo "127.0.0.1 postgres" | sudo tee -a /etc/hosts 7 | # MUST have a --host= 8 | psql --host=postgres --command='create database infobase_test;' 9 | 10 | # Run tests 11 | pytest infogami -s 12 | pytest tests 13 | pytest test 14 | -------------------------------------------------------------------------------- /infogami/core/i18n/mode/edit/strings.en: -------------------------------------------------------------------------------- 1 | save = 'Save' 2 | edit_title = 'Edit %s' 3 | add_property = 'Add %s' 4 | view = 'View' 5 | history = 'History' 6 | move_down = 'Move up' 7 | page_type = 'Page Type' 8 | edit_summary = 'Edit Summary (briefly describe the changes you have made):' 9 | move_up = 'Move down' 10 | preview = 'Preview' 11 | change = 'Change' 12 | delete = 'Delete' -------------------------------------------------------------------------------- /infogami/core/templates/default_repr.html: -------------------------------------------------------------------------------- 1 | $def with (thing, property=None) 2 | $if thing.is_primitive: $thing.value 3 | $elif thing.type.kind == 'embeddable' or thing.key is None: 4 | 5 | $for k in thing: 6 | 7 | 8 | 9 | 10 |
$k$:thingrepr(thing[k])
11 | $else: $thing.key 12 | 13 | -------------------------------------------------------------------------------- /infogami/core/templates/preferences.html: -------------------------------------------------------------------------------- 1 | $def with (preferences) 2 | 3 | $ _ = i18n.get_namespace('/account/preferences') 4 | 5 | $var title: $_.preferences 6 | 7 |
8 | $_.users_preferences(ctx.user.displayname) 9 |
10 | 11 |
    12 | $for title, href in preferences: 13 |
  • $title
  • 14 |
15 | -------------------------------------------------------------------------------- /infogami/core/templates/permission.html: -------------------------------------------------------------------------------- 1 | $def with (p) 2 | 3 | $var title: Permission of $p.key 4 | 5 |
6 | Permission: $:thinginput(p.permission, expected_type="/type/permission", name="permission")
7 | Child Permission: $:thinginput(p.child_permission, expected_type="/type/permission", name="child_permission")
8 | 9 |
10 | -------------------------------------------------------------------------------- /infogami/plugins/i18n/db.py: -------------------------------------------------------------------------------- 1 | import web 2 | 3 | 4 | def get_all_strings(site): 5 | t = site.get('/type/i18n') 6 | if t is None: 7 | return [] 8 | else: 9 | q = {'type': '/type/i18n', 'limit': 1000} 10 | return site.get_many(site.things(q)) 11 | 12 | 13 | def get_all_sites(): 14 | if web.ctx.site.exists(): 15 | return [web.ctx.site] 16 | else: 17 | return [] 18 | -------------------------------------------------------------------------------- /test/test_doctests.py: -------------------------------------------------------------------------------- 1 | """Run all doctests in infogami. 2 | """ 3 | 4 | from test import webtest 5 | 6 | 7 | def suite(): 8 | modules = [ 9 | "infogami.infobase.common", 10 | "infogami.infobase.readquery", 11 | "infogami.infobase.writequery", 12 | "infogami.infobase.dbstore", 13 | ] 14 | return webtest.doctest_suite(modules) 15 | 16 | 17 | if __name__ == "__main__": 18 | webtest.main() 19 | -------------------------------------------------------------------------------- /infogami/core/files/js/repetition/repetition-model-msie_init.js: -------------------------------------------------------------------------------- 1 | //Loaded dynamically in MSIE by script[defer] tag which emulated DOMContentLoaded event. See 2 | if(!window.RepetitionElement) 3 | throw Error("Repetition Model error: You must include the file 'repetition-model.js' to enable the functionality. The file you included is loaded dynamically for MSIE."); 4 | RepetitionElement._init_document(); -------------------------------------------------------------------------------- /infogami/core/templates/login.html: -------------------------------------------------------------------------------- 1 | $def with (f) 2 | 3 | $ _ = i18n.get_namespace('/account/login') 4 | 5 | $var title: $_.login 6 | 7 |

$_.login_stmt

8 | 9 |
10 | $:f.render() 11 | 12 |
13 | 14 |

($_.forgot_password)

15 | 16 |

$:_.create_new_account(homepath() + "/account/register")

17 | -------------------------------------------------------------------------------- /infogami/core/i18n/account/preferences/strings.en: -------------------------------------------------------------------------------- 1 | confirm_password = 'Confirm Password' 2 | login_preferences = 'Login Preferences' 3 | new_password = 'New Password' 4 | template_root = 'Template Root' 5 | current_password = 'Current Password' 6 | template_preferences = 'Template Preferences' 7 | users_preferences = "%s's Preferences" 8 | passwords_did_not_match = 'Passwords did not match' 9 | save = 'Save' 10 | incorrect_password = 'Incorrect password' 11 | preferences = ' Preferences' -------------------------------------------------------------------------------- /infogami/core/macros/PageList.html: -------------------------------------------------------------------------------- 1 | $def with (path="", limit=50) 2 | 3 | $ page = safeint(query_param("page", "0")) 4 | $ pages = list_pages(path, limit=limit, offset=page * limit) 5 | 6 |
    7 | $for p in pages: 8 |
  • $p.key
  • 9 |
10 | 11 |
12 | $if page != 0: 13 | ← Prev 14 | 15 | $if len(pages) == limit: 16 | ... Next → 17 |
18 | -------------------------------------------------------------------------------- /infogami/core/types/page.type: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/type/page', 3 | 'type': {'key': '/type/type'}, 4 | 'name': 'Page', 5 | 'kind': 'regular', 6 | 'properties': [{ 7 | 'name': 'title', 8 | 'type': {'key': '/type/property'}, 9 | 'expected_type': {'key': '/type/string'}, 10 | 'unique': True 11 | }, { 12 | 'name': 'body', 13 | 'type': {'key': '/type/property'}, 14 | 'expected_type': {'key': '/type/text'}, 15 | 'unique': True 16 | }] 17 | } 18 | -------------------------------------------------------------------------------- /infogami/core/templates/editpage.html: -------------------------------------------------------------------------------- 1 | $def with (page, preview=False) 2 | 3 | $ _ = i18n.get_namespace('/mode/edit') 4 | 5 |
6 | $_.view 7 | $_.history 8 |
9 | 10 | $if preview: 11 |
12 | $:thingview(page) 13 |
14 | 15 |
16 | 17 | $ edit = thingedit(page) 18 | 19 | $var title: $edit.title 20 | 21 | $:edit 22 |
23 | 24 | -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/types/macro.type: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/type/macro', 3 | 'type': {'key': '/type/type'}, 4 | 'name': 'Macro', 5 | 'kind': 'regular', 6 | 'properties': [{ 7 | 'name': 'macro', 8 | 'type': {'key': '/type/property'}, 9 | 'expected_type': {'key': '/type/text'}, 10 | 'unique': True 11 | }, { 12 | 'name': 'description', 13 | 'type': {'key': '/type/property'}, 14 | 'expected_type': {'key': '/type/string'}, 15 | 'unique': True 16 | }] 17 | } 18 | 19 | -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/types/template.type: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/type/template', 3 | 'type': {'key': '/type/type'}, 4 | 'name': 'Template', 5 | 'kind': 'regular', 6 | 'properties': [{ 7 | 'name': 'title', 8 | 'type': {'key': '/type/property'}, 9 | 'expected_type': {'key': '/type/string'}, 10 | 'unique': True 11 | }, { 12 | 'name': 'body', 13 | 'type': {'key': '/type/property'}, 14 | 'expected_type': {'key': '/type/text'}, 15 | 'unique': True 16 | }] 17 | } 18 | 19 | -------------------------------------------------------------------------------- /sample_infobase.yml: -------------------------------------------------------------------------------- 1 | ## infobase configuration 2 | 3 | db_parameters: 4 | host: localhost 5 | name: infobase 6 | user: joe 7 | password: secret 8 | 9 | ## secret_key used in encrypting user passwords 10 | # secret_key: my-secret-key 11 | 12 | ## query timeout in milli sec. 13 | query_timeout: 60000 14 | 15 | cache_size: 1000 16 | 17 | ## Additional python path. will be added to python sys.path 18 | # python_path: 19 | # - /addition/path1 20 | 21 | ## plugins 22 | # plugins: 23 | # - plugin1 24 | 25 | bind_address: 26 | port: 8080 27 | fastcgi: false 28 | -------------------------------------------------------------------------------- /infogami/core/templates/type/boolean/input.html: -------------------------------------------------------------------------------- 1 | $def with (value, property) 2 | 3 | $# when checkbox is not selected, browser doesn't send any value to the server. 4 | $# Adding a hidden field sends false value when checkbox is not selected 5 | $# and 2 values when checkbox is selected and the server takes only the latter value. 6 | 7 | 8 | $if value.value: 9 | 10 | $else: 11 | 12 | -------------------------------------------------------------------------------- /infogami/utils/types.py: -------------------------------------------------------------------------------- 1 | """Maintains a registry of path pattern vs type names to guess type from path when a page is newly created. 2 | """ 3 | 4 | import re 5 | 6 | from infogami.utils import storage 7 | 8 | default_type = '/type/page' 9 | type_patterns = storage.OrderedDict() 10 | 11 | 12 | def register_type(pattern, typename): 13 | type_patterns[pattern] = typename 14 | 15 | 16 | def guess_type(path): 17 | for pattern, typename in type_patterns.items(): 18 | if re.search(pattern, path): 19 | return typename 20 | 21 | return default_type 22 | -------------------------------------------------------------------------------- /infogami/core/templates/viewpage.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $ _ = i18n.get_namespace('/mode/view') 4 | 5 | $ view = thingview(page) 6 | 7 | $var title: $view.title 8 | 9 | $if 'content_type' in view: 10 | $var content_type = view.content_type 11 | 12 | $if 'rawtext' in view: 13 | $var rawtext = view.rawtext 14 | 15 | $:view 16 | 17 |
18 | $_.edit 19 | $_.history 20 | $_.last_modified $datestr(page.last_modified) 21 |
22 | 23 | -------------------------------------------------------------------------------- /infogami/core/templates/password_mailer.html: -------------------------------------------------------------------------------- 1 | $def with (site, username, code) 2 | 3 | $var subject: Forgot password 4 | $var title: Forgot password 5 | Hello, 6 | 7 | You (or someone claiming to be you) have requested us to reset your password. 8 | 9 | In case you forgot your username, it is $:username. 10 | 11 | If you want to reset your password, click the following link. 12 | 13 | $:url(site + "/account/reset_password", username=username, code=code) 14 | 15 | If you have not requested this, please ignore this mail. Nothing is changed in your account. 16 | 17 | Thanks 18 | Infogami 19 | -------------------------------------------------------------------------------- /infogami/core/templates/type/text/diff.html: -------------------------------------------------------------------------------- 1 | $def with (a, b, name) 2 | 3 | $ diffresults = better_diff(a.value.splitlines(), b.value.splitlines()) 4 | 5 | 6 | $name 7 | 8 | 9 | $for key, ai, a, bi, b in diffresults: 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
$ai$:spacesafe(a)$bi$:spacesafe(b)
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /infogami/core/templates/type/backreference/input.html: -------------------------------------------------------------------------------- 1 | $def with (value, p) 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
Name$:thinginput(value.name, expected_type="/type/string", name=p.name + ".name") 7 |
Expected Type$:thinginput(value.expected_type, expected_type="/type/type", name=p.name + ".expected_type")
Property Name$:thinginput(value.property_name, expected_type="/type/string", name=p.name + ".property_name")
18 |
19 | -------------------------------------------------------------------------------- /infogami/plugins/review/templates/changes.html: -------------------------------------------------------------------------------- 1 | $def with (root, changes) 2 | 3 | $var title: $_.UNREVIEWED_CHANGES 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | $for c in changes: 14 | 15 | 16 | 17 | 18 | 21 | 22 | $else: 23 | 24 |
$_.PATH$_.REVIEWED$_.LATEST
$c.path$(c.reviewed_revision or "-")$c.revision 19 | $_.REVIEW 20 |
$_.NO_NEW_CHANGES_TO_REVIEW
25 | 26 | -------------------------------------------------------------------------------- /scripts/pytests_failing_on_py2_and_py3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | FAILING_FILES=( 4 | infogami/core/dbupgrade.py 5 | infogami/infobase/_json.py 6 | infogami/infobase/bulkupload.py 7 | infogami/plugins/i18n/code.py 8 | infogami/plugins/links/db.py 9 | infogami/plugins/pages/code.py 10 | infogami/plugins/review/code.py 11 | infogami/plugins/review/db.py 12 | infogami/plugins/wikitemplates/code.py 13 | migration/migrate-0.4-0.5.py 14 | test/bug_239238.py 15 | ) 16 | 17 | for FILEPATH in "${FAILING_FILES[@]}"; do 18 | echo "<<< $FILEPATH >>>" 19 | pytest "$FILEPATH" 20 | pytest --doctest-modules "$FILEPATH" 21 | done 22 | -------------------------------------------------------------------------------- /infogami/core/i18n/utils/date/strings.en: -------------------------------------------------------------------------------- 1 | ago = "ago" 2 | from_now = "from now" 3 | 4 | microsecond = "microsecond" 5 | millisecond = "millisecond" 6 | second = "second" 7 | minute = "minute" 8 | hour = "hour" 9 | day = "day" 10 | 11 | microseconds = "microseconds" 12 | milliseconds = "milliseconds" 13 | seconds = "seconds" 14 | minutes = "minutes" 15 | hours = "hours" 16 | days = "days" 17 | 18 | january = "January" 19 | february = "February" 20 | march = "March" 21 | april = "April" 22 | may = "May" 23 | june = "June" 24 | july = "July" 25 | august = "August" 26 | septemeber = "September" 27 | october = "October" 28 | november = "November" 29 | december = "December" 30 | 31 | -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/forms.py: -------------------------------------------------------------------------------- 1 | from web.form import Button, Form, Textbox, net 2 | 3 | from infogami.utils import i18n 4 | 5 | 6 | class BetterButton(Button): 7 | def render(self): 8 | label = self.attrs.get('label', self.name) 9 | safename = net.websafe(self.name) 10 | x = f'' 11 | return x 12 | 13 | 14 | _ = i18n.strings.get_namespace('/account/preferences') 15 | 16 | template_preferences = Form( 17 | Textbox("path", description=_.template_root), BetterButton('save', label=_.save) 18 | ) 19 | 20 | if __name__ == "__main__": 21 | print(template_preferences().render()) 22 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from setuptools import find_packages, setup 4 | 5 | setup( 6 | name='infogami', 7 | version="0.5dev", 8 | description='Infogami: A new kind of wiki', 9 | author='Anand Chitipothu', 10 | author_email='anandology@gmail.com', 11 | url=' http://infogami.org/', 12 | packages=find_packages(exclude=["ez_setup"]), 13 | classifiers=[ 14 | 'Programming Language :: Python', 15 | 'Programming Language :: Python :: 3', 16 | 'Programming Language :: Python :: 3.12', 17 | 'Programming Language :: Python :: Implementation :: CPython', 18 | ], 19 | license="AGPLv3", 20 | platforms=["any"], 21 | ) 22 | -------------------------------------------------------------------------------- /infogami/core/types/rawtext.type: -------------------------------------------------------------------------------- 1 | { 2 | 'key': '/type/rawtext', 3 | 'type': {'key': '/type/type'}, 4 | 'name': 'Raw Text', 5 | 'kind': 'regular', 6 | 'properties': [{ 7 | 'name': 'title', 8 | 'type': {'key': '/type/property'}, 9 | 'expected_type': {'key': '/type/string'}, 10 | 'unique': True 11 | }, { 12 | 'name': 'content_type', 13 | 'type': {'key': '/type/property'}, 14 | 'expected_type': {'key': '/type/string'}, 15 | 'unique': True 16 | }, { 17 | 'name': 'body', 18 | 'type': {'key': '/type/property'}, 19 | 'expected_type': {'key': '/type/text'}, 20 | 'unique': True 21 | }] 22 | } 23 | -------------------------------------------------------------------------------- /infogami/plugins/links/code.py: -------------------------------------------------------------------------------- 1 | """ 2 | links: allow interwiki links 3 | 4 | Adds a markdown preprocessor to catch `[[foo]]` style links. 5 | Creates a new set of database tables to keep track of them. 6 | Creates a new `m=backlinks` to display the results. 7 | """ 8 | 9 | from infogami.core import db 10 | from infogami.utils import delegate 11 | from infogami.utils.template import render 12 | 13 | 14 | class backlinks(delegate.mode): 15 | def GET(self, site, path): 16 | # @@ fix later 17 | return [] 18 | # TODO: (cclauss) unreachable code... 19 | links = db.Things(type=db.get_type(site, 'type/page'), parent=site, links=path) 20 | return render.backlinks(links) 21 | -------------------------------------------------------------------------------- /infogami/core/files/jquery.autocomplete.css: -------------------------------------------------------------------------------- 1 | .ac_results { 2 | padding: 0px; 3 | border: 1px solid WindowFrame; 4 | background-color: Window; 5 | overflow: hidden; 6 | } 7 | 8 | .ac_results ul { 9 | width: 100%; 10 | list-style-position: outside; 11 | list-style: none; 12 | padding: 0; 13 | margin: 0; 14 | } 15 | 16 | .ac_results li { 17 | margin: 0px; 18 | padding: 2px 5px; 19 | cursor: default; 20 | display: block; 21 | width: 100%; 22 | font: menu; 23 | font-size: 12px; 24 | overflow: hidden; 25 | } 26 | 27 | .ac_loading { 28 | background : Window url('indicator.gif') right center no-repeat; 29 | } 30 | 31 | .ac_over { 32 | background-color: Highlight; 33 | color: HighlightText; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /infogami/infobase/tests/test_seq.py: -------------------------------------------------------------------------------- 1 | from infogami.infobase._dbstore.sequence import SequenceImpl 2 | from infogami.infobase.tests import utils 3 | 4 | 5 | def setup_module(mod): 6 | global db 7 | utils.setup_db(mod) 8 | mod.seq = SequenceImpl(db) 9 | 10 | 11 | def teardown_module(mod): 12 | utils.teardown_db(mod) 13 | mod.seq = None 14 | 15 | 16 | class TestSeq: 17 | def setup_method(self, method): 18 | global db 19 | db.delete("seq", where="1=1") 20 | 21 | def test_seq(self): 22 | global seq 23 | seq.get_value("foo") == 0 24 | seq.next_value("foo") == 1 25 | seq.get_value("foo") == 1 26 | 27 | seq.next_value("foo") == 2 28 | seq.next_value("foo") == 3 29 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # This file is used to ignore specific commit revision for `git blame`. It 2 | # contains a list of commits that are not likely what you are looking for in a 3 | # blame, such as mass reformatting or renaming. It can be used by any of the 4 | # following ways: 5 | # 6 | # - Include the file in the command: 7 | # $ git blame --ignore-revs-file .git-blame-ignore-revs 8 | # 9 | # - Through gitconfig (needs to be set per-project): 10 | # $ git config blame.ignoreRevsFile .git-blame-ignore-revs 11 | # 12 | # Each commit has to be the full 40 character hash and comments are allowed. 13 | # Required git version: 2.23 14 | 15 | # Format the entire codebase through black (PR #162) 16 | 42acd0ae22c27659959788fdbc82d89a4c35afd4 17 | -------------------------------------------------------------------------------- /infogami/core/templates/default_diff.html: -------------------------------------------------------------------------------- 1 | $def with (a, b, name) 2 | 3 | $if a.is_primitive: 4 | $ diffresults = diff(a.value, b.value) 5 | $else: 6 | $ diffresults = diff(a.key, b.key) 7 | 8 | $name 9 | $for r in diffresults: 10 | $if r.tag == "equal": $r.left \ 11 | $if r.tag == "delete": $r.left \ 12 | $if r.tag == "insert": $r.left \ 13 | $if r.tag == "replace": $r.left \ 14 | 15 | $for r in diffresults: 16 | $if r.tag == "equal": $r.right \ 17 | $if r.tag == "delete": $r.right \ 18 | $if r.tag == "insert": $r.right \ 19 | $if r.tag == "replace": $r.right \ 20 | 21 | -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/db.py: -------------------------------------------------------------------------------- 1 | import web 2 | 3 | 4 | def get_all_templates(site): 5 | t = site.get('/type/template') 6 | if t is None: 7 | return [] 8 | q = {'type': '/type/template', 'limit': 1000} 9 | # return [site.get(key) for key in site.things(q)] 10 | return site.get_many([key for key in site.things(q)]) 11 | 12 | 13 | def get_all_macros(site): 14 | t = site.get('/type/macro') 15 | if t is None: 16 | return [] 17 | q = {'type': '/type/macro', 'limit': 1000} 18 | # return [site.get(key) for key in site.things(q)] 19 | return site.get_many([key for key in site.things(q)]) 20 | 21 | 22 | def get_all_sites(): 23 | if web.ctx.site.exists(): 24 | return [web.ctx.site] 25 | else: 26 | return [] 27 | -------------------------------------------------------------------------------- /infogami/core/templates/type/property/input.html: -------------------------------------------------------------------------------- 1 | $def with (value, p) 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
Name$:thinginput(value.name, expected_type="/type/string", name=p.name + ".name") 7 |
Expected Type$:thinginput(value.expected_type, expected_type="/type/type", name=p.name + ".expected_type")
Unique$:thinginput(value.unique, expected_type="/type/boolean", name=p.name + ".unique")
Description$:thinginput(value.description, expected_type="/type/string", name=p.name + ".description")
22 |
23 | -------------------------------------------------------------------------------- /scripts/server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Script to run infogami server. 3 | 4 | USAGE: 5 | 6 | * Run Infogami http server at port 8080. 7 | 8 | $ ./scripts/server infogami.yml startserver 8080 9 | 10 | * Run Infobase as fastcgi server at port 7070 11 | 12 | $ ./scripts/server infogami.yml startserver fastcgi 8080 13 | """ 14 | import sys 15 | 16 | import _init_path # noqa: F401 Imported for its side effect of setting PYTHONPATH 17 | 18 | import infogami 19 | 20 | 21 | def main(args): 22 | if len(args) < 1 or sys.argv[0] in ("-h", "--help"): 23 | print(f"USAGE: {sys.argv[0]} configfile [subcommand] [arguments]", file=sys.stderr) 24 | sys.exit(1) 25 | 26 | infogami.main(*args) 27 | 28 | 29 | if __name__ == "__main__": 30 | main(sys.argv[1:]) 31 | -------------------------------------------------------------------------------- /infogami/core/templates/default_input.html: -------------------------------------------------------------------------------- 1 | $def with (thing, property) 2 | 3 | $ kind = property.expected_type.kind 4 | 5 | $if kind == "primitive" or kind == "basic": 6 | $if property.get('options'): 7 | $:Dropdown(property.name, property.options, value=thing.value).render() 8 | $else: 9 | 10 | $elif kind == 'embeddable': 11 | 12 | $for p in property.expected_type.properties: 13 | 14 | 15 | 16 | 17 |
$p.name$:thinginput(thing[p.name], expected_type=p.expected_type, name=property.name + '.' + p.name)
18 | $else: 19 | $:macros.ThingReference(thing.type, property.name, thing) 20 | 21 | -------------------------------------------------------------------------------- /scripts/infobase_server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Script to run infobase. 3 | 4 | USAGE: 5 | 6 | * Run Infobase http server at port 7070. 7 | 8 | $ python ./script/infobase_server infobase.yaml 7070 9 | 10 | * Run Infobase as fastcgi server at port 7070 11 | 12 | $ python ./script/infobase_server infobase.yaml fastcgi 7070 13 | """ 14 | import sys 15 | 16 | import _init_path # noqa: F401 Imported for its side effect of setting PYTHONPATH 17 | 18 | from infogami.infobase import server 19 | 20 | 21 | def main(args): 22 | if len(args) < 1 or args[0] in ('-h', '--help'): 23 | print(f"USAGE: {sys.argv[0]} configfile [port]", file=sys.stderr) 24 | sys.exit(1) 25 | 26 | server.start(*args) 27 | 28 | if __name__ == "__main__": 29 | main(sys.argv[1:]) 30 | -------------------------------------------------------------------------------- /infogami/core/macros/TypeChanger.html: -------------------------------------------------------------------------------- 1 | $def with (type, usetable=0) 2 | 3 | $ _ = i18n.get_namespace('/mode/edit') 4 | 5 | 11 | 12 | $if usetable: 13 | 14 | $_.page_type 15 | 16 | $:thinginput(type, name="type.key", expected_type="/type/type", kind="regular") 17 | 18 | 19 | 20 | $else: 21 | $_.page_type $:thinginput(type, name="type.key", expected_type="/type/type", kind="regular") 22 |

23 | 24 | -------------------------------------------------------------------------------- /infogami/core/templates/type/page/edit.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $ _e = i18n.get_namespace('/mode/edit') 4 | $ _t = i18n.get_namespace('/type/page') 5 | 6 | $var title: $_e.edit_title(page.title) 7 | 8 | 9 |
10 | 11 | $:macros.TypeChanger(page.type) 12 | 13 | $_t.title
14 | 15 | 16 |

$:_e.edit_summary
17 | 18 |

19 | 20 |

21 | 22 | 23 | 24 |

25 |
26 | -------------------------------------------------------------------------------- /infogami/plugins/links/db.py: -------------------------------------------------------------------------------- 1 | from infogami import tdb 2 | from infogami.core import db 3 | 4 | 5 | def get_links_type(): 6 | linkstype = db.get_type('links') or db.new_type('links') 7 | linkstype.save() 8 | return linkstype 9 | 10 | 11 | def new_links(page, links): 12 | # for links thing: parent=page, type=linkstype 13 | site = page.parent 14 | path = page.name 15 | d = {'site': site, 'path': path, 'links': list(links)} 16 | 17 | try: 18 | backlinks = tdb.withName("links", page) 19 | backlinks.setdata(d) 20 | backlinks.save() 21 | except tdb.NotFound: 22 | backlinks = tdb.new("links", page, get_links_type(), d) 23 | backlinks.save() 24 | 25 | 26 | def get_links(site, path): 27 | return tdb.Things(type=get_links_type(), site=site, links=path) 28 | -------------------------------------------------------------------------------- /infogami/plugins/wikitemplates/templates/type/template/edit.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $ _e = i18n.get_namespace('/mode/edit') 4 | $ _t = i18n.get_namespace('/type/template') 5 | 6 | $var title: $_e.edit_title(page.name) 7 | 8 | 9 |
10 | 11 | $:macros.TypeChanger(page.type) 12 | 13 | $_t.title
14 | 15 | 16 |

$:_e.edit_summary
17 | 18 |

19 | 20 |

21 | 22 | 23 | 24 |

25 |
26 | -------------------------------------------------------------------------------- /infogami/utils/context.py: -------------------------------------------------------------------------------- 1 | """ 2 | Threaded context for infogami. 3 | """ 4 | 5 | import web 6 | 7 | # Placeholder for keeping context defaults. This is populated by 8 | # the app on startup. 9 | defaults = web.storage() 10 | 11 | 12 | class InfogamiContext(web.ThreadedDict): 13 | """ 14 | Threaded context for infogami. 15 | Uses web.ctx for providing a thread-specific context for infogami. 16 | """ 17 | 18 | def load(self): 19 | self.update(defaults) 20 | 21 | def __getattr__(self, name): 22 | # In some error conditions, context is not initialzied. 23 | # Using the default as fallback. 24 | try: 25 | return web.ThreadedDict.__getattr__(self, name) 26 | except AttributeError: 27 | return getattr(defaults, name) 28 | 29 | 30 | context = InfogamiContext() 31 | -------------------------------------------------------------------------------- /infogami/core/templates/default_view.html: -------------------------------------------------------------------------------- 1 | $def with (page) 2 | 3 | $var title: $page.name 4 | 5 | 6 | 7 | 8 | $for p in page.type.properties: 9 | $ label = i18n.get(page.type.key, p.name) 10 | $if p.unique: 11 | 12 | 13 | 14 | 15 | $else: 16 | $for x in page[p.name]: 17 | 18 | 19 | 20 | 21 | 22 | $for p in page.type.backreferences: 23 | $ label = i18n.get(page.type.key, p.name) 24 | $for x in page[p.name]: 25 | 26 | 27 | 28 | 29 | 30 | 31 |
$label$:thingrepr(page[p.name], p.expected_type)
$label$:thingrepr(x, p.expected_type)
$label$:thingrepr(x, p.expected_type)
32 | 33 | -------------------------------------------------------------------------------- /infogami/config.py: -------------------------------------------------------------------------------- 1 | """ 2 | Infogami configuration. 3 | """ 4 | 5 | 6 | def get(name, default=None): 7 | return globals().get(name, default) 8 | 9 | 10 | middleware = [] # type: ignore 11 | 12 | cache_templates = True 13 | db_printing = False 14 | db_kind = 'SQL' 15 | 16 | db_parameters: dict[str, str] | None = None 17 | infobase_host = None 18 | site = "infogami.org" 19 | 20 | plugins = ['links'] 21 | plugin_modules = [] # type: ignore 22 | 23 | plugin_path = ['infogami.plugins'] 24 | 25 | # key for encrypting password 26 | encryption_key = "ofu889e4i5kfem" 27 | 28 | # salt added to password before encrypting 29 | password_salt = "zxps#2s4g@z" 30 | 31 | from_address = "noreply@infogami.org" 32 | smtp_server = "localhost" 33 | 34 | login_cookie_name = "infogami_session" 35 | 36 | infobase_parameters = dict(type='local') 37 | bugfixer = None 38 | 39 | admin_password = "admin123" 40 | -------------------------------------------------------------------------------- /.github/workflows/openlibrary_tests.yml: -------------------------------------------------------------------------------- 1 | name: openlibrary_tests 2 | on: 3 | push: 4 | branches: [ master ] 5 | pull_request: 6 | branches: [ master ] 7 | workflow_dispatch: 8 | jobs: 9 | openlibrary_tests: 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | python-version: ["3.12"] 14 | runs-on: ubuntu-latest 15 | steps: 16 | # - if: "contains(matrix.python-version, '-dev')" 17 | # run: sudo apt-get install -y libxml2 libxslt-dev 18 | - name: Checkout Open Library 19 | uses: actions/checkout@v3 20 | with: 21 | repository: internetarchive/openlibrary 22 | - name: Checkout current Infogami 23 | uses: actions/checkout@v3 24 | with: 25 | path: vendor/infogami 26 | - uses: actions/setup-python@v4 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | - run: pip install -r requirements_test.txt 30 | - run: make test-py 31 | -------------------------------------------------------------------------------- /tests/test_doctests.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from web.test import doctest_suite 4 | 5 | 6 | def add_test(test): 7 | if isinstance(test, unittest.TestSuite): 8 | for t in test._tests: 9 | add_test(t) 10 | elif isinstance(test, unittest.TestCase): 11 | test_method = getattr(test, test._testMethodName) 12 | 13 | def do_test(test_method=test_method): 14 | test_method() 15 | 16 | name = "test_" + test.id().replace(".", "_") 17 | globals()[name] = do_test 18 | 19 | 20 | modules = [ 21 | "infogami.core.code", 22 | "infogami.core.helpers", 23 | "infogami.utils.app", 24 | "infogami.utils.i18n", 25 | "infogami.utils.storage", 26 | "infogami.infobase.common", 27 | "infogami.infobase.client", 28 | "infogami.infobase.dbstore", 29 | "infogami.infobase.lru", 30 | "infogami.infobase.readquery", 31 | "infogami.infobase.utils", 32 | "infogami.infobase.writequery", 33 | ] 34 | 35 | suite = doctest_suite(modules) 36 | 37 | add_test(suite) 38 | -------------------------------------------------------------------------------- /tests/test_infogami/test_account.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import web 3 | 4 | from infogami.utils.delegate import app 5 | 6 | b = app.browser() 7 | 8 | 9 | @pytest.mark.skip( 10 | reason="Browser test not currently functioning, requires BeautifulSoup and ClientForm, and site is still set to None" 11 | ) 12 | def test_login(): 13 | # try with bad account 14 | b.open('/account/login') 15 | b.select_form(name='login') 16 | b['username'] = 'joe' 17 | b['password'] = 'secret' 18 | 19 | try: 20 | b.submit() 21 | except web.BrowserError as e: 22 | assert str(e) == 'Invalid username or password' 23 | else: 24 | assert False, 'Expected exception' 25 | 26 | # follow register link 27 | b.follow_link(text='create a new account') 28 | assert b.path == '/account/register' 29 | 30 | b.select_form('register') 31 | b['username'] = 'joe' 32 | b['displayname'] = 'Joe' 33 | b['password'] = 'secret' 34 | b['password2'] = 'secret' 35 | b['email'] = 'joe@example.com' 36 | b.submit() 37 | assert b.path == '/' 38 | -------------------------------------------------------------------------------- /infogami/core/macros/ThingReference.html: -------------------------------------------------------------------------------- 1 | $def with (type, name, value, property="key", limit=10) 2 | 3 | $add_javascript('/static/js/jquery/jquery.js') 4 | $add_javascript('/static/js/jquery/jquery.bgiframe.min.js') 5 | $add_javascript('/static/js/jquery/jquery.dimensions.pack.js') 6 | $add_javascript('/static/js/jquery/jquery.autocomplete.js') 7 | $add_javascript('/static/js/autocomplete.js') 8 | 9 | $add_stylesheet('/static/jquery.autocomplete.css') 10 | 11 | $if property == "key": 12 | 13 | $else: 14 | 15 | 16 | 17 | 24 | -------------------------------------------------------------------------------- /infogami/infobase/tests/test_doctests.py: -------------------------------------------------------------------------------- 1 | import doctest 2 | 3 | import pytest 4 | 5 | modules = [ 6 | "infogami.infobase.account", 7 | "infogami.infobase.bootstrap", 8 | "infogami.infobase.cache", 9 | "infogami.infobase.client", 10 | "infogami.infobase.common", 11 | "infogami.infobase.core", 12 | "infogami.infobase.dbstore", 13 | "infogami.infobase.infobase", 14 | "infogami.infobase.logger", 15 | "infogami.infobase.logreader", 16 | "infogami.infobase.lru", 17 | "infogami.infobase.readquery", 18 | "infogami.infobase.tests.pytest_wildcard", 19 | "infogami.infobase.utils", 20 | "infogami.infobase.writequery", 21 | ] 22 | 23 | 24 | @pytest.mark.parametrize('module', modules) 25 | def test_doctest(module): 26 | mod = __import__(module, None, None, ['x']) 27 | finder = doctest.DocTestFinder() 28 | tests = finder.find(mod, mod.__name__) 29 | for test in tests: 30 | runner = doctest.DocTestRunner(verbose=True) 31 | failures, tries = runner.run(test) 32 | if failures: 33 | pytest.fail("doctest failed: " + test.name) 34 | -------------------------------------------------------------------------------- /scripts/pytests_failing_on_py3_only.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | FAILING_FILES=( 4 | infogami/core/code.py 5 | infogami/infobase/_dbstore/indexer.py 6 | infogami/infobase/common.py 7 | infogami/infobase/tests/__init__.py 8 | infogami/infobase/tests/test_account.py 9 | infogami/infobase/tests/test_client.py 10 | infogami/infobase/tests/test_doctests.py 11 | infogami/infobase/tests/test_infobase.py 12 | infogami/infobase/tests/test_read.py 13 | infogami/infobase/tests/test_save.py 14 | infogami/infobase/tests/test_seq.py 15 | infogami/infobase/tests/test_store.py 16 | infogami/infobase/tests/test_writequery.py 17 | infogami/utils/app.py 18 | infogami/utils/view.py 19 | test/test_dbstore.py 20 | test/test_doctests.py 21 | tests/__init__.py 22 | tests/test_doctests.py 23 | ) 24 | 25 | for FILEPATH in "${FAILING_FILES[@]}"; do 26 | echo "<<< $FILEPATH >>>" 27 | pytest "$FILEPATH" 28 | # See TODO in test/test_dbstore.py 29 | if [ "$FILEPATH" != "test/test_dbstore.py" ]; then 30 | pytest --doctest-modules "$FILEPATH"; 31 | fi 32 | done 33 | -------------------------------------------------------------------------------- /infogami/infobase/config.py: -------------------------------------------------------------------------------- 1 | """Infobase configuration.""" 2 | 3 | # IP address of machines which can be trusted for doing admin tasks 4 | trusted_machines = ["127.0.0.1"] 5 | 6 | # default size of cache 7 | cache_size = 1000 8 | 9 | secret_key = "bzuim9ws8u" 10 | 11 | # set this to log dir to enable logging 12 | logroot = None 13 | compress_log = False 14 | 15 | # query_timeout in milli seconds. 16 | query_timeout = "60000" 17 | 18 | user_root = "/user/" 19 | 20 | # @@ Hack to execute some code when infobase is created. 21 | # @@ This will be replaced with a better method soon. 22 | startup_hook = None 23 | 24 | bind_address = None 25 | port = 5964 26 | fastcgi = False 27 | 28 | # earlier there used to be a machine_comment column in version table. 29 | # Set this flag to True to continue to use that field in earlier installations. 30 | use_machine_comment = False 31 | 32 | # bot column is added transaction table to mark edits by bot. Flag to enable/disable this feature. 33 | use_bot_column = True 34 | 35 | verify_user_email = False 36 | 37 | 38 | def get(key, default=None): 39 | return globals().get(key, default) 40 | -------------------------------------------------------------------------------- /infogami/infobase/tests/pytest_wildcard.py: -------------------------------------------------------------------------------- 1 | """py.test wildcard plugin. 2 | """ 3 | 4 | import pytest 5 | 6 | 7 | class Wildcard: 8 | """Wildcard object is equal to anything. 9 | 10 | Useful to compare datastructures which contain some random numbers or db sequences. 11 | 12 | >>> import random 13 | >>> assert [random.random(), 1, 2] == [Wildcard(), 1, 2] 14 | """ 15 | 16 | def __eq__(self, other): 17 | return True 18 | 19 | def __ne__(self, other): 20 | return False 21 | 22 | def __repr__(self): 23 | return '' 24 | 25 | 26 | def test_wildcard(): 27 | wildcard = Wildcard() 28 | assert wildcard == 1 29 | assert wildcard == [1, 2, 3] 30 | assert 1 == wildcard 31 | assert ["foo", 1, 2] == [wildcard, 1, 2] 32 | 33 | 34 | @pytest.fixture() 35 | def wildcard(request): 36 | """Returns the wildcard object. 37 | 38 | Wildcard object is equal to anything. It is useful in testing datastuctures with some random parts. 39 | 40 | >>> import random 41 | >>> assert [random.random(), 1, 2] == [Wildcard(), 1, 2] 42 | """ 43 | return Wildcard() 44 | -------------------------------------------------------------------------------- /infogami/plugins/i18n/templates/i18n.html: -------------------------------------------------------------------------------- 1 | $def with (namespace, lang, page) 2 | 3 | 14 | 15 |
16 | Language: $:Dropdown('lang', _.get_languages(), onchange="changelang();", value=lang).render()

17 | 18 |
19 | 20 | 21 | 22 | 26 | 36 | 37 |
23 | $for ns in _.get_namespaces(): 24 | $(ns or "root") $(_.get_count(ns, lang))/$_.get_count(ns)
25 |
27 | $if page: 28 | $page.key 29 | 30 | $:thingview(page) 31 | $else: 32 | $ name = homepath() + "/i18n/" + namespace + "/strings." + lang 33 | $:name
34 |
Page not found. [create]
35 |
38 | -------------------------------------------------------------------------------- /infogami/utils/tests/test_app.py: -------------------------------------------------------------------------------- 1 | from infogami.utils import app 2 | 3 | 4 | def test_parse_accept(): 5 | # testing examples from http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 6 | assert app.parse_accept("audio/*; q=0.2, audio/basic") == [ 7 | {"media_type": "audio/basic"}, 8 | {"media_type": "audio/*", "q": 0.2}, 9 | ] 10 | 11 | assert app.parse_accept( 12 | "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c" 13 | ) == [ 14 | {"media_type": "text/html"}, 15 | {"media_type": "text/x-c"}, 16 | {"media_type": "text/x-dvi", "q": 0.8}, 17 | {"media_type": "text/plain", "q": 0.5}, 18 | ] 19 | 20 | # try empty 21 | assert app.parse_accept("") == [{'media_type': ''}] 22 | assert app.parse_accept(" ") == [{'media_type': ''}] 23 | assert app.parse_accept(",") == [{'media_type': ''}, {'media_type': ''}] 24 | 25 | # try some bad ones 26 | assert app.parse_accept("hc/url;*/*") == [{"media_type": "hc/url"}] 27 | assert app.parse_accept("text/plain;q=bad") == [{"media_type": "text/plain"}] 28 | 29 | assert app.parse_accept(";q=1") == [{"media_type": "", "q": 1.0}] 30 | -------------------------------------------------------------------------------- /scripts/run_doctests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # USER=openlibrary@example.com pytest --doctest-modules || true 4 | 5 | USER=openlibrary@example.com pytest --doctest-modules \ 6 | --ignore=infogami/core/dbupgrade.py \ 7 | --ignore=infogami/infobase/_json.py \ 8 | --ignore=infogami/infobase/bulkupload.py \ 9 | --ignore=infogami/infobase/tests/test_account.py \ 10 | --ignore=infogami/infobase/tests/test_client.py \ 11 | --ignore=infogami/infobase/tests/test_infobase.py \ 12 | --ignore=infogami/infobase/tests/test_read.py \ 13 | --ignore=infogami/infobase/tests/test_save.py \ 14 | --ignore=infogami/infobase/tests/test_seq.py \ 15 | --ignore=infogami/infobase/tests/test_store.py \ 16 | --ignore=infogami/infobase/tests/test_writequery.py \ 17 | --ignore=infogami/plugins/i18n/code.py \ 18 | --ignore=infogami/plugins/links/db.py \ 19 | --ignore=infogami/plugins/pages/code.py \ 20 | --ignore=infogami/plugins/review/code.py \ 21 | --ignore=infogami/plugins/review/db.py \ 22 | --ignore=infogami/plugins/wikitemplates/code.py \ 23 | --ignore=migration/migrate-0.4-0.5.py \ 24 | --ignore=test/bug_239238.py \ 25 | --ignore=test/test_dbstore.py 26 | -------------------------------------------------------------------------------- /sample_run.py: -------------------------------------------------------------------------------- 1 | """ 2 | Sample run.py 3 | """ 4 | 5 | import infogami 6 | 7 | # your db parameters 8 | infogami.config.db_parameters = dict( 9 | dbn='postgres', db="infogami", user='yourname', pw='' 10 | ) 11 | 12 | # site name 13 | infogami.config.site = 'infogami.org' 14 | infogami.config.admin_password = "admin123" 15 | 16 | # add additional plugins and plugin path 17 | # infogami.config.plugin_path += ['plugins'] 18 | # infogami.config.plugins += ['search'] 19 | 20 | 21 | def createsite(): 22 | import web 23 | 24 | from infogami.infobase import config, dbstore, infobase, server 25 | 26 | web.config.db_parameters = infogami.config.db_parameters 27 | web.config.db_printing = True 28 | web.ctx.ip = '127.0.0.1' 29 | 30 | server.app.request('/') 31 | schema = dbstore.Schema() 32 | store = dbstore.DBStore(schema) 33 | ib = infobase.Infobase(store, config.secret_key) 34 | ib.create(infogami.config.site) 35 | 36 | 37 | if __name__ == "__main__": 38 | import sys 39 | 40 | if '--schema' in sys.argv: 41 | from infogami.infobase.dbstore import Schema 42 | 43 | print(Schema().sql()) 44 | elif '--createsite' in sys.argv: 45 | createsite() 46 | else: 47 | infogami.run() 48 | -------------------------------------------------------------------------------- /infogami/core/files/js/autocomplete.js: -------------------------------------------------------------------------------- 1 | 2 | function setup_autocomplete(e) { 3 | var e = $(e); 4 | 5 | var name = e.attr('ac_name'); 6 | var type = e.attr('ac_type'); 7 | var property = e.attr('ac_property'); 8 | var limit = e.attr("ac_limit"); 9 | 10 | e.autocomplete("/getthings", { 11 | extraParams: { 12 | type: type, 13 | property: property 14 | }, 15 | matchCase: true, 16 | max: limit, 17 | formatItem: function (row) { 18 | if (property == "key") 19 | return row[0]; 20 | else 21 | return "
" + row[0] + "
" + row[1] + "
"; 22 | } 23 | }) 24 | .result(function(event, data, formatted) { 25 | var name = $(this).attr('ac_name'); 26 | if ($(this).attr("ac_property") != "key") 27 | $(document.getElementById('result_' + name)).val(data[1]) 28 | }) 29 | .change(function() { 30 | // When user selects empty string, set the result to empty 31 | var name = $(this).attr('ac_name'); 32 | if ($(this).attr("ac_property") != "key") 33 | $(document.getElementById("result_" + name)).val(""); 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /infogami/core/macros/RecentChanges.html: -------------------------------------------------------------------------------- 1 | $def with (author=None, type=None, limit=50) 2 | 3 | $ page = safeint(query_param('page', '0')) 4 | $ ip = query_param('ip', None) 5 | $ type = type or query_param('type', None) 6 | $ changes = get_recent_changes(author=author, ip=ip, type=type, limit=limit, offset=page * limit) 7 | 8 |
9 | 10 | $var title: $_.RECENT_CHANGES 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | $for v in changes: 22 | 23 | 24 | 25 | $if v.author: 26 | 27 | $else: 28 | 29 | 30 | 35 | 36 |
$_.WHEN$_.PATH$_.WHO$_.WHAT$_.ACTIONS
$datestr(v.created)$v.key$v.author.displayname$v.ip$v.comment 31 | $_.VIEW  32 | $_.EDIT  33 | $_.DIFF  34 |
37 | 38 |
39 | $if page != 0: 40 | Newer 41 | 42 | $if len(changes) == limit: 43 | Older 44 |
45 | 46 | -------------------------------------------------------------------------------- /infogami/infobase/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Infobase. 3 | """ 4 | 5 | import sys 6 | 7 | import web 8 | 9 | from infogami.infobase import infobase, server 10 | 11 | commands = {} 12 | 13 | 14 | def command(f): 15 | commands[f.__name__] = f 16 | return f 17 | 18 | 19 | @command 20 | def help(): 21 | """Prints this help.""" 22 | print("Infobase help\n\nCommands:\n") 23 | for name, c in commands.items(): 24 | print("%-20s %s" % (name, c.__doc__)) 25 | 26 | 27 | @command 28 | def createsite(sitename, admin_password): 29 | """Creates a new site. Takes 2 arguments sitename and admin_password.""" 30 | web.load() 31 | infobase.Infobase().create_site(sitename, admin_password) 32 | 33 | 34 | @command 35 | def startserver(*args): 36 | """Starts the infobase server at port 8080. An optional port argument can be specified to run the server at a different port.""" 37 | sys.argv = [sys.argv[0]] + list(args) 38 | server.run() 39 | 40 | 41 | def run(): 42 | action = sys.argv[1] if len(sys.argv) > 1 else 'startserver' 43 | return commands[action](*sys.argv[2:]) 44 | 45 | 46 | if __name__ == "__main__": 47 | import os 48 | 49 | dbname = os.environ.get('INFOBASE_DB', 'infobase') 50 | web.config.db_printing = True 51 | web.config.db_parameters = dict(dbn='postgres', db=dbname) 52 | run() 53 | -------------------------------------------------------------------------------- /infogami/core/templates/feed.html: -------------------------------------------------------------------------------- 1 | $def with (site, changes) 2 | 3 | 4 | 5 | 6 | Infogami - Recent changes 7 | $site 8 | 9 | Track the most recent changes to $site in this feed. 10 | $changes[0].created 11 | infogami 12 | $for v in changes: 13 | 14 | $v.key 15 | $site$v.key?m=diff&b=$v.revision 16 | $site$v.key?m=diff&b=$v.revision 17 | 18 | Path: $v.key <br/> 19 | Comment: $v.comment <br/> 20 | $if v.author: 21 | Author: $v.author.displayname 22 | $else: 23 | Author: $v.ip 24 | <br/> 25 | $v.diff 26 | 27 | $v.created 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /infogami/utils/flash.py: -------------------------------------------------------------------------------- 1 | """Utility to display flash messages. 2 | 3 | To add a flash message: 4 | 5 | add_flash_message('info', 'Login successful!') 6 | 7 | To display flash messages in a template: 8 | 9 | $ for flash in get_flash_messages(): 10 |
$flash.message
11 | """ 12 | 13 | import json 14 | 15 | import web 16 | 17 | 18 | def get_flash_messages(): 19 | flash = web.ctx.get('flash', []) 20 | web.ctx.flash = [] 21 | return flash 22 | 23 | 24 | def add_flash_message(type, message): 25 | flash = web.ctx.setdefault('flash', []) 26 | flash.append(web.storage(type=type, message=message)) 27 | 28 | 29 | def flash_processor(handler): 30 | flash = web.cookies(flash="[]").flash 31 | try: 32 | flash = [ 33 | web.storage(d) 34 | for d in json.loads(flash) 35 | if isinstance(d, dict) and 'type' in d and 'message' in d 36 | ] 37 | except ValueError: 38 | flash = [] 39 | 40 | web.ctx.flash = list(flash) 41 | 42 | try: 43 | return handler() 44 | finally: 45 | # Flash changed. Need to save it. 46 | if flash != web.ctx.flash: 47 | if web.ctx.flash: 48 | web.setcookie('flash', json.dumps(web.ctx.flash)) 49 | else: 50 | web.setcookie('flash', '', expires=-1) 51 | -------------------------------------------------------------------------------- /infogami/core/files/js/jquery/jquery.bgiframe.min.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net) 2 | * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 3 | * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 4 | * 5 | * $LastChangedDate: 2007-03-19 16:02:41 +0100 (Mo, 19 Mrz 2007) $ 6 | * $Rev: 1546 $ 7 | */ 8 | (function($){$.fn.bgIframe=jQuery.fn.bgiframe=function(s){if(!($.browser.msie&&typeof XMLHttpRequest=='function'))return this;s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='