From a2e4e83c200acd07a651d3d5c8810003380ee64a Mon Sep 17 00:00:00 2001 From: Martin Mahner Date: Mon, 30 May 2011 01:03:04 +0200 Subject: [PATCH] Initial commit after move to linode --- .gitignore | 7 + .pylintrc | 308 ++++++++++++++ README | 4 + docs/Makefile | 88 ++++ docs/conf.py | 195 +++++++++ docs/deployment.rst | 18 + docs/index.rst | 18 + docs/install.rst | 57 +++ fabfile.py | 92 +++++ pastebin/__init__.py | 0 pastebin/apps/__init__.py | 0 pastebin/apps/api/__init__.py | 0 pastebin/apps/api/handlers.py | 29 ++ pastebin/apps/dpaste/__init__.py | 1 + pastebin/apps/dpaste/admin.py | 13 + pastebin/apps/dpaste/forms.py | 109 +++++ pastebin/apps/dpaste/highlight.py | 43 ++ .../dpaste/locale/de/LC_MESSAGES/django.mo | Bin 0 -> 3419 bytes .../dpaste/locale/de/LC_MESSAGES/django.po | 236 +++++++++++ .../dpaste/locale/en/LC_MESSAGES/django.mo | Bin 0 -> 1175 bytes .../dpaste/locale/en/LC_MESSAGES/django.po | 226 +++++++++++ pastebin/apps/dpaste/management/__init__.py | 0 .../dpaste/management/commands/__init__.py | 0 .../management/commands/cleanup_snippets.py | 22 + pastebin/apps/dpaste/models.py | 48 +++ .../apps/dpaste/templates/dpaste/base.html | 1 + .../templates/dpaste/snippet_details.html | 174 ++++++++ .../templates/dpaste/snippet_details_raw.html | 1 + .../dpaste/templates/dpaste/snippet_diff.html | 13 + .../dpaste/templates/dpaste/snippet_form.html | 19 + .../dpaste/templates/dpaste/snippet_list.html | 26 ++ .../dpaste/templates/dpaste/snippet_new.html | 39 ++ .../dpaste/templates/dpaste/userprefs.html | 28 ++ pastebin/apps/dpaste/templatetags/__init__.py | 1 + .../apps/dpaste/templatetags/dpaste_tags.py | 7 + pastebin/apps/dpaste/urls.py | 14 + pastebin/apps/dpaste/views.py | 165 ++++++++ pastebin/bin/manage.py | 40 ++ pastebin/conf/__init__.py | 0 pastebin/conf/common/__init__.py | 0 pastebin/conf/common/urls/__init__.py | 0 pastebin/conf/common/urls/admin.py | 9 + pastebin/conf/dev/__init__.py | 0 pastebin/conf/dev/settings.py | 17 + pastebin/conf/dev/urls.py | 9 + pastebin/conf/settings.py | 105 +++++ pastebin/conf/test/__init__.py | 0 pastebin/conf/test/settings.py | 16 + pastebin/conf/test/urls.py | 9 + pastebin/conf/urls.py | 26 ++ pastebin/locale/de/LC_MESSAGES/django.mo | Bin 0 -> 3405 bytes pastebin/locale/de/LC_MESSAGES/django.po | 253 ++++++++++++ pastebin/locale/en/LC_MESSAGES/django.mo | Bin 0 -> 698 bytes pastebin/locale/en/LC_MESSAGES/django.po | 246 +++++++++++ pastebin/static/.gitignore | 0 pastebin/static/theme.css | 384 ++++++++++++++++++ pastebin/templates/404.html | 9 + pastebin/templates/500.html | 9 + pastebin/templates/about.html | 64 +++ pastebin/templates/base.html | 62 +++ requirements.pip | 4 + server_configs/dev/apache.conf | 16 + server_configs/dev/django.wsgi | 13 + server_configs/dev/nginx.conf | 31 ++ setup.py | 9 + 65 files changed, 3333 insertions(+) create mode 100644 .gitignore create mode 100644 .pylintrc create mode 100644 README create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/deployment.rst create mode 100644 docs/index.rst create mode 100644 docs/install.rst create mode 100644 fabfile.py create mode 100644 pastebin/__init__.py create mode 100644 pastebin/apps/__init__.py create mode 100644 pastebin/apps/api/__init__.py create mode 100644 pastebin/apps/api/handlers.py create mode 100644 pastebin/apps/dpaste/__init__.py create mode 100644 pastebin/apps/dpaste/admin.py create mode 100644 pastebin/apps/dpaste/forms.py create mode 100644 pastebin/apps/dpaste/highlight.py create mode 100644 pastebin/apps/dpaste/locale/de/LC_MESSAGES/django.mo create mode 100644 pastebin/apps/dpaste/locale/de/LC_MESSAGES/django.po create mode 100644 pastebin/apps/dpaste/locale/en/LC_MESSAGES/django.mo create mode 100644 pastebin/apps/dpaste/locale/en/LC_MESSAGES/django.po create mode 100644 pastebin/apps/dpaste/management/__init__.py create mode 100644 pastebin/apps/dpaste/management/commands/__init__.py create mode 100644 pastebin/apps/dpaste/management/commands/cleanup_snippets.py create mode 100644 pastebin/apps/dpaste/models.py create mode 100644 pastebin/apps/dpaste/templates/dpaste/base.html create mode 100644 pastebin/apps/dpaste/templates/dpaste/snippet_details.html create mode 100644 pastebin/apps/dpaste/templates/dpaste/snippet_details_raw.html create mode 100644 pastebin/apps/dpaste/templates/dpaste/snippet_diff.html create mode 100644 pastebin/apps/dpaste/templates/dpaste/snippet_form.html create mode 100644 pastebin/apps/dpaste/templates/dpaste/snippet_list.html create mode 100644 pastebin/apps/dpaste/templates/dpaste/snippet_new.html create mode 100644 pastebin/apps/dpaste/templates/dpaste/userprefs.html create mode 100644 pastebin/apps/dpaste/templatetags/__init__.py create mode 100644 pastebin/apps/dpaste/templatetags/dpaste_tags.py create mode 100644 pastebin/apps/dpaste/urls.py create mode 100644 pastebin/apps/dpaste/views.py create mode 100755 pastebin/bin/manage.py create mode 100644 pastebin/conf/__init__.py create mode 100644 pastebin/conf/common/__init__.py create mode 100644 pastebin/conf/common/urls/__init__.py create mode 100644 pastebin/conf/common/urls/admin.py create mode 100644 pastebin/conf/dev/__init__.py create mode 100644 pastebin/conf/dev/settings.py create mode 100644 pastebin/conf/dev/urls.py create mode 100644 pastebin/conf/settings.py create mode 100644 pastebin/conf/test/__init__.py create mode 100644 pastebin/conf/test/settings.py create mode 100644 pastebin/conf/test/urls.py create mode 100644 pastebin/conf/urls.py create mode 100644 pastebin/locale/de/LC_MESSAGES/django.mo create mode 100644 pastebin/locale/de/LC_MESSAGES/django.po create mode 100644 pastebin/locale/en/LC_MESSAGES/django.mo create mode 100644 pastebin/locale/en/LC_MESSAGES/django.po create mode 100644 pastebin/static/.gitignore create mode 100644 pastebin/static/theme.css create mode 100644 pastebin/templates/404.html create mode 100644 pastebin/templates/500.html create mode 100644 pastebin/templates/about.html create mode 100644 pastebin/templates/base.html create mode 100644 requirements.pip create mode 100644 server_configs/dev/apache.conf create mode 100644 server_configs/dev/django.wsgi create mode 100644 server_configs/dev/nginx.conf create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1759fa8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*~ +*.pyc +docs/_build/* +uploads +pastebin/conf/local/*.py +dev.db +pastebin.egg-info diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..ea16ed1 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,308 @@ +# lint Python modules using external checkers. +# +# This is the main checker controlling the other ones and the reports +# generation. It is itself both a raw checker and an astng checker in order +# to: +# * handle message activation / deactivation at the module level +# * handle some basic but necessary stats'data (number of classes, methods...) +# +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add to the black list. It should be a base name, not a +# path. You may set this option multiple times. +ignore=conf +ignore=migrations + +# Pickle collected data for later comparisons. +persistent=yes + +# Set the cache size for astng objects. +cache-size=500 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable only checker(s) with the given id(s). This option conflicts with the +# disable-checker option +#enable-checker= + +# Enable all checker(s) except those with the given id(s). This option +# conflicts with the enable-checker option +#disable-checker= + +# Enable all messages in the listed categories (IRCWEF). +#enable-msg-cat= + +# Disable all messages in the listed categories (IRCWEF). +disable-msg-cat=I + +# Enable the message(s) with the given id(s). +#enable-msg= + +# Disable the message(s) with the given id(s). +disable=W0704,W0201,W0142,W0232,R0903,C0301 + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html +output-format=text + +# Include message's id in output +include-ids=yes + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells wether to display a full report or only the messages +reports=yes + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectivly contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (R0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (R0004). +comment=no + +# Enable the report(s) with the given id(s). +#enable-report= + +# Disable the report(s) with the given id(s). +#disable-report= + + +# checks for : +# * doc strings +# * modules / classes / functions / methods / arguments / variables name +# * number of arguments, local variables, branchs, returns and statements in +# functions, methods +# * required module attributes +# * dangerous default values as arguments +# * redefinition of function / method / class +# * uses of the global statement +# +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# Regular expression which should only match functions or classes name which do +# not require a docstring +no-docstring-rgx=__.*__|get_absolute_url + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}$) + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,v,qs,urlpatterns,register,p,a,t,r,u,x,f,e,setUp,tearDown + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + + +# try to find bugs in the code using type inference +# +[TYPECHECK] + +# Tells wether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamicaly set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. +generated-members=objects,DoesNotExist,id,pk,_default_manager,_meta +# checks for +# * unused variables / imports +# * undefined variables +# * redefinition of variable from builtins or from an outer scope +# * use of variable before assigment +# +[VARIABLES] + +# Tells wether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching names used for dummy variables (i.e. not used). +dummy-variables-rgx=_|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +# checks for : +# * methods without self as first argument +# * overridden methods signature +# * access only to existant members via self +# * attributes not defined in the __init__ method +# * supported interfaces implementation +# * unreachable code +# +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + + +# checks for sign of poor/misdesign: +# * number of methods, attributes, local variables... +# * size, complexity of functions, methods +# +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branchs=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +# checks for +# * external modules dependencies +# * relative / wildcard imports +# * cyclic imports +# * uses of deprecated modules +# +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,string,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report R0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report R0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report R0402 must +# not be disabled) +int-import-graph= + + +# checks for : +# * unauthorized constructions +# * strict indentation +# * line length +# * use of <> instead of != +# +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=88 + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + + +# checks for: +# * warning notes in the code like FIXME, XXX +# * PEP 263: source code with non ascii character but no encoding declaration +# +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +# checks for similarities and duplicated code. This computation may be +# memory / CPU intensive, so you should disable it if you experiments some +# problems. +# +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes diff --git a/README b/README new file mode 100644 index 0000000..fc64e1e --- /dev/null +++ b/README @@ -0,0 +1,4 @@ +Developer documentation is available in Sphinx format in the docs directory. + +Initial installation instructions (including how to build the documentation as +HTML) can be found in docs/install.rst. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..9ed9270 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,88 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf _build/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html + @echo + @echo "Build finished. The HTML pages are in _build/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml + @echo + @echo "Build finished. The HTML pages are in _build/dirhtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in _build/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in _build/qthelp, like this:" + @echo "# qcollectiongenerator _build/qthelp/pastebin.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile _build/qthelp/pastebin.qhc" + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex + @echo + @echo "Build finished; the LaTeX files are in _build/latex." + @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ + "run these through (pdf)latex." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes + @echo + @echo "The overview file is in _build/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in _build/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in _build/doctest/output.txt." diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..0a84897 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +# +# pastebin documentation build configuration file, created by +# sphinx-quickstart on Wed Aug 19 10:27:46 2009. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os +import datetime + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.append(os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'pastebin' +copyright = u'%d, Martin Mahner' % datetime.date.today().year + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_use_modindex = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'pastebindoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'pastebin.tex', u'pastebin Documentation', + u'Martin Mahner', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True diff --git a/docs/deployment.rst b/docs/deployment.rst new file mode 100644 index 0000000..fec4016 --- /dev/null +++ b/docs/deployment.rst @@ -0,0 +1,18 @@ +Deployment +========== + +Staging/Development +------------------- + +`Fabric `_ is used to allow developers to +easily push changes to a previously setup development/staging environment. +To get started, run the following command from within your virtual +environment:: + + pip install fabric==0.9.3 + fab --fabfile src/pastebin/fabfile.py -l + +This will install Fabric and provide a list of available commands. + +When run from src/pastebin, you can just run ``fab [command]`` (i.e. without +the ``-fabfile`` flag). diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..51f2cb8 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,18 @@ +Welcome to pastebin's documentation! +===================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + install + deployment + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/install.rst b/docs/install.rst new file mode 100644 index 0000000..aa11ebf --- /dev/null +++ b/docs/install.rst @@ -0,0 +1,57 @@ +================== +Installation +================== + +Pre-Requisites +=============== + +* `setuptools `_ +* `virtualenv `_ + +To install all of these system dependencies on a Debian-based system, run:: + + sudo apt-get install python-setuptools + sudo easy_install virtualenv + + +Creating the Virtual Environment +================================ + +First, create a clean base environment using virtualenv:: + + virtualenv pastebin + cd pastebin + source bin/activate + + +Installing the Project +====================== + +Install the requirements and the project source:: + + cd path/to/your/pastebin/repository + pip install -r requirements.pip + pip install -e . + + +Configuring a Local Environment +=============================== + +If you're just checking the project out locally, you can copy some example +configuration files to get started quickly:: + + cp pastebin/conf/local/example/* pastebin/conf/local + manage.py syncdb --migrate + + +Building Documentation +====================== + +Documentation is available in ``docs`` and can be built into a number of +formats using `Sphinx `_. To get started:: + + pip install Sphinx + cd docs + make html + +This creates the documentation in HTML format at ``docs/_build/html``. diff --git a/fabfile.py b/fabfile.py new file mode 100644 index 0000000..e85ce1a --- /dev/null +++ b/fabfile.py @@ -0,0 +1,92 @@ +from fabric.api import env, local, run, require, cd +from fabric.operations import _prefix_commands, _prefix_env_vars + +env.disable_known_hosts = True # always fails for me without this +env.hosts = ['pastebin.dev.lincolnloop.com'] +env.root = '/opt/webapps/pastebin' +env.proj_root = env.root + '/src/pastebin' +env.proj_repo = 'git@github.com:myuser/myrepo.git' +env.pip_file = env.proj_root + '/requirements.pip' + + +def deploy(): + """Update source, update pip requirements, syncdb, restart server""" + update() + update_reqs() + syncdb() + restart() + + +def switch(branch): + """Switch the repo branch which the server is using""" + with cd(env.proj_root): + ve_run('git checkout %s' % branch) + restart() + + +def version(): + """Show last commit to repo on server""" + with cd(env.proj_root): + sshagent_run('git log -1') + + +def restart(): + """Restart Apache process""" + run('touch %s/etc/apache/django.wsgi' % env.root) + + +def update_reqs(): + """Update pip requirements""" + ve_run('yes w | pip install -r %s' % env.pip_file) + + +def update(): + """Updates project source""" + with cd(env.proj_root): + sshagent_run('git pull') + + +def syncdb(): + """Run syncdb (along with any pending south migrations)""" + ve_run('manage.py syncdb --migrate') + + +def clone(): + """Clone the repository for the first time""" + with cd('%s/src' % env.root): + sshagent_run('git clone %s' % env.proj_repo) + ve_run('pip install -e %s' % env.proj_root) + + with cd('%s/pastebin/conf/local' % env.proj_root): + run('ln -s ../dev/__init__.py') + run('ln -s ../dev/settings.py') + + +def ve_run(cmd): + """ + Helper function. + Runs a command using the virtualenv environment + """ + require('root') + return sshagent_run('source %s/bin/activate; %s' % (env.root, cmd)) + + +def sshagent_run(cmd): + """ + Helper function. + Runs a command with SSH agent forwarding enabled. + + Note:: Fabric (and paramiko) can't forward your SSH agent. + This helper uses your system's ssh to do so. + """ + # Handle context manager modifications + wrapped_cmd = _prefix_commands(_prefix_env_vars(cmd), 'remote') + try: + host, port = env.host_string.split(':') + return local( + "ssh -p %s -A %s@%s '%s'" % (port, env.user, host, wrapped_cmd) + ) + except ValueError: + return local( + "ssh -A %s@%s '%s'" % (env.user, env.host_string, wrapped_cmd) + ) diff --git a/pastebin/__init__.py b/pastebin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/apps/__init__.py b/pastebin/apps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/apps/api/__init__.py b/pastebin/apps/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/apps/api/handlers.py b/pastebin/apps/api/handlers.py new file mode 100644 index 0000000..402afc5 --- /dev/null +++ b/pastebin/apps/api/handlers.py @@ -0,0 +1,29 @@ +import datetime +import re +from piston.utils import rc +from piston.handler import AnonymousBaseHandler +from pastebin.apps.dpaste.models import Snippet + +class SnippetHandler(AnonymousBaseHandler): + allowed_methods = ('GET', 'POST') + fields = ('title', 'content',) + exclude = ('id', re.compile(r'^private_')) + model = Snippet + + def content_size(self, blogpost): + return len(blogpost.content) + + def read(self, request, secret_id): + post = Snippet.objects.get(secret_id=secret_id) + return post + + def create(self, request): + if not request.POST.get('content'): + return rc.BAD_REQUEST + + s = Snippet.objects.create( + content=request.POST.get('content'), + expires=datetime.datetime.now()+datetime.timedelta(seconds=60*60*24*30) + ) + s.save() + return 'http://dpaste.de%s' % s.get_absolute_url() diff --git a/pastebin/apps/dpaste/__init__.py b/pastebin/apps/dpaste/__init__.py new file mode 100644 index 0000000..d93b5b2 --- /dev/null +++ b/pastebin/apps/dpaste/__init__.py @@ -0,0 +1 @@ +__version__ = '0.2.3' diff --git a/pastebin/apps/dpaste/admin.py b/pastebin/apps/dpaste/admin.py new file mode 100644 index 0000000..d107ef8 --- /dev/null +++ b/pastebin/apps/dpaste/admin.py @@ -0,0 +1,13 @@ +from pastebin.apps.dpaste.models import Snippet +from django.contrib import admin + +class SnippetAdmin(admin.ModelAdmin): + list_display = ( + '__unicode__', + 'author', + 'lexer', + 'published', + 'expires', + ) + +admin.site.register(Snippet, SnippetAdmin) diff --git a/pastebin/apps/dpaste/forms.py b/pastebin/apps/dpaste/forms.py new file mode 100644 index 0000000..4959b8f --- /dev/null +++ b/pastebin/apps/dpaste/forms.py @@ -0,0 +1,109 @@ +from django import forms +from django.conf import settings +from django.utils.translation import ugettext_lazy as _ +from pastebin.apps.dpaste.models import Snippet +from pastebin.apps.dpaste.highlight import LEXER_LIST_ALL, LEXER_LIST, LEXER_DEFAULT +import datetime + +#=============================================================================== +# Snippet Form and Handling +#=============================================================================== + +EXPIRE_CHOICES = ( + (3600, _(u'In one hour')), + (3600*24*7, _(u'In one week')), + (3600*24*30, _(u'In one month')), + (3600*24*30*12*100, _(u'Save forever')), # 100 years, I call it forever ;) +) + +EXPIRE_DEFAULT = 3600*24*30 + +class SnippetForm(forms.ModelForm): + + lexer = forms.ChoiceField( + choices=LEXER_LIST, + initial=LEXER_DEFAULT, + label=_(u'Lexer'), + ) + + expire_options = forms.ChoiceField( + choices=EXPIRE_CHOICES, + initial=EXPIRE_DEFAULT, + label=_(u'Expires'), + ) + + def __init__(self, request, *args, **kwargs): + super(SnippetForm, self).__init__(*args, **kwargs) + self.request = request + + try: + if self.request.session['userprefs'].get('display_all_lexer', False): + self.fields['lexer'].choices = LEXER_LIST_ALL + except KeyError: + pass + + try: + self.fields['author'].initial = self.request.session['userprefs'].get('default_name', '') + except KeyError: + pass + + def save(self, parent=None, *args, **kwargs): + + # Set parent snippet + if parent: + self.instance.parent = parent + + # Add expire datestamp + self.instance.expires = datetime.datetime.now() + \ + datetime.timedelta(seconds=int(self.cleaned_data['expire_options'])) + + # Save snippet in the db + super(SnippetForm, self).save(*args, **kwargs) + + # Add the snippet to the user session list + if self.request.session.get('snippet_list', False): + if len(self.request.session['snippet_list']) >= getattr(settings, 'MAX_SNIPPETS_PER_USER', 10): + self.request.session['snippet_list'].pop(0) + self.request.session['snippet_list'] += [self.instance.pk] + else: + self.request.session['snippet_list'] = [self.instance.pk] + + return self.request, self.instance + + class Meta: + model = Snippet + fields = ( + 'title', + 'content', + 'author', + 'lexer', + ) + + +#=============================================================================== +# User Settings +#=============================================================================== + +USERPREFS_FONT_CHOICES = [(None, _(u'Default'))] + [ + (i, i) for i in sorted(( + 'Monaco', + 'Bitstream Vera Sans Mono', + 'Courier New', + 'Consolas', + )) +] + +USERPREFS_SIZES = [(None, _(u'Default'))] + [(i, '%dpx' % i) for i in range(5, 25)] + +class UserSettingsForm(forms.Form): + + default_name = forms.CharField(label=_(u'Default Name'), required=False) + display_all_lexer = forms.BooleanField( + label=_(u'Display all lexer'), + required=False, + widget=forms.CheckboxInput, + help_text=_(u'This also enables the super secret \'guess lexer\' function.'), + ) + font_family = forms.ChoiceField(label=_(u'Font Family'), required=False, choices=USERPREFS_FONT_CHOICES) + font_size = forms.ChoiceField(label=_(u'Font Size'), required=False, choices=USERPREFS_SIZES) + line_height = forms.ChoiceField(label=_(u'Line Height'), required=False, choices=USERPREFS_SIZES) diff --git a/pastebin/apps/dpaste/highlight.py b/pastebin/apps/dpaste/highlight.py new file mode 100644 index 0000000..dc38127 --- /dev/null +++ b/pastebin/apps/dpaste/highlight.py @@ -0,0 +1,43 @@ +from pygments.lexers import get_all_lexers, get_lexer_by_name, guess_lexer +from pygments.styles import get_all_styles +from pygments.formatters import HtmlFormatter +from pygments.util import ClassNotFound +from pygments import highlight + +LEXER_LIST_ALL = sorted([(i[1][0], i[0]) for i in get_all_lexers()]) +LEXER_LIST = ( + ('bash', 'Bash'), + ('c', 'C'), + ('css', 'CSS'), + ('diff', 'Diff'), + ('django', 'Django/Jinja'), + ('html', 'HTML'), + ('irc', 'IRC logs'), + ('js', 'JavaScript'), + ('php', 'PHP'), + ('pycon', 'Python console session'), + ('pytb', 'Python Traceback'), + ('python', 'Python'), + ('python3', 'Python 3'), + ('rst', 'Restructured Text'), + ('sql', 'SQL'), + ('text', 'Text only'), +) +LEXER_DEFAULT = 'python' + + +class NakedHtmlFormatter(HtmlFormatter): + def wrap(self, source, outfile): + return self._wrap_code(source) + def _wrap_code(self, source): + for i, t in source: + yield i, t + +def pygmentize(code_string, lexer_name='text'): + return highlight(code_string, get_lexer_by_name(lexer_name), NakedHtmlFormatter()) + +def guess_code_lexer(code_string, default_lexer='unknown'): + try: + return guess_lexer(code_string).name + except ClassNotFound: + return default_lexer diff --git a/pastebin/apps/dpaste/locale/de/LC_MESSAGES/django.mo b/pastebin/apps/dpaste/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..c988c49b601967406920de74323c8752bbe3ec27 GIT binary patch literal 3419 zcmbuAO^hQ)6~_w_APgG<3nY9d#V(uKVbiu}BE-hb%&ud5X3TnK9Jgmy$sSDGe(tVJ zyV|O*o-ZU0kP{p@AT9`rLoN{qq8zeF5X8X}oDetQgjfjs5Nc+K^%fS*FU4t^4R&b9A=pF=wYdH(lZ z|Bpbn^HbOUC5WGR#kGIq_&e|^^#2Kb6ub|zojGiR?Op^Q0-pqV-6F_-KLfJ;9q?hW z=iZM&o_`FM!5@M!DgFR{4V-|GO56i^-hV*0e;<4Vd>6a|UVssPzXYy8^PAvL(Eb4i z-vH;}4BP!KI0v>s*5?ig6Cwngpa%aA{@(Tf41;;SUw~}?Wsvvtn(O}yh@bcy{yq)f zb9@JU4DJ7dyuZh=82kGK$m5ERt01qx3F0R@_~UiH2d;q{{1W&&$bS44{4)3t*S-(t zI)GnC{{@Krd9VQT`c)7vh&v$rF$8ad8e~0Q1)m0A2U+JgL5{DtK}aATfHT~F7`zHz z2HF262$_XMW&dY|*S_Q$p5p?@zOlV)sH`8y4j1;3?Q-nqaSghwA|A&x?|B}TW8wb` zwk$q_%J<_Ns86E8t-L&ie{A8TT*edY#=i5upFm|@S(`7S;#!G|sH_pkF>ArPa{1;I zd7OzkiBeO;q3n@8Akulqav&o^!<9={t`1d9K{qq;LV9V{*J?Z_D=*Lb)nFlAE(WXl ztUwRmZ+7nkX7{@1W{a!UWPBu(p**wtI54E`%s_g&yn8XTupla#jS?fOagvg#CLrsMIFrNHnxeG|4E*% z(@Sh6vL6LHq*NY|Avp>LG&^r;Bb7>fkVro1w7`Siyi^AJfr^7(Oa-w$wkpx7Xa%Vy z8AyG`{o%`i5SD_3V4 zbw|PBLV6;Z=pEr@kO$)e)H2D7)VE$^;O&x0;Z|9;D%D$vGr3!D`-ri*HjNWwz0EXK z1Mk@^OubH0mUFG`j#o7l@Ls$cmMzPrQt275^ewOSZMnEqUV8dk2|XC-wP|0m@zZhF zz0!4Wu_Q~2<)zZK(jvw+adKYAU^m!AV#;zeFi;(cGz3^4<;|O;yje(0xQZz{%z}`- z4h5sKY*x0`ci8piX7gsOreii6oAuMpEfz|1E`q(z(HKr!IuP&$7BsyH(Q2KyWT3#-?4p}3<-5dy-Z}9-Y z;c@2(IV0JFbGYE++@i4sF&OhrE#Rgjk?=T-8k`Kk+!WbKk+J9Z6j?hi7mIFoKN%G- zt)4bG*B9`;Ai0Z}C1eZinAYUkGB35768 zAVq-}8y5#JBIpt?_a1An=kIdg^Tpl1gm3Y=3C!T+VVZ?2F?IfB;(mBycRy01Eh@k0exrTf--}7adorB=iapu$TKi2SlfdBvi literal 0 HcmV?d00001 diff --git a/pastebin/apps/dpaste/locale/de/LC_MESSAGES/django.po b/pastebin/apps/dpaste/locale/de/LC_MESSAGES/django.po new file mode 100644 index 0000000..8ab1f6f --- /dev/null +++ b/pastebin/apps/dpaste/locale/de/LC_MESSAGES/django.po @@ -0,0 +1,236 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-05-07 12:23+0200\n" +"PO-Revision-Date: 2008-08-10 01:20+0100\n" +"Last-Translator: Martin Mahner \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: forms.py:13 +msgid "In one hour" +msgstr "In einer Stunde" + +#: forms.py:14 +msgid "In one week" +msgstr "In einer Woche" + +#: forms.py:15 +msgid "In one month" +msgstr "In einem Monat" + +#: forms.py:16 +msgid "Save forever" +msgstr "Für immer speichern" + +#: forms.py:26 models.py:20 +msgid "Lexer" +msgstr "Syntax" + +#: forms.py:32 models.py:22 +msgid "Expires" +msgstr "Erlischt" + +#: forms.py:87 forms.py:96 +msgid "Default" +msgstr "Standard" + +#: forms.py:100 +msgid "Default Name" +msgstr "Standard Name" + +#: forms.py:102 +msgid "Display all lexer" +msgstr "Alle Syntaxformate anzeigen" + +#: forms.py:105 +msgid "This also enables the super secret 'guess lexer' function." +msgstr "Dies aktiviert auch die super geheime 'Syntax erraten' Funktion." + +#: forms.py:107 +msgid "Font Family" +msgstr "Schriftart" + +#: forms.py:108 +msgid "Font Size" +msgstr "Schriftgröße" + +#: forms.py:109 +msgid "Line Height" +msgstr "Zeilenhöhe" + +#: models.py:15 +msgid "Secret ID" +msgstr "Geheime ID" + +#: models.py:16 +msgid "Title" +msgstr "Titel" + +#: models.py:17 +msgid "Author" +msgstr "Autor" + +#: models.py:18 +msgid "Content" +msgstr "Inhalt" + +#: models.py:19 +msgid "Highlighted Content" +msgstr "Gehighlighteter Content" + +#: models.py:21 +msgid "Published" +msgstr "Veröffentlicht" + +#: views.py:145 +msgid "No changes were made between this two files." +msgstr "Zwischen diesen beiden Dateien wurden keine Änderungen durchgeführt." + +#: templates/dpaste/snippet_details.html:18 +#: templates/dpaste/snippet_details.html:21 +#: templates/dpaste/snippet_details.html:44 +#: templates/dpaste/snippet_details.html:81 +#: templates/dpaste/snippet_details.html:83 +#: templates/dpaste/snippet_list.html:4 templates/dpaste/snippet_list.html:13 +msgid "Snippet" +msgstr "Snippet" + +#: templates/dpaste/snippet_details.html:23 +#, python-format +msgid "(Copy of snippet #%(parent_id)s)" +msgstr "(Kopie von Snippet #%(parent_id)s)" + +#: templates/dpaste/snippet_details.html:25 +#: templates/dpaste/snippet_list.html:14 +msgid "DATETIME_FORMAT" +msgstr "" + +#: templates/dpaste/snippet_details.html:25 +msgid "UTC" +msgstr "UTC" + +#: templates/dpaste/snippet_details.html:35 +msgid "Time to life" +msgstr "" + +#: templates/dpaste/snippet_details.html:38 +msgid "Really delete this snippet?" +msgstr "Wirklich dieses Snippet löschen?" + +#: templates/dpaste/snippet_details.html:41 +msgid "Wordwrap" +msgstr "" + +#: templates/dpaste/snippet_details.html:45 +#, python-format +msgid "by %(author)s" +msgstr "von %(author)s" + +#: templates/dpaste/snippet_details.html:59 +msgid "Write an answer" +msgstr "Schreibe eine Antwort" + +#: templates/dpaste/snippet_details.html:69 +msgid "History" +msgstr "Verlauf" + +#: templates/dpaste/snippet_details.html:89 +msgid "Compare" +msgstr "Vergleichen" + +#: templates/dpaste/snippet_details.html:94 +msgid "Options" +msgstr "Optionen" + +#: templates/dpaste/snippet_details.html:95 +msgid "View raw" +msgstr "Rohformat" + +#: templates/dpaste/snippet_diff.html:4 +msgid "Close" +msgstr "Schließen" + +#: templates/dpaste/snippet_diff.html:5 +#, python-format +msgid "" +"\n" +" Diff between\n" +" Snippet #%(filea_id)s\n" +" and\n" +" Snippet #%(fileb_id)s\n" +" " +msgstr "" +"\n" +" Diff zwischen\n" +" Snippet #%(filea_id)s\n" +" und\n" +" Snippet #%(fileb_id)s\n" +" " + +#: templates/dpaste/snippet_form.html:10 +msgid "Guess lexer" +msgstr "Syntax erraten" + +#: templates/dpaste/snippet_form.html:15 +msgid "Paste it" +msgstr "Paste es" + +#: templates/dpaste/snippet_list.html:6 +#, python-format +msgid "Your latest %(snippets_max)s snippets" +msgstr "Deine neuesten %(snippets_max)s Snippets" + +#: templates/dpaste/snippet_list.html:19 +msgid "No snippets available." +msgstr "Keine Snippets verfügbar" + +#: templates/dpaste/snippet_list.html:24 templates/dpaste/userprefs.html:25 +msgid "DATA_STORED_IN_A_COOKIE_HINT" +msgstr "" +"

Hinweis: Deine Daten werden in einem Cookie gespeichert." + +#: templates/dpaste/snippet_new.html:4 templates/dpaste/snippet_new.html:8 +msgid "New snippet" +msgstr "Neues Snippet" + +#: templates/dpaste/snippet_new.html:5 +msgid "Paste a new snippet" +msgstr "Schreibe ein neues Snippet" + +#: templates/dpaste/snippet_new.html:14 +msgid "DPASTE_HOMEPAGE_TITLE" +msgstr "dpaste" + +#: templates/dpaste/snippet_new.html:15 +msgid "DPASTE_HOMEPAGE_DESCRIPTION" +msgstr "" +"dpaste.de ist ein Codespeicher inspiriert von dpaste.com. Die Vorteile und den Quellcode dieser Seite findest du " +"bei Google Code." + +#: templates/dpaste/userprefs.html:5 templates/dpaste/userprefs.html.py:15 +msgid "User Settings" +msgstr "Benutzereinstellungen" + +#: templates/dpaste/userprefs.html:11 +msgid "USER_PREFS_SAVED_SUCCESSFULLY" +msgstr "Deine Einstellungen wurden erfolgreich gespeichert." + +#: templates/dpaste/userprefs.html:20 +msgid "Save settings" +msgstr "Einstellungen speichern" + +#~ msgid "WHAT_IS_THIS_TITLE" +#~ msgstr "Was ist das hier?" + +#~ msgid "Youre displaying the whole bunch of lexers!" +#~ msgstr "Du siehst derzeit das ganze Bündel an Lexern!" diff --git a/pastebin/apps/dpaste/locale/en/LC_MESSAGES/django.mo b/pastebin/apps/dpaste/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..93d5f4b4c9f4863284254f50359ed22ab8eb17c2 GIT binary patch literal 1175 zcma)5-Hy{n6rR#8v`e`FsZ!MzX~YepXdGuN)Wu{YvWa(z$e&_oC9a~0ebzB`W~`aX zcJmay>RYt0(nmmW%`>#(vp0|;ZW!s)H|NZE=A1J=esyQ>Plojk@Dq>%w}8KZYP|+3 z{~O>(;6LCy;D;|5yAAfiH^Il?ufQX40FJ?T!GC~{fWLub*l({f_7B+mlCkUHf5G2_ z_x2e37JL_6`F{pK0XM-9z$-AWV35~&s(Nn#Ujvo?{etYnLMq03owzfP;_)=>&HJNy zXWku;pZCN0v;HV%y-6pEu^$h^N#``2_rj<Zw#>*cmA7JaeU8%kSvZYQ_WqPgZJZd|EKkMp zIWr_a6)Yk??=z&4b|Jmxn$)5Q-^X2 zYLso3mgt%)1+FGuTMMYP$+KKxCN_w%WnKj@HoPVI($M+Qy`^(y&}dwRdx>5(?zMMD zt0CJSKgm^E4~k4Lq;hyC4AItAt`|j~aElrfs#9zA$?cWj%e2l4s#BDW^d(+gi@Ho? zJgv`o7rHv-ww;e=+HR2glCPk#+tI#qv8X;_pFiAJasQw0`i)Dx2pLid`uiOl{1^%L O_IzDEpOqJsdh8wGyG#TC literal 0 HcmV?d00001 diff --git a/pastebin/apps/dpaste/locale/en/LC_MESSAGES/django.po b/pastebin/apps/dpaste/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..c02770f --- /dev/null +++ b/pastebin/apps/dpaste/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,226 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-05-07 12:23+0200\n" +"PO-Revision-Date: 2008-08-10 01:19+0100\n" +"Last-Translator: Martin Mahner \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: forms.py:13 +msgid "In one hour" +msgstr "" + +#: forms.py:14 +msgid "In one week" +msgstr "" + +#: forms.py:15 +msgid "In one month" +msgstr "" + +#: forms.py:16 +msgid "Save forever" +msgstr "" + +#: forms.py:26 models.py:20 +msgid "Lexer" +msgstr "Syntax" + +#: forms.py:32 models.py:22 +msgid "Expires" +msgstr "" + +#: forms.py:87 forms.py:96 +msgid "Default" +msgstr "" + +#: forms.py:100 +msgid "Default Name" +msgstr "" + +#: forms.py:102 +msgid "Display all lexer" +msgstr "Display all syntax modes" + +#: forms.py:105 +msgid "This also enables the super secret 'guess lexer' function." +msgstr "This also enables the super secret 'guess syntax' function." + +#: forms.py:107 +msgid "Font Family" +msgstr "" + +#: forms.py:108 +msgid "Font Size" +msgstr "" + +#: forms.py:109 +msgid "Line Height" +msgstr "" + +#: models.py:15 +msgid "Secret ID" +msgstr "" + +#: models.py:16 +msgid "Title" +msgstr "" + +#: models.py:17 +msgid "Author" +msgstr "" + +#: models.py:18 +msgid "Content" +msgstr "" + +#: models.py:19 +msgid "Highlighted Content" +msgstr "" + +#: models.py:21 +msgid "Published" +msgstr "" + +#: views.py:145 +msgid "No changes were made between this two files." +msgstr "" + +#: templates/dpaste/snippet_details.html:18 +#: templates/dpaste/snippet_details.html:21 +#: templates/dpaste/snippet_details.html:44 +#: templates/dpaste/snippet_details.html:81 +#: templates/dpaste/snippet_details.html:83 +#: templates/dpaste/snippet_list.html:4 templates/dpaste/snippet_list.html:13 +msgid "Snippet" +msgstr "" + +#: templates/dpaste/snippet_details.html:23 +#, python-format +msgid "(Copy of snippet #%(parent_id)s)" +msgstr "" + +#: templates/dpaste/snippet_details.html:25 +#: templates/dpaste/snippet_list.html:14 +msgid "DATETIME_FORMAT" +msgstr "" + +#: templates/dpaste/snippet_details.html:25 +msgid "UTC" +msgstr "" + +#: templates/dpaste/snippet_details.html:35 +msgid "Time to life" +msgstr "" + +#: templates/dpaste/snippet_details.html:38 +msgid "Really delete this snippet?" +msgstr "" + +#: templates/dpaste/snippet_details.html:41 +msgid "Wordwrap" +msgstr "" + +#: templates/dpaste/snippet_details.html:45 +#, python-format +msgid "by %(author)s" +msgstr "" + +#: templates/dpaste/snippet_details.html:59 +msgid "Write an answer" +msgstr "" + +#: templates/dpaste/snippet_details.html:69 +msgid "History" +msgstr "" + +#: templates/dpaste/snippet_details.html:89 +msgid "Compare" +msgstr "" + +#: templates/dpaste/snippet_details.html:94 +msgid "Options" +msgstr "" + +#: templates/dpaste/snippet_details.html:95 +msgid "View raw" +msgstr "" + +#: templates/dpaste/snippet_diff.html:4 +msgid "Close" +msgstr "" + +#: templates/dpaste/snippet_diff.html:5 +#, python-format +msgid "" +"\n" +" Diff between\n" +" Snippet #%(filea_id)s\n" +" and\n" +" Snippet #%(fileb_id)s\n" +" " +msgstr "" + +#: templates/dpaste/snippet_form.html:10 +msgid "Guess lexer" +msgstr "Guess syntax" + +#: templates/dpaste/snippet_form.html:15 +msgid "Paste it" +msgstr "" + +#: templates/dpaste/snippet_list.html:6 +#, python-format +msgid "Your latest %(snippets_max)s snippets" +msgstr "" + +#: templates/dpaste/snippet_list.html:19 +msgid "No snippets available." +msgstr "" + +#: templates/dpaste/snippet_list.html:24 templates/dpaste/userprefs.html:25 +msgid "DATA_STORED_IN_A_COOKIE_HINT" +msgstr "

Remember: Your data is stored in a cookie.

" + +#: templates/dpaste/snippet_new.html:4 templates/dpaste/snippet_new.html:8 +msgid "New snippet" +msgstr "" + +#: templates/dpaste/snippet_new.html:5 +msgid "Paste a new snippet" +msgstr "" + +#: templates/dpaste/snippet_new.html:14 +msgid "DPASTE_HOMEPAGE_TITLE" +msgstr "dpaste" + +#: templates/dpaste/snippet_new.html:15 +msgid "DPASTE_HOMEPAGE_DESCRIPTION" +msgstr "" +"dpaste is code pastebin originally inspired by dpaste.com. Find the advantages and the public sourcecode on Google Code." + +#: templates/dpaste/userprefs.html:5 templates/dpaste/userprefs.html.py:15 +msgid "User Settings" +msgstr "" + +#: templates/dpaste/userprefs.html:11 +msgid "USER_PREFS_SAVED_SUCCESSFULLY" +msgstr "Your preferences were successfully saved." + +#: templates/dpaste/userprefs.html:20 +msgid "Save settings" +msgstr "" + +#~ msgid "WHAT_IS_THIS_TITLE" +#~ msgstr "What is this?" diff --git a/pastebin/apps/dpaste/management/__init__.py b/pastebin/apps/dpaste/management/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/apps/dpaste/management/commands/__init__.py b/pastebin/apps/dpaste/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/apps/dpaste/management/commands/cleanup_snippets.py b/pastebin/apps/dpaste/management/commands/cleanup_snippets.py new file mode 100644 index 0000000..bafac42 --- /dev/null +++ b/pastebin/apps/dpaste/management/commands/cleanup_snippets.py @@ -0,0 +1,22 @@ +import datetime +import sys +from optparse import make_option +from django.core.management.base import CommandError, LabelCommand +from pastebin.apps.dpaste.models import Snippet + +class Command(LabelCommand): + option_list = LabelCommand.option_list + ( + make_option('--dry-run', '-d', action='store_true', dest='dry_run', + help='Don\'t do anything.'), + ) + help = "Purges snippets that are expired" + + def handle(self, *args, **options): + deleteable_snippets = Snippet.objects.filter(expires__lte=datetime.datetime.now()) + sys.stdout.write(u"%s snippets gets deleted:\n" % deleteable_snippets.count()) + for d in deleteable_snippets: + sys.stdout.write(u"- %s (%s)\n" % (d.secret_id, d.expires)) + if options.get('dry_run'): + sys.stdout.write(u'Dry run - Doing nothing! *crossingfingers*\n') + else: + deleteable_snippets.delete() diff --git a/pastebin/apps/dpaste/models.py b/pastebin/apps/dpaste/models.py new file mode 100644 index 0000000..d4182be --- /dev/null +++ b/pastebin/apps/dpaste/models.py @@ -0,0 +1,48 @@ +import datetime +import difflib +import random +import mptt +from django.db import models +from django.db.models import permalink +from django.utils.translation import ugettext_lazy as _ +from pastebin.apps.dpaste.highlight import LEXER_DEFAULT, pygmentize + +t = 'abcdefghijkmnopqrstuvwwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ1234567890' +def generate_secret_id(length=4): + return ''.join([random.choice(t) for i in range(length)]) + +class Snippet(models.Model): + secret_id = models.CharField(_(u'Secret ID'), max_length=4, blank=True) + title = models.CharField(_(u'Title'), max_length=120, blank=True) + author = models.CharField(_(u'Author'), max_length=30, blank=True) + content = models.TextField(_(u'Content'), ) + content_highlighted = models.TextField(_(u'Highlighted Content'), blank=True) + lexer = models.CharField(_(u'Lexer'), max_length=30, default=LEXER_DEFAULT) + published = models.DateTimeField(_(u'Published'), blank=True) + expires = models.DateTimeField(_(u'Expires'), blank=True, help_text='asdf') + parent = models.ForeignKey('self', null=True, blank=True, related_name='children') + + class Meta: + ordering = ('-published',) + + def get_linecount(self): + return len(self.content.splitlines()) + + def content_splitted(self): + return self.content_highlighted.splitlines() + + def save(self, *args, **kwargs): + if not self.pk: + self.published = datetime.datetime.now() + self.secret_id = generate_secret_id() + self.content_highlighted = pygmentize(self.content, self.lexer) + super(Snippet, self).save(*args, **kwargs) + + @permalink + def get_absolute_url(self): + return ('snippet_details', (self.secret_id,)) + + def __unicode__(self): + return '%s' % self.secret_id + +mptt.register(Snippet, order_insertion_by=['content']) diff --git a/pastebin/apps/dpaste/templates/dpaste/base.html b/pastebin/apps/dpaste/templates/dpaste/base.html new file mode 100644 index 0000000..63913c1 --- /dev/null +++ b/pastebin/apps/dpaste/templates/dpaste/base.html @@ -0,0 +1 @@ +{% extends "base.html" %} \ No newline at end of file diff --git a/pastebin/apps/dpaste/templates/dpaste/snippet_details.html b/pastebin/apps/dpaste/templates/dpaste/snippet_details.html new file mode 100644 index 0000000..bdbd3f0 --- /dev/null +++ b/pastebin/apps/dpaste/templates/dpaste/snippet_details.html @@ -0,0 +1,174 @@ +{% extends "dpaste/base.html" %} +{% load mptt_tags %} +{% load i18n %} + +{% block extrahead %} + {% if request.session.userprefs %} + + {% endif %} +{% endblock %} + +{% block title %}{% trans "Snippet" %} #{{ snippet.pk }}{% endblock %} +{% block headline %} +

+ {% trans "Snippet" %} #{{ snippet.pk }} + {% if snippet.parent_id %} + {% blocktrans with snippet.parent.get_absolute_url as parent_url and snippet.parent.id as parent_id %}(Copy of snippet #{{ parent_id }}){% endblocktrans %} + {% endif %} + {{ snippet.published|date:_("DATETIME_FORMAT") }} ({% trans "UTC" %}) +

+{% endblock %} +{% load dpaste_tags %} + +{% block content %} + + +
+
+ TTL: {{ snippet.expires|timeuntil }} + — + {% if snippet.pk|in_list:request.session.snippet_list %} + Delete now! + — + {% endif %} + {% trans "Wordwrap" %} +
+

+ {% if snippet.title %}{{ snippet.title }}{% else %} {% trans "Snippet" %} #{{ snippet.id}}{% endif %} + {% if snippet.author %}{% blocktrans with snippet.author as author %}by {{ author }}{% endblocktrans %}{% endif %} +

+ +
+
+ + + + + +
{% for l in lines %}{{ forloop.counter }}{% endfor %}
{% for line in snippet.content_splitted %}
{% if line %}{{ line|safe }}{% else %} {% endif %}
{% endfor %}
+
+
+ +

{% trans "Write an answer" %} →

+ +
+{% endblock %} + + + +{% block sidebar %} +

{% trans "History" %}

+ +
+ {% csrf_token %} +
+ {% for tree_item,structure in tree|tree_info %} + {% if structure.new_level %}
  • {% else %}
  • {% endif %} +
    + + + + + {% ifequal snippet tree_item %} + {% trans "Snippet" %} #{{ tree_item.id }} + {% else %} + {% trans "Snippet" %} #{{ tree_item.id }} + {% endifequal %} +
    + {% for level in structure.closed_levels %}
{% endfor %} + {% endfor %} +
+ +
+
+
+ +

{% trans "Options" %}

+

{% trans "View raw" %}

+{% endblock %} + +{% block script_footer %} + + + +{% endblock %} diff --git a/pastebin/apps/dpaste/templates/dpaste/snippet_details_raw.html b/pastebin/apps/dpaste/templates/dpaste/snippet_details_raw.html new file mode 100644 index 0000000..47e704a --- /dev/null +++ b/pastebin/apps/dpaste/templates/dpaste/snippet_details_raw.html @@ -0,0 +1 @@ +{{ snippet.content|safe }} \ No newline at end of file diff --git a/pastebin/apps/dpaste/templates/dpaste/snippet_diff.html b/pastebin/apps/dpaste/templates/dpaste/snippet_diff.html new file mode 100644 index 0000000..ca403d4 --- /dev/null +++ b/pastebin/apps/dpaste/templates/dpaste/snippet_diff.html @@ -0,0 +1,13 @@ +{% load i18n %} + +

+ ({% trans "Close" %}) + {% blocktrans with fileA.get_absolute_url as filea_url and fileB.get_absolute_url as fileb_url and fileA.id as filea_id and fileB.id as fileb_id %} + Diff between + Snippet #{{ filea_id }} + and + Snippet #{{ fileb_id }} + {% endblocktrans %} +

+ +
{{ difftext|safe }}
diff --git a/pastebin/apps/dpaste/templates/dpaste/snippet_form.html b/pastebin/apps/dpaste/templates/dpaste/snippet_form.html new file mode 100644 index 0000000..3b9e1e9 --- /dev/null +++ b/pastebin/apps/dpaste/templates/dpaste/snippet_form.html @@ -0,0 +1,19 @@ +{% load i18n %} +
+{% csrf_token %} +
    + {% for field in snippet_form %} +
  1. + {{ field.errors }} + {{ field.label_tag }} + {{ field }} + {% if request.session.userprefs.display_all_lexer %} + {% ifequal field.name "lexer" %} + + {% endifequal %} + {% endif %} +
  2. + {% endfor %} +
  3. +
+
\ No newline at end of file diff --git a/pastebin/apps/dpaste/templates/dpaste/snippet_list.html b/pastebin/apps/dpaste/templates/dpaste/snippet_list.html new file mode 100644 index 0000000..658b522 --- /dev/null +++ b/pastebin/apps/dpaste/templates/dpaste/snippet_list.html @@ -0,0 +1,26 @@ +{% extends "dpaste/base.html" %} +{% load i18n %} + +{% block title %}{% trans "Snippet" %} #{{ snippet.pk }}{% endblock %} +{% block headline %} +

{% blocktrans %}Your latest {{ snippets_max }} snippets{% endblocktrans %}

+{% endblock %} + +{% block content %} + {% if snippet_list %} + {% for snippet in snippet_list %} +

+ {% trans "Snippet" %} #{{ snippet.pk }} + ~ {{ snippet.published|date:_("DATETIME_FORMAT") }} +

+

{{ snippet.content|truncatewords:40 }}

+ {% endfor %} + {% else %} +

{% trans "No snippets available." %}

+ {% endif %} + + +
+ {% trans "DATA_STORED_IN_A_COOKIE_HINT" %} +
+{% endblock %} diff --git a/pastebin/apps/dpaste/templates/dpaste/snippet_new.html b/pastebin/apps/dpaste/templates/dpaste/snippet_new.html new file mode 100644 index 0000000..f74188f --- /dev/null +++ b/pastebin/apps/dpaste/templates/dpaste/snippet_new.html @@ -0,0 +1,39 @@ +{% extends "dpaste/base.html" %} +{% load i18n %} + +{% block title %}{% trans "New snippet" %}{% endblock %} +{% block headline %}

{% trans "Paste a new snippet" %}

{% endblock %} + +{% block content %} +

{% trans "New snippet" %}

+ {% include "dpaste/snippet_form.html" %} +{% endblock %} + + +{% block sidebar %} +

{% trans "DPASTE_HOMEPAGE_TITLE" %}

+

{% trans "DPASTE_HOMEPAGE_DESCRIPTION" %}

+{% endblock %} + + +{% block script_footer %} + + +{% endblock %} diff --git a/pastebin/apps/dpaste/templates/dpaste/userprefs.html b/pastebin/apps/dpaste/templates/dpaste/userprefs.html new file mode 100644 index 0000000..79ec935 --- /dev/null +++ b/pastebin/apps/dpaste/templates/dpaste/userprefs.html @@ -0,0 +1,28 @@ +{% extends "dpaste/base.html" %} +{% load i18n %} + +{% block headline %} +

{% trans "User Settings" %}

+{% endblock %} + +{% block content %} + {% if settings_saved %} +
+ {% trans "USER_PREFS_SAVED_SUCCESSFULLY" %} +
+ {% endif %} + +

{% trans "User Settings" %}

+ +
+ {% csrf_token %} +
    + {{ settings_form.as_ul }} +
  1. +
+
+ +
+ {% trans "DATA_STORED_IN_A_COOKIE_HINT" %} +
+{% endblock %} diff --git a/pastebin/apps/dpaste/templatetags/__init__.py b/pastebin/apps/dpaste/templatetags/__init__.py new file mode 100644 index 0000000..11d27f8 --- /dev/null +++ b/pastebin/apps/dpaste/templatetags/__init__.py @@ -0,0 +1 @@ +__version__ = '0.1' diff --git a/pastebin/apps/dpaste/templatetags/dpaste_tags.py b/pastebin/apps/dpaste/templatetags/dpaste_tags.py new file mode 100644 index 0000000..4f2e463 --- /dev/null +++ b/pastebin/apps/dpaste/templatetags/dpaste_tags.py @@ -0,0 +1,7 @@ +from django.template import Library + +register = Library() + +@register.filter +def in_list(value,arg): + return value in arg diff --git a/pastebin/apps/dpaste/urls.py b/pastebin/apps/dpaste/urls.py new file mode 100644 index 0000000..65acb34 --- /dev/null +++ b/pastebin/apps/dpaste/urls.py @@ -0,0 +1,14 @@ +from django.conf.urls.defaults import patterns, url +from django.conf import settings + + +urlpatterns = patterns('pastebin.apps.dpaste.views', + url(r'^$', 'snippet_new', name='snippet_new'), + url(r'^guess/$', 'guess_lexer', name='snippet_guess_lexer'), + url(r'^diff/$', 'snippet_diff', name='snippet_diff'), + url(r'^your-latest/$', 'snippet_userlist', name='snippet_userlist'), + url(r'^your-settings/$', 'userprefs', name='snippet_userprefs'), + url(r'^(?P[a-zA-Z0-9]{4})/$', 'snippet_details', name='snippet_details'), + url(r'^(?P[a-zA-Z0-9]{4})/delete/$', 'snippet_delete', name='snippet_delete'), + url(r'^(?P[a-zA-Z0-9]{4})/raw/$', 'snippet_details', {'template_name': 'dpaste/snippet_details_raw.html', 'is_raw': True}, name='snippet_details_raw'), +) \ No newline at end of file diff --git a/pastebin/apps/dpaste/views.py b/pastebin/apps/dpaste/views.py new file mode 100644 index 0000000..070e509 --- /dev/null +++ b/pastebin/apps/dpaste/views.py @@ -0,0 +1,165 @@ +from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404 +from django.template.context import RequestContext +from django.http import HttpResponseRedirect, HttpResponseBadRequest, HttpResponse, HttpResponseForbidden +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist +from django.utils.translation import ugettext_lazy as _ +from pastebin.apps.dpaste.forms import SnippetForm, UserSettingsForm +from pastebin.apps.dpaste.models import Snippet +from pastebin.apps.dpaste.highlight import pygmentize, guess_code_lexer +from django.core.urlresolvers import reverse +from django.utils import simplejson +import difflib + +def snippet_new(request, template_name='dpaste/snippet_new.html'): + + if request.method == "POST": + snippet_form = SnippetForm(data=request.POST, request=request) + if snippet_form.is_valid(): + request, new_snippet = snippet_form.save() + return HttpResponseRedirect(new_snippet.get_absolute_url()) + else: + snippet_form = SnippetForm(request=request) + + template_context = { + 'snippet_form': snippet_form, + } + + return render_to_response( + template_name, + template_context, + RequestContext(request) + ) + + +def snippet_details(request, snippet_id, template_name='dpaste/snippet_details.html', is_raw=False): + + snippet = get_object_or_404(Snippet, secret_id=snippet_id) + + tree = snippet.get_root() + tree = tree.get_descendants(include_self=True) + + new_snippet_initial = { + 'content': snippet.content, + 'lexer': snippet.lexer, + } + + if request.method == "POST": + snippet_form = SnippetForm(data=request.POST, request=request, initial=new_snippet_initial) + if snippet_form.is_valid(): + request, new_snippet = snippet_form.save(parent=snippet) + return HttpResponseRedirect(new_snippet.get_absolute_url()) + else: + snippet_form = SnippetForm(initial=new_snippet_initial, request=request) + + template_context = { + 'snippet_form': snippet_form, + 'snippet': snippet, + 'lines': range(snippet.get_linecount()), + 'tree': tree, + } + + response = render_to_response( + template_name, + template_context, + RequestContext(request) + ) + + if is_raw: + response['Content-Type'] = 'text/plain' + return response + else: + return response + +def snippet_delete(request, snippet_id): + snippet = get_object_or_404(Snippet, secret_id=snippet_id) + try: + snippet_list = request.session['snippet_list'] + except KeyError: + return HttpResponseForbidden('You have no recent snippet list, cookie error?') + if not snippet.pk in snippet_list: + return HttpResponseForbidden('That\'s not your snippet, sucka!') + snippet.delete() + return HttpResponseRedirect(reverse('snippet_new')) + +def snippet_userlist(request, template_name='dpaste/snippet_list.html'): + + try: + snippet_list = get_list_or_404(Snippet, pk__in=request.session.get('snippet_list', None)) + except ValueError: + snippet_list = None + + template_context = { + 'snippets_max': getattr(settings, 'MAX_SNIPPETS_PER_USER', 10), + 'snippet_list': snippet_list, + } + + return render_to_response( + template_name, + template_context, + RequestContext(request) + ) + + +def userprefs(request, template_name='dpaste/userprefs.html'): + + if request.method == 'POST': + settings_form = UserSettingsForm(request.POST, initial=request.session.get('userprefs', None)) + if settings_form.is_valid(): + request.session['userprefs'] = settings_form.cleaned_data + settings_saved = True + else: + settings_form = UserSettingsForm(initial=request.session.get('userprefs', None)) + settings_saved = False + + template_context = { + 'settings_form': settings_form, + 'settings_saved': settings_saved, + } + + return render_to_response( + template_name, + template_context, + RequestContext(request) + ) + +def snippet_diff(request, template_name='dpaste/snippet_diff.html'): + + if request.GET.get('a').isdigit() and request.GET.get('b').isdigit(): + try: + fileA = Snippet.objects.get(pk=int(request.GET.get('a'))) + fileB = Snippet.objects.get(pk=int(request.GET.get('b'))) + except ObjectDoesNotExist: + return HttpResponseBadRequest(u'Selected file(s) does not exist.') + else: + return HttpResponseBadRequest(u'You must select two snippets.') + + if fileA.content != fileB.content: + d = difflib.unified_diff( + fileA.content.splitlines(), + fileB.content.splitlines(), + 'Original', + 'Current', + lineterm='' + ) + difftext = '\n'.join(d) + difftext = pygmentize(difftext, 'diff') + else: + difftext = _(u'No changes were made between this two files.') + + template_context = { + 'difftext': difftext, + 'fileA': fileA, + 'fileB': fileB, + } + + return render_to_response( + template_name, + template_context, + RequestContext(request) + ) + +def guess_lexer(request): + code_string = request.GET.get('codestring', False) + response = simplejson.dumps({'lexer': guess_code_lexer(code_string)}) + return HttpResponse(response) diff --git a/pastebin/bin/manage.py b/pastebin/bin/manage.py new file mode 100755 index 0000000..fca5b86 --- /dev/null +++ b/pastebin/bin/manage.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +import os +import sys +from django import get_version +from django.core.management import execute_from_command_line, LaxOptionParser +from django.core.management.base import BaseCommand + +# Work out the project module name and root directory, assuming that this file +# is located at [project]/bin/manage.py +PROJECT_DIR, PROJECT_MODULE_NAME = os.path.split( + os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) + +# Check that the project module can be imported. +try: + __import__(PROJECT_MODULE_NAME) +except ImportError: + # Couldn't import the project, place it on the Python path and try again. + sys.path.append(PROJECT_DIR) + try: + __import__(PROJECT_MODULE_NAME) + except ImportError: + sys.stderr.write("Error: Can't import the \"%s\" project module." % + PROJECT_MODULE_NAME) + sys.exit(1) + +def has_settings_option(): + parser = LaxOptionParser(usage="%prog subcommand [options] [args]", + version=get_version(), + option_list=BaseCommand.option_list) + try: + options = parser.parse_args(sys.argv[:])[0] + except: + return False # Ignore any option errors at this point. + return bool(options.settings) + +if not has_settings_option() and not 'DJANGO_SETTINGS_MODULE' in os.environ: + settings_module = '%s.conf.local.settings' % PROJECT_MODULE_NAME + os.environ['DJANGO_SETTINGS_MODULE'] = settings_module + +execute_from_command_line() diff --git a/pastebin/conf/__init__.py b/pastebin/conf/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/conf/common/__init__.py b/pastebin/conf/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/conf/common/urls/__init__.py b/pastebin/conf/common/urls/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/conf/common/urls/admin.py b/pastebin/conf/common/urls/admin.py new file mode 100644 index 0000000..e330a95 --- /dev/null +++ b/pastebin/conf/common/urls/admin.py @@ -0,0 +1,9 @@ +from django.conf.urls.defaults import patterns, include +from django.contrib import admin + +admin.autodiscover() + +urlpatterns = patterns('', + (r'^admin/doc/', include('django.contrib.admindocs.urls')), + (r'^admin/', include(admin.site.urls)), +) diff --git a/pastebin/conf/dev/__init__.py b/pastebin/conf/dev/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/conf/dev/settings.py b/pastebin/conf/dev/settings.py new file mode 100644 index 0000000..b0f2358 --- /dev/null +++ b/pastebin/conf/dev/settings.py @@ -0,0 +1,17 @@ +from pastebin.conf.settings import * + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ROOT_URLCONF = 'pastebin.conf.dev.urls' + +MEDIA_ROOT = os.path.join(VAR_ROOT, 'uploads') + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'pastebin', +# 'USER': 'dbuser', +# 'PASSWORD': 'dbpassword', + } +} diff --git a/pastebin/conf/dev/urls.py b/pastebin/conf/dev/urls.py new file mode 100644 index 0000000..a44386d --- /dev/null +++ b/pastebin/conf/dev/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls.defaults import * +from django.conf import settings + +CONF_MODULE = '%s.conf' % settings.PROJECT_MODULE_NAME + +urlpatterns = patterns('', + (r'', include('%s.urls' % CONF_MODULE)), + (r'', include('%s.common.urls.admin' % CONF_MODULE)), +) diff --git a/pastebin/conf/settings.py b/pastebin/conf/settings.py new file mode 100644 index 0000000..5658222 --- /dev/null +++ b/pastebin/conf/settings.py @@ -0,0 +1,105 @@ +# Import global settings to make it easier to extend settings. +from django.conf.global_settings import * + +#============================================================================== +# Generic Django project settings +#============================================================================== + +DEBUG = False +TEMPLATE_DEBUG = DEBUG + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +TIME_ZONE = 'America/Chicago' +USE_I18N = True +SITE_ID = 1 + +# Make this unique, and don't share it with anybody. +SECRET_KEY = '' + +#============================================================================== +# I18N +#============================================================================== + +USE_I18N = True +USE_L10N = False + +LANGUAGE_CODE = 'en' +LANGUAGES = ( + ('en', 'English'), +) + +#============================================================================== +# Calculation of directories relative to the module location +#============================================================================== +import os +import sys +import pastebin + +PROJECT_DIR, PROJECT_MODULE_NAME = os.path.split( + os.path.dirname(os.path.realpath(pastebin.__file__)) +) + +PYTHON_BIN = os.path.dirname(sys.executable) +if os.path.exists(os.path.join(PYTHON_BIN, 'activate_this.py')): + # Assume that the presence of 'activate_this.py' in the python bin/ + # directory means that we're running in a virtual environment. Set the + # variable root to $VIRTUALENV/var. + VAR_ROOT = os.path.join(os.path.dirname(PYTHON_BIN), 'var') + if not os.path.exists(VAR_ROOT): + os.mkdir(VAR_ROOT) +else: + # Set the variable root to the local configuration location (which is + # ignored by the repository). + VAR_ROOT = os.path.join(PROJECT_DIR, PROJECT_MODULE_NAME, 'conf', 'local') + +#============================================================================== +# Static files +#============================================================================== + +STATIC_ROOT = os.path.join(VAR_ROOT, 'static') + +#============================================================================== +# Project URLS and media settings +#============================================================================== + +MEDIA_URL = '/uploads/' +STATIC_URL = '/static/' +ADMIN_MEDIA_PREFIX = '/static/admin/' + +MEDIA_ROOT = os.path.join(VAR_ROOT, 'uploads') + +ROOT_URLCONF = 'pastebin.conf.urls' + +LOGIN_URL = '/accounts/login/' +LOGOUT_URL = '/accounts/logout/' +LOGIN_REDIRECT_URL = '/' + +#============================================================================== +# Templates +#============================================================================== + +TEMPLATE_DIRS = ( + os.path.join(PROJECT_DIR, PROJECT_MODULE_NAME, 'templates'), +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.admin', + 'django.contrib.staticfiles', + 'mptt', + 'piston', + 'pastebin', + 'pastebin.apps.dpaste', +) + +#============================================================================== +# App specific settings +#============================================================================== + +# How many recent snippets to save for every user? IDs of this snippets are +# stored in the user session. +MAX_SNIPPETS_PER_USER = 25 diff --git a/pastebin/conf/test/__init__.py b/pastebin/conf/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/conf/test/settings.py b/pastebin/conf/test/settings.py new file mode 100644 index 0000000..5a706bc --- /dev/null +++ b/pastebin/conf/test/settings.py @@ -0,0 +1,16 @@ +from pastebin.conf.settings import * + +DEBUG = False +TEMPLATE_DEBUG = DEBUG + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': ':memory:', + } +} +ROOT_URLCONF = 'pastebin.conf.test.urls' + +INSTALLED_APPS += ('django_nose',) + +TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' diff --git a/pastebin/conf/test/urls.py b/pastebin/conf/test/urls.py new file mode 100644 index 0000000..a44386d --- /dev/null +++ b/pastebin/conf/test/urls.py @@ -0,0 +1,9 @@ +from django.conf.urls.defaults import * +from django.conf import settings + +CONF_MODULE = '%s.conf' % settings.PROJECT_MODULE_NAME + +urlpatterns = patterns('', + (r'', include('%s.urls' % CONF_MODULE)), + (r'', include('%s.common.urls.admin' % CONF_MODULE)), +) diff --git a/pastebin/conf/urls.py b/pastebin/conf/urls.py new file mode 100644 index 0000000..27f6c0f --- /dev/null +++ b/pastebin/conf/urls.py @@ -0,0 +1,26 @@ +from django.conf.urls.defaults import * +from django.conf import settings +from django.contrib import admin +from django.contrib.staticfiles.urls import staticfiles_urlpatterns +from piston.resource import Resource +from pastebin.apps.api.handlers import SnippetHandler + +admin.autodiscover() +snippet_resource = Resource(handler=SnippetHandler) + +urlpatterns = patterns('', + (r'^', include('pastebin.apps.dpaste.urls')), + + # Static + url(r'^about/$', 'django.views.generic.simple.direct_to_template', {'template': 'about.html'}, name='about'), + + # Bla + (r'^i18n/', include('django.conf.urls.i18n')), + (r'^admin/(.*)', include(admin.site.urls)), + + # API + url(r'^api/(?P[^/]+)/$', snippet_resource), + url(r'^api/$', snippet_resource), +) + +urlpatterns += staticfiles_urlpatterns() \ No newline at end of file diff --git a/pastebin/locale/de/LC_MESSAGES/django.mo b/pastebin/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a70e205a206ec1b4352b3eba24ba61d53727b34c GIT binary patch literal 3405 zcmbuAO^hQ)6~~KwkTAf81QNbOWs_yb?Dni@Ltydl?8f+G#@d;&<@W5dD}hzEU)#mB ztF7wl@pvx?2@ne60^)!KN~FLs0`V~ih?IjbQMi#qgh08#fkO@`he&V<|JQDNX2^z1 zN?rY{k5~0xy?Xun^@r~Hi9pGteg^et?-QcL?Yr?pS-D4uXTTh|4*m{&KlmniFZgfp zKJe{~_hFFtc>w%0cn*9R+yq(f8{mh)0DKUPv+?hOA4LC$;0M5;X8q^EkD~u8kk?PM z@jrpQ&udx#A0Qs_udM%8#=BtbIgFnI9|13cyiXJ4eQ$yHg9c>1W039sHuwPebCC7C z0Dc(!1IThOgS_s~An*5AumJuYWcf!i$o8BCKMSsbyuJ?dy02#pK-Lq1XTWcPEcZ+B zH@J)6flFA(#=n4kPyYn*i2vZl_TCGnEcbB6CqUN!B#1{8@Zxh+L5`ai_$ly5 z+4u|K$I<^I$acL7^1goq9|PaW`lnzl>wOet`CQg7g1rA02p5T4;L~6S#3P=^i~aO# za2Y%VS^jm9&-(_*dfx&$F5U)N?hy#_xvqfhKQ3QDWg9q-*|!q)bEsT6R=DI)dA*0q zdiZ-{d%19&ad~`()K4pDpGLh4mHmt3F3Lk_eSXoy+0kYjS5euAT=)!pKK9vJRQ~4J z51&B2Q^`K(bc)Z7LABw%@8ZE9G`=r(JB9 z>h){2N_(@m(-P%I(Qlz$->x)@82CEI#ivIRz-c}bYx=DP_ZMaq&c?#Y)m`RNIId82hres%l#uCFUue?T|UFAXz3wrie#t*LdS(9cKu4T-Dp;-e%mizN0|7# zrBcQBtGioUH^pv@O&1ni*EqXXV{s$0y|Gmzal>kMiop}Z!{R0`ONPo(?Bto1xjWlK zb&!jX&fS?{Ql)X5gJW&%8r_uY2BClYZ>AqJms% z)LUN3lHx;oWoRqN3;DG*FaMNx;VW|O%Y`pqL_42{px2~*&3pcj+>?2k&ljHh(%JkP zXX+ZHH5)*N2%@FcID_) zYpeOCEXuvsWCXJv9k}!OdbGL3k!o@O>$|P0ckxJ$tqRC`71ND+h>e20*wJpO5hhlJ zUNy4AxFF3a?Z)dDF3DMQeZ|Pf*5z7m>1$piqMml%+~k7XAUjm%Xr>e;#@PubD$VWU z&dsA49~auC(#*7iOk4oljwR3AV;y$~?T&vJ{3~UK&APP6AVY1;Y88{5FLcUA<|Z~2mQz~qjZsVtN5cz;XC{ml z2H_%LwIfcDY#Y8@2j?#OL%AIp<&LIrL^x!&v$#b_gJv*2#Lx~Qf5^;h;#PLYvZpD= z(b*50J&~lI*kfIC`W~ZxCe4HeaWN|Um!yrHk4f&k-@xYvgnR2Y{9#6<{dYH!KRs0>?ZLFOu7uD&D zR%+OVf7Ef^a(;L0*a2~tMCLsqBIe#;ty1kdy|2kSsS;>}W3mL?&z3Krysu?hO$^qY zOv3wV5~dLUQ+DAAeRJ=gh^rG4q8SbF^BCer7x@?hB#Q=rHJAn`SkfIt%WQxAk>CyU P&cwX%4}V0*GV^}{1l?qX literal 0 HcmV?d00001 diff --git a/pastebin/locale/de/LC_MESSAGES/django.po b/pastebin/locale/de/LC_MESSAGES/django.po new file mode 100644 index 0000000..9a29711 --- /dev/null +++ b/pastebin/locale/de/LC_MESSAGES/django.po @@ -0,0 +1,253 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: dpaste\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-05-29 17:48-0500\n" +"PO-Revision-Date: 2011-05-30 00:56+0100\n" +"Last-Translator: Martin Mahner \n" +"Language-Team: de \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"X-Poedit-Language: German\n" +"X-Poedit-Country: GERMANY\n" +"X-Poedit-SourceCharset: utf-8\n" + +#: apps/dpaste/forms.py:13 +msgid "In one hour" +msgstr "In einer Stunde" + +#: apps/dpaste/forms.py:14 +msgid "In one week" +msgstr "In einer Woche" + +#: apps/dpaste/forms.py:15 +msgid "In one month" +msgstr "In einem Monat" + +#: apps/dpaste/forms.py:16 +msgid "Save forever" +msgstr "Für immer" + +#: apps/dpaste/forms.py:26 +#: apps/dpaste/models.py:20 +msgid "Lexer" +msgstr "Syntax" + +#: apps/dpaste/forms.py:32 +#: apps/dpaste/models.py:22 +msgid "Expires" +msgstr "Verfällt" + +#: apps/dpaste/forms.py:87 +#: apps/dpaste/forms.py:96 +msgid "Default" +msgstr "Standard" + +#: apps/dpaste/forms.py:100 +msgid "Default Name" +msgstr "Standardname" + +#: apps/dpaste/forms.py:102 +msgid "Display all lexer" +msgstr "Alle Syntax anzeigen" + +#: apps/dpaste/forms.py:105 +msgid "This also enables the super secret 'guess lexer' function." +msgstr "Dies aktiviert auch die super geheime 'Syntax erraten' Funktion." + +#: apps/dpaste/forms.py:107 +msgid "Font Family" +msgstr "Schriftart" + +#: apps/dpaste/forms.py:108 +msgid "Font Size" +msgstr "Schriftgröße" + +#: apps/dpaste/forms.py:109 +msgid "Line Height" +msgstr "Zeilenhöhe" + +#: apps/dpaste/models.py:15 +msgid "Secret ID" +msgstr "Geheime ID" + +#: apps/dpaste/models.py:16 +msgid "Title" +msgstr "Titel" + +#: apps/dpaste/models.py:17 +msgid "Author" +msgstr "Autor" + +#: apps/dpaste/models.py:18 +msgid "Content" +msgstr "Inhalt" + +#: apps/dpaste/models.py:19 +msgid "Highlighted Content" +msgstr "Gefärbter Inhalt" + +#: apps/dpaste/models.py:21 +msgid "Published" +msgstr "Veröffentlicht" + +#: apps/dpaste/views.py:148 +msgid "No changes were made between this two files." +msgstr "Zwischen diesen Dateien wurden keine Änderungen vorgenommen." + +#: apps/dpaste/templates/dpaste/snippet_details.html:18 +#: apps/dpaste/templates/dpaste/snippet_details.html:21 +#: apps/dpaste/templates/dpaste/snippet_details.html:44 +#: apps/dpaste/templates/dpaste/snippet_details.html:82 +#: apps/dpaste/templates/dpaste/snippet_details.html:84 +#: apps/dpaste/templates/dpaste/snippet_list.html:4 +#: apps/dpaste/templates/dpaste/snippet_list.html:13 +msgid "Snippet" +msgstr "Snippet" + +#: apps/dpaste/templates/dpaste/snippet_details.html:23 +#, python-format +msgid "(Copy of snippet #%(parent_id)s)" +msgstr "(Kopie von Snippet #%(parent_id)s)" + +#: apps/dpaste/templates/dpaste/snippet_details.html:25 +#: apps/dpaste/templates/dpaste/snippet_list.html:14 +msgid "DATETIME_FORMAT" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:25 +msgid "UTC" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:35 +msgid "Time to life" +msgstr "Time to live" + +#: apps/dpaste/templates/dpaste/snippet_details.html:38 +msgid "Really delete this snippet?" +msgstr "Dieses Snippet wirklich löschen?" + +#: apps/dpaste/templates/dpaste/snippet_details.html:41 +msgid "Wordwrap" +msgstr "Wordwrap" + +#: apps/dpaste/templates/dpaste/snippet_details.html:45 +#, python-format +msgid "by %(author)s" +msgstr "von %(author)s" + +#: apps/dpaste/templates/dpaste/snippet_details.html:59 +msgid "Write an answer" +msgstr "Eine Antwort schreiben" + +#: apps/dpaste/templates/dpaste/snippet_details.html:69 +msgid "History" +msgstr "Geschichte" + +#: apps/dpaste/templates/dpaste/snippet_details.html:90 +msgid "Compare" +msgstr "Vergleichen" + +#: apps/dpaste/templates/dpaste/snippet_details.html:95 +msgid "Options" +msgstr "Einstellungen" + +#: apps/dpaste/templates/dpaste/snippet_details.html:96 +msgid "View raw" +msgstr "Rohformat" + +#: apps/dpaste/templates/dpaste/snippet_diff.html:4 +msgid "Close" +msgstr "Schließen" + +#: apps/dpaste/templates/dpaste/snippet_diff.html:5 +#, python-format +msgid "" +"\n" +" Diff between\n" +" Snippet #%(filea_id)s\n" +" and\n" +" Snippet #%(fileb_id)s\n" +" " +msgstr "" +"\n" +" Diff zwischen\n" +" Snippet #%(filea_id)s\n" +" und\n" +" Snippet #%(fileb_id)s\n" +" " + +#: apps/dpaste/templates/dpaste/snippet_form.html:12 +msgid "Guess lexer" +msgstr "Syntax erraten" + +#: apps/dpaste/templates/dpaste/snippet_form.html:17 +msgid "Paste it" +msgstr "Paste it" + +#: apps/dpaste/templates/dpaste/snippet_list.html:6 +#, python-format +msgid "Your latest %(snippets_max)s snippets" +msgstr "Deine letzten %(snippets_max)s Snippets" + +#: apps/dpaste/templates/dpaste/snippet_list.html:19 +msgid "No snippets available." +msgstr "Keine Snippets verfügbar." + +#: apps/dpaste/templates/dpaste/snippet_list.html:24 +#: apps/dpaste/templates/dpaste/userprefs.html:26 +msgid "DATA_STORED_IN_A_COOKIE_HINT" +msgstr "Deine Daten werden in einem Cookie gespeichert." + +#: apps/dpaste/templates/dpaste/snippet_new.html:4 +#: apps/dpaste/templates/dpaste/snippet_new.html:8 +#: templates/base.html:9 +#: templates/base.html.py:16 +msgid "New snippet" +msgstr "Neues Snippet" + +#: apps/dpaste/templates/dpaste/snippet_new.html:5 +msgid "Paste a new snippet" +msgstr "Paste ein neues Snippet" + +#: apps/dpaste/templates/dpaste/snippet_new.html:14 +msgid "DPASTE_HOMEPAGE_TITLE" +msgstr " " + +#: apps/dpaste/templates/dpaste/snippet_new.html:15 +msgid "DPASTE_HOMEPAGE_DESCRIPTION" +msgstr " " + +#: apps/dpaste/templates/dpaste/userprefs.html:5 +#: apps/dpaste/templates/dpaste/userprefs.html:15 +msgid "User Settings" +msgstr "Einstellungen" + +#: apps/dpaste/templates/dpaste/userprefs.html:11 +msgid "USER_PREFS_SAVED_SUCCESSFULLY" +msgstr "Deine Einstellungen wurden gespeichert." + +#: apps/dpaste/templates/dpaste/userprefs.html:21 +msgid "Save settings" +msgstr "Einstellungen speichern" + +#: templates/base.html:38 +msgid "Recent snippets" +msgstr "Letzte Snippets" + +#: templates/base.html:39 +msgid "Settings" +msgstr "Einstellungen" + +#: templates/base.html:40 +#, fuzzy +msgid "About" +msgstr "Über" + diff --git a/pastebin/locale/en/LC_MESSAGES/django.mo b/pastebin/locale/en/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..42acc1b7e17379b8b07546ad5689adc591365402 GIT binary patch literal 698 zcmZvZ!H&}~5QYsb2YN)}fCSQTTZ9~v0-|KMh>)gBMAJq|x}p+NWSZG*ptXbTEbL2g zgEI%7fJfj#cowFuP$k4jpJvAM+a8a9-#qxr$PS1*#4&N5cuQ=oB{u6HiCe@M;x6%n z_<4n~U*v)4t}=Fm{5SHq$$uwLWp<6&oK5M@MnMsjc`?hPQ5jFmpbTfT*Kt(7il+q| zr9oa$JWHZ9IEl(4E+!G1=TTOsSv1beJUFF&`8*7xJRi>|lLbq)dXG!XynUX zc+qUm{73i51=sUk?}6))ZbG;5LJMhD!Yb`UBD8HJxpRpcj@R4t#d@1MO4rY6i>y0Q zBQH>_eL(qNRT3xB{#Bmi_Ch5sO1kZ`rM4}8wh!BtXyg$r&xJN7z#wB2>)Q1Kgw);P) V!kv_!MdPdud_s+2#06Fk`vdgN#ti@f literal 0 HcmV?d00001 diff --git a/pastebin/locale/en/LC_MESSAGES/django.po b/pastebin/locale/en/LC_MESSAGES/django.po new file mode 100644 index 0000000..fdfe8c1 --- /dev/null +++ b/pastebin/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,246 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: dpaste\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-05-29 17:48-0500\n" +"PO-Revision-Date: 2011-05-30 01:01+0100\n" +"Last-Translator: Martin Mahner \n" +"Language-Team: en \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"X-Poedit-Language: German\n" +"X-Poedit-Country: GERMANY\n" +"X-Poedit-SourceCharset: utf-8\n" + +#: apps/dpaste/forms.py:13 +msgid "In one hour" +msgstr "" + +#: apps/dpaste/forms.py:14 +msgid "In one week" +msgstr "" + +#: apps/dpaste/forms.py:15 +msgid "In one month" +msgstr "" + +#: apps/dpaste/forms.py:16 +msgid "Save forever" +msgstr "" + +#: apps/dpaste/forms.py:26 +#: apps/dpaste/models.py:20 +msgid "Lexer" +msgstr "" + +#: apps/dpaste/forms.py:32 +#: apps/dpaste/models.py:22 +msgid "Expires" +msgstr "" + +#: apps/dpaste/forms.py:87 +#: apps/dpaste/forms.py:96 +msgid "Default" +msgstr "" + +#: apps/dpaste/forms.py:100 +msgid "Default Name" +msgstr "" + +#: apps/dpaste/forms.py:102 +msgid "Display all lexer" +msgstr "" + +#: apps/dpaste/forms.py:105 +msgid "This also enables the super secret 'guess lexer' function." +msgstr "" + +#: apps/dpaste/forms.py:107 +msgid "Font Family" +msgstr "" + +#: apps/dpaste/forms.py:108 +msgid "Font Size" +msgstr "" + +#: apps/dpaste/forms.py:109 +msgid "Line Height" +msgstr "" + +#: apps/dpaste/models.py:15 +msgid "Secret ID" +msgstr "" + +#: apps/dpaste/models.py:16 +msgid "Title" +msgstr "" + +#: apps/dpaste/models.py:17 +msgid "Author" +msgstr "" + +#: apps/dpaste/models.py:18 +msgid "Content" +msgstr "" + +#: apps/dpaste/models.py:19 +msgid "Highlighted Content" +msgstr "" + +#: apps/dpaste/models.py:21 +msgid "Published" +msgstr "" + +#: apps/dpaste/views.py:148 +msgid "No changes were made between this two files." +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:18 +#: apps/dpaste/templates/dpaste/snippet_details.html:21 +#: apps/dpaste/templates/dpaste/snippet_details.html:44 +#: apps/dpaste/templates/dpaste/snippet_details.html:82 +#: apps/dpaste/templates/dpaste/snippet_details.html:84 +#: apps/dpaste/templates/dpaste/snippet_list.html:4 +#: apps/dpaste/templates/dpaste/snippet_list.html:13 +msgid "Snippet" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:23 +#, python-format +msgid "(Copy of snippet #%(parent_id)s)" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:25 +#: apps/dpaste/templates/dpaste/snippet_list.html:14 +msgid "DATETIME_FORMAT" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:25 +msgid "UTC" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:35 +msgid "Time to life" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:38 +msgid "Really delete this snippet?" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:41 +msgid "Wordwrap" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:45 +#, python-format +msgid "by %(author)s" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:59 +msgid "Write an answer" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:69 +msgid "History" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:90 +msgid "Compare" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:95 +msgid "Options" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_details.html:96 +msgid "View raw" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_diff.html:4 +msgid "Close" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_diff.html:5 +#, python-format +msgid "" +"\n" +" Diff between\n" +" Snippet #%(filea_id)s\n" +" and\n" +" Snippet #%(fileb_id)s\n" +" " +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_form.html:12 +msgid "Guess lexer" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_form.html:17 +msgid "Paste it" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_list.html:6 +#, python-format +msgid "Your latest %(snippets_max)s snippets" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_list.html:19 +msgid "No snippets available." +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_list.html:24 +#: apps/dpaste/templates/dpaste/userprefs.html:26 +msgid "DATA_STORED_IN_A_COOKIE_HINT" +msgstr "Your data is stored in a cookie." + +#: apps/dpaste/templates/dpaste/snippet_new.html:4 +#: apps/dpaste/templates/dpaste/snippet_new.html:8 +#: templates/base.html:9 +#: templates/base.html.py:16 +msgid "New snippet" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_new.html:5 +msgid "Paste a new snippet" +msgstr "" + +#: apps/dpaste/templates/dpaste/snippet_new.html:14 +msgid "DPASTE_HOMEPAGE_TITLE" +msgstr "dpaste.de" + +#: apps/dpaste/templates/dpaste/snippet_new.html:15 +msgid "DPASTE_HOMEPAGE_DESCRIPTION" +msgstr "" + +#: apps/dpaste/templates/dpaste/userprefs.html:5 +#: apps/dpaste/templates/dpaste/userprefs.html:15 +msgid "User Settings" +msgstr "" + +#: apps/dpaste/templates/dpaste/userprefs.html:11 +msgid "USER_PREFS_SAVED_SUCCESSFULLY" +msgstr "Your settings were saved." + +#: apps/dpaste/templates/dpaste/userprefs.html:21 +msgid "Save settings" +msgstr "" + +#: templates/base.html:38 +msgid "Recent snippets" +msgstr "" + +#: templates/base.html:39 +msgid "Settings" +msgstr "" + +#: templates/base.html:40 +msgid "About" +msgstr "" + diff --git a/pastebin/static/.gitignore b/pastebin/static/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/pastebin/static/theme.css b/pastebin/static/theme.css new file mode 100644 index 0000000..2d08663 --- /dev/null +++ b/pastebin/static/theme.css @@ -0,0 +1,384 @@ +body{ + margin: 0; + padding: 0; + font-family: Helvetica, Arial, sans-serif; + font-size: 13px; +} + +a:link, +a:visited{ + color: #3D813A; + text-decoration: none; +} + +a:hover{ + color: #52AA4D; + text-decoration: underline; +} + +hr.clear{ + clear: both; + border: none; + margin: 0; + padding: 0; + height: 0; + overflow: hidden; + font-size: 0; + line-height: 0; + visibility: hidden; +} + +div.success{ + background-color: green; + color: White; + margin: 10px 0; + padding: 10px 20px; +} + +div.success a{ + color: White; + text-decoration: underline; +} + +div.hint{ + padding: 5px 20px; + background-color: #F7F1C9; + margin: 20px 0; +} + + +/* ******************************************* + * Header + ******************************************* */ + +#header{ + background-color: #D6F1B7; + border-bottom: 1px solid #C6EB9A; + padding: 10px 20px; + font-size: 14px; +} + +#header span.new_snippet{ + float: right; +} + +#header h1{ + margin: 0; + color: #555555; + font-size: 14px; +} + +#header h1 span.date{ + color: gray; + color: #666; + padding-left: 15px; +} + +#header a:link, +#header a:visited{ + text-decoration: none; + color: #333; + font-weight: Bold; +} + +#header a:hover{ + text-decoration: underline; +} + +/* ******************************************* + * Content + ******************************************* */ + +#content{ + padding: 0 20px; + margin: 0; + width: 70%; + float: left; +} + + +#content h2{ + font-size: 1.3em; + line-height: 1.6em; +} + +#content h2 span{ + font-weight: normal; +} + +div.accordion h2{ + cursor: pointer; + color: #3D813A; +} + +div.accordion h2:hover{ + text-decoration: underline; +} + +/* ******************************************* + * Snippet table + ******************************************* */ +div.snippet{ + overflow: auto; +} + +div.snippet-options{ + float: right; + font-size: 0.9em; + margin-top: 5px; +} + +div.snippet table{ + margin: 0; + padding: 0; + border-collapse: collapse; +} + +div.snippet table td{ + margin: 0; + padding: 0 4px; + vertical-align: top; +} + +div.snippet table th{ + border-right: 1px solid #ccc; + vertical-align: top; +} + +div.snippet table th a{ + display: block; + text-decoration: none; + color: #888; + text-align: right; + padding: 0 4px 0 18px; +} + +/* ******************************************* + * Form + ******************************************* */ +form.snippetform ol{ + margin: 0; + padding: 0; + list-style: none; +} + +form.snippetform ol li{ + margin: 0; + padding: 5px 10px; + border-bottom: 1px solid #EEE; + clear: left; +} + +form.snippetform label{ + width: 125px; + float: left; +} + +form.snippetform #id_content{ + width: 80%; + height: 290px; + font-family: monospace; + font-size: 0.9em; +} + +form.snippetform #id_author, +form.snippetform #id_title{ + width: 60%; + opacity: 0.7; +} + +form.snippetform li.submit input{ + margin-left: 125px; +} + +form.snippetform ul.errorlist, +form.snippetform ul.errorlist li{ + margin: 0; + padding: 0; + list-style: none; + color: #c00; + font-weight: bold; + border: none; +} + +form.snippetform ul.errorlist li{ + padding: 10px 0 5px 0; +} +/* ******************************************* + * History + Tree + ******************************************* */ + +#sidebar{ + padding: 0 20px 0 10px; + margin: 20px 0 0 0; + float: right; + width: 20%; + overflow: auto; + border-left: 1px solid #DDD; +} + +#sidebar h2{ + font-size: 1em; + border-bottom: 1px solid #DDD; + color: #888; + margin-top: 0; + text-transform: uppercase; + width: auto !important; +} + +div.tree{ + margin: 0 0 15px 0; + line-height: 1.8em; +} + +div.tree ul, +div.tree ul li{ + margin: 0; + padding: 0; + list-style: none; +} + +div.tree ul li{ + clear: both; +} + +div.tree ul li div{ + border-bottom: 1px solid #EEE; +} + +div.tree span.diff{ + float: right; +} + +div.tree strong{ + color: #111; + font-weight: normal; +} + +div.tree ul li li{ + padding-left: 0; + margin-left: 15px; + color: #ccc; + list-style: circle; +} + +div.tree div.submit{ + margin: 8px 0 0 0; + text-align: right; +} + +div.tree div.submit input{ + font-size: 0.8em; +} + +/* ******************************************* + * Footer + ******************************************* */ + +#footer{ + position: fixed; + right: 1em; + bottom: 1em; +} + +#footer form.setlang{ + display: inline; + padding-right: 15px; +} + +#footer form.setlang input, +#footer form.setlang select{ + font-size: 0.8em; +} + +#footer a:link, +#footer a:visited{ + background-color: #D6F1B7; + color: #555; + text-decoration: none; + padding: 3px 6px; +} + +#footer a:hover, +#footer a:active{ + background-color: #D6F1B7; + color: #000; + text-decoration: none; +} + +/* ******************************************* + * Pygments + ******************************************* */ + +pre.code { + font-family: "Bitstream Vera Sans Mono", Monaco, Consolas, monospace; + font-size: 12px; + line-height: 17px; + margin: 0; + padding: 0; +} + +pre.code div.line:hover{ + background-color: #FFFFE6; +} + +pre.code div.line.marked, +pre.code div.line.marked *{ + background-color: #BAE688 !important; +} + +.code .c { color: #999988; font-style: italic } /* Comment */ +/* .code .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.code .k { font-weight: bold } /* Keyword */ +.code .o { font-weight: bold } /* Operator */ +.code .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.code .cp { color: #999999; font-weight: bold } /* Comment..codeproc */ +.code .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.code .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.code .ge { font-style: italic } /* Generic.Emph */ +.code .gr { color: #aa0000 } /* Generic.Error */ +.code .gh { color: #999999 } /* Generic.Heading */ +.code .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.code .go { color: #888888 } /* Generic.Output */ +.code .gp { color: #555555 } /* Generic.Prompt */ +.code .gs { font-weight: bold } /* Generic.Strong */ +.code .gu { color: #aaaaaa } /* Generic.Subheading */ +.code .gt { color: #aa0000 } /* Generic.Traceback */ +.code .kc { font-weight: bold } /* Keyword.Constant */ +.code .kd { font-weight: bold } /* Keyword.Declaration */ +.code .kp { font-weight: bold } /* Keyword.Pseudo */ +.code .kr { font-weight: bold } /* Keyword.Reserved */ +.code .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.code .m { color: #009999 } /* Literal.Number */ +.code .s { color: #bb8844 } /* Literal.String */ +.code .na { color: #008080 } /* Name.Attribute */ +.code .nb { color: #999999 } /* Name.Builtin */ +.code .nc { color: #445588; font-weight: bold } /* Name.Class */ +.code .no { color: #ff99ff } /* Name.Constant */ +.code .ni { color: #800080 } /* Name.Entity */ +.code .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.code .nf { color: #990000; font-weight: bold } /* Name.Function */ +.code .nn { color: #555555 } /* Name.Namespace */ +.code .nt { color: #000080 } /* Name.Tag */ +.code .nv { color: purple } /* Name.Variable */ +.code .ow { font-weight: bold } /* Operator.Word */ +.code .mf { color: #009999 } /* Literal.Number.Float */ +.code .mh { color: #009999 } /* Literal.Number.Hex */ +.code .mi { color: #009999 } /* Literal.Number.Integer */ +.code .mo { color: #009999 } /* Literal.Number.Oct */ +.code .sb { color: #bb8844 } /* Literal.String.Backtick */ +.code .sc { color: #bb8844 } /* Literal.String.Char */ +.code .sd { color: #bb8844 } /* Literal.String.Doc */ +.code .s2 { color: #bb8844 } /* Literal.String.Double */ +.code .se { color: #bb8844 } /* Literal.String.Escape */ +.code .sh { color: #bb8844 } /* Literal.String.Heredoc */ +.code .si { color: #bb8844 } /* Literal.String.Interpol */ +.code .sx { color: #bb8844 } /* Literal.String.Other */ +.code .sr { color: #808000 } /* Literal.String.Regex */ +.code .s1 { color: #bb8844 } /* Literal.String.Single */ +.code .ss { color: #bb8844 } /* Literal.String.Symbol */ +.code .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.code .vc { color: #ff99ff } /* Name.Variable.Class */ +.code .vg { color: #ff99ff } /* Name.Variable.Global */ +.code .vi { color: #ff99ff } /* Name.Variable.Instance */ +.code .il { color: #009999 } /* Literal.Number.Integer.Long */ diff --git a/pastebin/templates/404.html b/pastebin/templates/404.html new file mode 100644 index 0000000..3f7d387 --- /dev/null +++ b/pastebin/templates/404.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} + +{% block headline %} +

404 Not found

+{% endblock %} + +{% block content %} +

Snippet you have searched is not available (anymore).

+{% endblock %} diff --git a/pastebin/templates/500.html b/pastebin/templates/500.html new file mode 100644 index 0000000..1e9d6c8 --- /dev/null +++ b/pastebin/templates/500.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} + +{% block headline %} +

500 Internal Server Error

+{% endblock %} + +{% block content %} +

Sorry, there was an error with your request. My fault!

+{% endblock %} diff --git a/pastebin/templates/about.html b/pastebin/templates/about.html new file mode 100644 index 0000000..fe21714 --- /dev/null +++ b/pastebin/templates/about.html @@ -0,0 +1,64 @@ +{% extends "base.html" %} + +{% block headline %} +

About dpaste.de

+{% endblock %} + +{% block content %} +

Description follows...

+ + +

API

+ +
#!/usr/bin/env python
+ 
+import urllib
+import urllib2
+import sys
+ 
+def paste_code():
+    request = urllib2.Request(
+        'http://dpaste.de/api/',
+        urllib.urlencode([('content', ''.join(sys.stdin.readlines()))]),
+    )
+    response = urllib2.urlopen(request)
+    print response.read()[1:-1]
+ 
+if __name__ == '__main__':
+    paste_code()
+ +

Save this script in /usr/local/bin/dpaste and chmod +x ..filepath.

+

Usage: cat foo.txt | dpaste

+{% endblock %} + + +{% block sidebar %} +

Imprint

+ +

+ Address +

+

+ Martin Mahner
+ Lauterbacher Str. 4
+ DE-18581 Putbus
+ Germany +

+ +

+ Jabber/E-Mail: +

+ +

+ martin@mahner.org +

+ +

+ Phone: +

+ +

+ +49 38301 890(770+8)1

+ 1 Yes, that's math! +

+{% endblock %} diff --git a/pastebin/templates/base.html b/pastebin/templates/base.html new file mode 100644 index 0000000..40cc323 --- /dev/null +++ b/pastebin/templates/base.html @@ -0,0 +1,62 @@ +{% load i18n %} + + + + + + + dpaste.de: {% block title %}{% trans "New snippet" %}{% endblock %} + + {% block extrahead %}{% endblock %} + + + + + + + + +
+ {% block content %}{% endblock %} +
+ + +{% block script_footer %}{% endblock %} + + + + + + diff --git a/requirements.pip b/requirements.pip new file mode 100644 index 0000000..fb73646 --- /dev/null +++ b/requirements.pip @@ -0,0 +1,4 @@ +django==1.3 +mptt==0.4.2 +piston==0.2.2 +pygments==1.4 \ No newline at end of file diff --git a/server_configs/dev/apache.conf b/server_configs/dev/apache.conf new file mode 100644 index 0000000..7fbd969 --- /dev/null +++ b/server_configs/dev/apache.conf @@ -0,0 +1,16 @@ + + ServerName pastebin.dev.lincolnloop.com + ServerAdmin webmaster@dev.lincolnloop.com + + ErrorLog /var/log/apache2/pastebin.dev.lincolnloop.com.log + + WSGIDaemonProcess pastebin user=www-data inactivity-timeout=600 + WSGIProcessGroup pastebin + WSGIScriptAlias / /opt/webapps/pastebin.dev.lincolnloop.com/etc/apache/django.wsgi + + + Order deny,allow + Allow from all + + + diff --git a/server_configs/dev/django.wsgi b/server_configs/dev/django.wsgi new file mode 100644 index 0000000..d4a1766 --- /dev/null +++ b/server_configs/dev/django.wsgi @@ -0,0 +1,13 @@ +import os, sys +import site + +site.addsitedir('/opt/webapps/pastebin/lib/python2.5/site-packages') + + +sys.stdout = sys.stderr + +os.environ['DJANGO_SETTINGS_MODULE'] = 'pastebin.conf.local.settings' + +import django.core.handlers.wsgi + +application = django.core.handlers.wsgi.WSGIHandler() diff --git a/server_configs/dev/nginx.conf b/server_configs/dev/nginx.conf new file mode 100644 index 0000000..384496c --- /dev/null +++ b/server_configs/dev/nginx.conf @@ -0,0 +1,31 @@ +upstream pastebin { + server pastebin.dev.lincolnloop.com:9000; +} + +server { + listen 80; + server_name www.pastebin.dev.lincolnloop.com; + rewrite ^/(.*) http://pastebin.dev.lincolnloop.com/$1 permanent; +} + +server { + listen 80; + server_name pastebin.dev.lincolnloop.com; + root /var/www/pastebin.dev.lincolnloop.com/; + access_log /var/log/nginx/pastebin.dev.lincolnloop.com.access.log; + + location / { + if (-f $request_filename/index.html) { + rewrite (.*) $1/index.html break; + } + if (!-f $request_filename) { + proxy_pass http://pastebin; + } + include /etc/nginx/proxy-setup.inc.conf; + } + + # Serve up apache log on dev host. Useful for debugging. + location /apache.log { + alias /var/log/apache2/pastebin.dev.lincolnloop.com.log; + } +} diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..8825d0a --- /dev/null +++ b/setup.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +from setuptools import setup, find_packages + +setup(name='pastebin', + version='0.1', + packages=find_packages(), + package_data={'pastebin': ['bin/*.*', 'static/*.*', 'templates/*.*']}, + exclude_package_data={'pastebin': ['bin/*.pyc']}, + scripts=['pastebin/bin/manage.py'])