~mediagoblin/mediagoblin

3aee3f810ddfe5127de61f743a24b6e6e7482584 — Ben Sturmfels 5 months ago 1c94b1b + c1b080d stable
Merge branch '0.12.1' into stable
57 files changed, 388 insertions(+), 893 deletions(-)

M .builds/debian-11-sqlite.yml
R .builds/{fedora-33-sqlite.yml => ubuntu-20.04.yml}
M .gitignore
M AUTHORS
M Dockerfile-debian-11-sqlite
M Dockerfile-fedora-33-sqlite
M MANIFEST.in
D README
A README.md
M configure.ac
A docs/source/devel/contributing.rst
M docs/source/devel/release.rst
M docs/source/index.rst
M docs/source/siteadmin/deploying.rst
M docs/source/siteadmin/media-types.rst
M docs/source/siteadmin/plugins.rst
M docs/source/siteadmin/relnotes.rst
A docs/source/siteadmin/troubleshooting.rst
M docs/source/siteadmin/upgrading.rst
M extlib/README
M guix-env.scm
D m4/python.m4
M mediagoblin.example.ini
M mediagoblin/_version.py
M mediagoblin/api/views.py
M mediagoblin/app.py
M mediagoblin/db/migration_tools.py
M mediagoblin/db/migrations.py
M mediagoblin/db/migrations/env.py
M mediagoblin/db/models.py
M mediagoblin/decorators.py
M mediagoblin/edit/views.py
M mediagoblin/gmg_commands/addmedia.py
M mediagoblin/gmg_commands/assetlink.py
M mediagoblin/gmg_commands/batchaddmedia.py
M mediagoblin/gmg_commands/dbupdate.py
M mediagoblin/gmg_commands/reprocess.py
M mediagoblin/media_types/blog/views.py
M mediagoblin/media_types/video/transcoders.py
M mediagoblin/moderation/views.py
M mediagoblin/plugins/api/tools.py
M mediagoblin/plugins/api/views.py
M mediagoblin/plugins/archivalook/tools.py
M mediagoblin/plugins/archivalook/views.py
M mediagoblin/plugins/basic_auth/tools.py
M mediagoblin/plugins/ldap/views.py
M mediagoblin/plugins/openid/__init__.py
M mediagoblin/plugins/piwigo/views.py
M mediagoblin/plugins/subtitles/models.py
M mediagoblin/plugins/subtitles/views.py
M mediagoblin/submit/views.py
M mediagoblin/tests/test_processing.py
M mediagoblin/tools/pluginapi.py
M mediagoblin/user_pages/views.py
M runtests.sh
M setup.cfg
M tox.ini
M .builds/debian-11-sqlite.yml => .builds/debian-11-sqlite.yml +3 -3
@@ 54,20 54,20 @@ tasks:
      cd mediagoblin
      git show --oneline --no-patch
      ./bootstrap.sh
      VIRTUALENV_FLAGS='--system-site-packages' ./configure
      ./configure
      make

      # Install additional Sphinx dependencies not in Debian.
      ./bin/pip install sphinxcontrib-applehelp sphinxcontrib-htmlhelp sphinxcontrib-jsmath

      # Install raw image library from PyPI as not available in Debian 10.
      # Install raw image library from PyPI as not available in Debian 11.
      ./bin/pip install py3exiv2

      # Confirm our packages version for later troubleshooting.
      ./bin/python -m pip freeze

      # Run the tests, explicitly listing out skipped tests.
      ./bin/python -m pytest -rs ./mediagoblin/tests --boxed
      ./bin/python -m pytest -rs ./mediagoblin/tests --forked

      # Build the documentation.
      cd docs && make html

R .builds/fedora-33-sqlite.yml => .builds/ubuntu-20.04.yml +30 -27
@@ 1,69 1,72 @@
image: fedora/33
image: ubuntu/20.04
packages:
  # Install bootstrap and configure dependencies.
  - automake
  # - gcc
  # - make
  - nodejs
  - npm
  - python3-devel
  - python3-dev
  - virtualenv
  

  # Install make and runtime dependencies.
  # - findutils
  - python3-lxml
  - python3-pillow
  - libffi-devel
  # - which
  - python3-pil

  # Install test and docs dependencies.
  - python3-pytest
  - python3-pytest-xdist
  - python3-snowballstemmer
  - python3-sphinx
  - python3-sphinxcontrib.websupport
  - python3-webtest

  # Install audio dependencies.
  - gstreamer1-plugins-base
  - gstreamer1-plugins-bad-free
  - gstreamer1-plugins-good
  - gstreamer1-plugins-ugly-free
  - gstreamer1.0-libav
  - gstreamer1.0-plugins-bad
  - gstreamer1.0-plugins-base
  - gstreamer1.0-plugins-good
  - gstreamer1.0-plugins-ugly
  - python3-gst-1.0
  - python3-numpy

  # Install video dependencies.
  - python3-gobject
  - python3-gstreamer1
  -  gstreamer1-plugin-openh264
  
  # # Install raw image dependencies.
  # - libexiv2-dev
  # - libboost-python-dev
  - gir1.2-gst-plugins-base-1.0
  - gir1.2-gstreamer-1.0
  - gstreamer1.0-tools
  - python3-gi

  # Install raw image dependencies.
  - libexiv2-dev
  - libboost-python-dev

  # # Install document (PDF-only) dependencies.
  # - poppler-utils
  # Install document (PDF-only) dependencies.
  - poppler-utils

  # Install LDAP depedencies.
  - python3-ldap

  # Install OpenID dependencies.
  - python3-openid
  

tasks:
  - core: |
      cd mediagoblin
      git show --oneline --no-patch
      ./bootstrap.sh
      VIRTUALENV_FLAGS='--system-site-packages' ./configure
      ./configure
      make

      # # Install raw image library from PyPI as not available in Debian 10.
      # ./bin/pip install py3exiv2
      # Install additional Sphinx dependencies not in Debian.
      ./bin/pip install sphinxcontrib-applehelp sphinxcontrib-htmlhelp sphinxcontrib-jsmath

      # Install raw image library from PyPI as not available in Debian 11.
      ./bin/pip install py3exiv2

      # Confirm our packages version for later troubleshooting.
      ./bin/python -m pip freeze

      # Run the tests, explicitly listing out skipped tests.
      ./bin/python -m pytest -rs ./mediagoblin/tests --boxed
      ./bin/python -m pytest -rs ./mediagoblin/tests --forked

      # Build the documentation.
      cd docs && make html


M .gitignore => .gitignore +5 -1
@@ 41,6 41,10 @@
/configure
/aclocal.m4

# npm status
/package-lock.json
/package.json

# Tests
/mediagoblin/tests/.cache/
/mediagoblin/tests/user_dev/


@@ 51,12 55,12 @@
*~
*.sw?
*.mo
*.patch

# The legacy of buildout
.installed.cfg

# Virtualenv, tox
/pyvenv.cfg
venv*
.tox/


M AUTHORS => AUTHORS +4 -0
@@ 25,6 25,7 @@ Thank you!
* Bernhard Keller
* Berker Peksag
* Beuc
* Bill Auger
* Boris Bobrov
* Brandon Invergo
* Brett Smith


@@ 35,6 36,7 @@ Thank you!
* Christopher Allan Webber
* chrysn
* Dan Callahan
* Dan Helfman
* David Thompson
* Daniel Krol
* Daniel Neel


@@ 44,6 46,7 @@ Thank you!
* Derek Moore
* Duncan
* Duncan Paterson
* Elisei Roca
* Elrond of Samba TNG
* Emily O'Leary
* Fernando Gutierrez


@@ 98,6 101,7 @@ Thank you!
* Olivier Mehani
* Osama Khalid
* Pablo J. Urbano Santos
* Peter Horvath
* Praveen Kumar
* Rasmus Larsson
* Robert Smith

M Dockerfile-debian-11-sqlite => Dockerfile-debian-11-sqlite +2 -2
@@ 48,7 48,7 @@
#
# You can run the test suite with:
#
# docker run --tty mediagoblin-python3 bash -c "bin/python -m pytest ./mediagoblin/tests --boxed"
# docker run --tty mediagoblin-python3 bash -c "bin/python -m pytest ./mediagoblin/tests --forked"

ARG DEBIAN_FRONTEND=noninteractive



@@ 182,7 182,7 @@ RUN ./bin/pip install py3exiv2
RUN ./bin/python -m pip freeze

# Run the tests.
RUN ./bin/python -m pytest -rs ./mediagoblin/tests --boxed
RUN ./bin/python -m pytest -rs ./mediagoblin/tests --forked

# Build the documentation.
RUN cd docs && make html

M Dockerfile-fedora-33-sqlite => Dockerfile-fedora-33-sqlite +1 -1
@@ 83,7 83,7 @@ RUN make

RUN ./bin/python -m pip freeze

RUN ./bin/python -m pytest -rs ./mediagoblin/tests --boxed
RUN ./bin/python -m pytest -rs ./mediagoblin/tests --forked

RUN cd docs && make html


M MANIFEST.in => MANIFEST.in +1 -0
@@ 14,6 14,7 @@ recursive-include mediagoblin/media_types/video/migrations *.py
include mediagoblin.example.ini mediagoblin/config_spec.ini paste.ini
include mediagoblin/config_spec.ini
include mediagoblin/db/migrations/alembic.ini
include mediagoblin/db/migrations/env.py
graft extlib
graft licenses
graft devtools

D README => README +0 -41
@@ 1,41 0,0 @@
========
 README
========

What is GNU MediaGoblin?
========================

* A place to store all your different media (photos, videos, audios,
  and more!) that’s as awesome as, if not more awesome than, existing
  network services (Flickr, YouTube, etc)
* Customizable!
* A place for people to collaborate and show off original and derived
  creations.  Free, as in freedom.  We’re a GNU project after all.
* Extensible: Plugins allow you to add new media types (3d models?
  Presentations and documents?  Yes, and more!) or extend old ones.
* A real community, and we'd love to have you join us!


Is it ready for me to use?
==========================

Yes!


Can I help/hang out/participate/whisper sweet nothings in your ear?
===================================================================

Yes!  Please join us and hang out!  For more information on where we
hang out, see `our Join page <http://mediagoblin.org/join/>`_


Where is the documentation?
===========================

The beginnings of a site administration manual is located in the ``docs/``
directory in HTML, Texinfo, and source (Restructured Text) forms.  It's
also available online at http://docs.mediagoblin.org/ in HTML form.

Contributor/developer documentation as well as documentation on the
project processes and infrastructure is located on 
`the wiki <http://wiki.mediagoblin.org/>`_.

A README.md => README.md +27 -0
@@ 0,0 1,27 @@
# GNU MediaGoblin

<img src="https://mediagoblin.org/images/home_goblin.png" alt="">

MediaGoblin is a free software media publishing platform that anyone can run.
You can think of it as a decentralized alternative to Flickr, YouTube,
SoundCloud. It's also:

* The perfect tool to show and share your media!
* Building tools to empower the world through decentralization!
* Built for extensibility. Multiple media types, including video support!
* Part of the GNU project and devoted to user freedom.
* Powered by a community of people like you.

MediaGoblin is a self-hosted web application that you install on a server you or
your organisation controls. See our [Deploying
MediaGoblin](https://docs.mediagoblin.org/en/master/siteadmin/deploying.html)
for instructions.

Please see our [join us](https://mediagoblin.org/pages/join.html) page us and
get involved!

* [website](https://mediagoblin.org)
* [documentation](https://docs.mediagoblin.org)
* [bug tracker](https://todo.sr.ht/~mediagoblin/mediagoblin)
* [bug tracker (legacy)](https://issues.mediagoblin.org)
* [CI](https://builds.sr.ht/~mediagoblin/mediagoblin)

M configure.ac => configure.ac +13 -14
@@ 56,7 56,7 @@ dnl # * x.y.dev  - dev
dnl 
dnl # see http://www.python.org/dev/peps/pep-0386/

AC_INIT([mediagoblin], [0.12.0], [mediagoblin-devel@gnu.org])
AC_INIT([mediagoblin], [0.12.1], [mediagoblin-devel@gnu.org])


dnl----


@@ 80,9 80,7 @@ dnl In this section, we check for the presence of important commands
dnl and programs.

AC_CHECK_PROGS([PYTHON], [python3], [none])
AS_IF([test "x$PYTHON" = xnone],
	    [AC_MSG_FAILURE(
		[No acceptable python3 could be found])])
AS_IF([test "$PYTHON" = none], [AC_MSG_FAILURE([No acceptable python3 could be found])])

dnl----
dnl With the following set of macros, we implement an option 


@@ 96,16 94,17 @@ dnl
# Support doing development in a virtualenv via the --with-virtualenv 
# configure flag
AC_ARG_WITH([virtualenv],
	[AS_HELP_STRING([--without-virtualenv],
                        [don't install a Python virtualenv for the user])],
	[],
	[with_virtualenv=yes])
AS_IF([test "x$with_virtualenv" != xno],
	    AC_CHECK_PROGS([VIRTUALENV], [virtualenv virtualenv3 virtualenv2], [no])
	    AS_IF([test "x$VIRTUALENV" = xno],
	    [AC_MSG_FAILURE(
		[--with-virtualenv given but virtualenv could not be found])]),
	AC_SUBST([VIRTUALENV], [no]))
  [AS_HELP_STRING([--without-virtualenv], [do not install a Python virtualenv for the user])],
  [],
  [with_virtualenv=yes])

AC_CHECK_PROGS([VIRTUALENV], virtualenv, no)

AS_IF(
  [test "$with_virtualenv" = yes -a "$VIRTUALENV" = no], [AC_MSG_FAILURE([--with-virtualenv given but virtualenv could not be found])],
  [test "$with_virtualenv" = no], [AC_SUBST([VIRTUALENV], [no])]
)

AC_ARG_VAR([VIRTUALENV_FLAGS], [flags to pass to the virtualenv command])

dnl----

A docs/source/devel/contributing.rst => docs/source/devel/contributing.rst +31 -0
@@ 0,0 1,31 @@
.. MediaGoblin Documentation

   Written in 2011, 2012, 2013, 2020, 2021 by MediaGoblin contributors

   To the extent possible under law, the author(s) have dedicated all
   copyright and related and neighboring rights to this software to
   the public domain worldwide. This software is distributed without
   any warranty.

   You should have received a copy of the CC0 Public Domain
   Dedication along with this software. If not, see
   <http://creativecommons.org/publicdomain/zero/1.0/>.

.. _contributing-chapter:

============
Contributing
============

This page will describe how to get started contributing to MediaGoblin:

* How to set up a development environment
* How to run the test suite
* How to update and build the documentation
* How to submit code contributions

We eventually hope to migrate the information over from these wiki pages:

* https://wiki.mediagoblin.org/Main_Page#Technical_project_documentation
* https://wiki.mediagoblin.org/HackingHowto
* https://wiki.mediagoblin.org/Git_workflow

M docs/source/devel/release.rst => docs/source/devel/release.rst +9 -3
@@ 5,14 5,20 @@ Release Checklist
- update docs/sources/siteadmin/relnotes.txt
- update docs/sources/siteadmin/upgrading.txt
- write a blog post
- update mediagoblin/_version.py
- update configure.ac version
- test the upgrade process
- build the docs and check they look good
- git tag v0.11.0 --signed
- git tag --annotate v0.11.0 --signed --message
- push tags
- log in and rebuild master and new version docs on readthedocs.org
- merge into stable branch?
- post to mediagoblin-devel
- post to info-gnu@gnu.org
- post to mastodon and twitter
- update IRC topic
- email personal contacts

- update mediagoblin/_version.py
- update configure.ac version
- update mediagoblin/_version.py again to add ".dev" suffix
- update configure.ac version again to add ".dev" suffix


M docs/source/index.rst => docs/source/index.rst +2 -0
@@ 40,6 40,7 @@ MediaGoblin website.  It is written for site administrators.
   siteadmin/production-deployments
   siteadmin/configuration
   siteadmin/upgrading
   siteadmin/troubleshooting
   siteadmin/media-types
   siteadmin/help
   siteadmin/relnotes


@@ 92,6 93,7 @@ This chapter contains various information for developers.
.. toctree::
   :maxdepth: 1

   devel/contributing
   devel/codebase
   devel/storage
   devel/release

M docs/source/siteadmin/deploying.rst => docs/source/siteadmin/deploying.rst +22 -6
@@ 21,7 21,7 @@ This deployment guide will take you step-by-step through
setting up your own instance of MediaGoblin.

MediaGoblin most likely isn't yet available from your operating
system's package manage, however, a basic install isn't too complex in
system's package manager, however, a basic install isn't too complex in
and of itself. We recommend a setup that combines MediaGoblin,
virtualenv and Nginx on a .deb or .rpm-based GNU/Linux distribution.



@@ 66,14 66,14 @@ MediaGoblin has the following core dependencies:

These instructions have been tested on Debian 11 and Fedora 33. These
instructions should approximately translate to recent Debian
derivatives such as Ubuntu 18.04 and Trisquel 8, and to relatives of
Fedora such as CentOS 8.
derivatives such as Ubuntu and Trisquel, and to relatives of Fedora
such as CentOS, but we haven't explicitly tested these options.

Issue the following commands:

.. code-block:: bash

    # Debian 10
    # Debian 11
    sudo apt update
    sudo apt install automake git nodejs npm python3-dev \
    python3-gst-1.0 python3-lxml python3-pil virtualenv


@@ 130,7 130,7 @@ Fedora also requires that you initialize and start the
PostgreSQL database with a few commands. The following commands are
not needed on a Debian-based platform, however::

    # Feora
    # Fedora
    sudo /usr/bin/postgresql-setup initdb
    sudo systemctl enable postgresql
    sudo systemctl start postgresql


@@ 428,6 428,12 @@ should be modeled on the following::
     # Forward requests to the MediaGoblin app server.
     location / {
        proxy_pass http://127.0.0.1:6543;
        # On Debian and derivatives the below proxy_set_header lines can be replaced by:
        # include proxy_params;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
     }
    }



@@ 473,9 479,19 @@ created::

    # Debian
    sudo chown --no-dereference --recursive mediagoblin:www-data /srv/mediagoblin.example.org
    sudo find /srv/mediagoblin.example.org -type d -exec chmod 755 {} \;
    sudo find /srv/mediagoblin.example.org -type f -exec chmod 644 {} \;
    sudo find /srv/mediagoblin.example.org/mediagoblin/user_dev/crypto -type d -exec chmod 750 {} \;
    sudo find /srv/mediagoblin.example.org/mediagoblin/user_dev/crypto -type f -exec chmod 640 {} \;
    sudo find /srv/mediagoblin.example.org/mediagoblin/bin -type f -exec chmod 750 {} \;

    # Fedora
    sudo chown --no-dereference --recursive mediagoblin:nginx /srv/mediagoblin.example.org
    sudo find /srv/mediagoblin.example.org -type d -exec chmod 755 {} \;
    sudo find /srv/mediagoblin.example.org -type f -exec chmod 644 {} \;
    sudo find /srv/mediagoblin.example.org/mediagoblin/user_dev/crypto -type d -exec chmod 750 {} \;
    sudo find /srv/mediagoblin.example.org/mediagoblin/user_dev/crypto -type f -exec chmod 640 {} \;
    sudo find /srv/mediagoblin.example.org/mediagoblin/bin -type f -exec chmod 750 {} \;

.. note::
   


@@ 572,7 588,7 @@ the error by entering either of::
    sudo systemctl status mediagoblin-celeryd.service
    sudo systemctl status mediagoblin-paster.service

Or view the full logs with:
Or view the full logs with::

    sudo journalctl -u mediagoblin-paster.service -f
    sudo journalctl -u mediagoblin-celeryd.service -f

M docs/source/siteadmin/media-types.rst => docs/source/siteadmin/media-types.rst +3 -3
@@ 174,10 174,10 @@ Raw image
MediaGoblin can extract and display the JPEG preview from RAW images.

To enable raw image you need to install the Python library ``py3exiv2``. This
library is not currently available for Debian 10 or 11 but can be installed from
the Python Package Index after installing the build dependencies::
library is not currently available for Debian 11 but can be installed from the
Python Package Index after installing the build dependencies::

    # Debian 10/11
    # Debian 11
    sudo apt install libexiv2-dev libboost-python-devn
    ./bin/pip install py3pyexiv2


M docs/source/siteadmin/plugins.rst => docs/source/siteadmin/plugins.rst +1 -2
@@ 54,8 54,7 @@ offer for your media), we would do::
   If you're using a virtual environment, make sure to activate the
   virtual environment before installing with pip. Otherwise the plugin
   may get installed in a different environment than the one MediaGoblin
   is installed in. Also make sure, you use e.g. pip-2.7 if your default
   python (and thus pip) is python 3 (e.g. in Ubuntu and derivatives).
   is installed in.

Once you've installed the plugin software, you need to tell
MediaGoblin that this is a plugin you want MediaGoblin to use. To do

M docs/source/siteadmin/relnotes.rst => docs/source/siteadmin/relnotes.rst +47 -3
@@ 19,9 19,53 @@ Release Notes

This chapter has important information about our current and previous releases.

..
   **To do:**
   - add TLS to deploying documentation

0.12.1
=========

This patch release fixes a number of Python dependency issues, allows us to
support newer autoconf versions, fixes a few small bugs and improves the
documentation.

This release has been tested on Debian Bullseye (11) and Ubuntu 20.04. Due to a
dependency issue, we unfortunately **don't yet support Python 3.10**, which
means that Debian Bookworm and Ubuntu 22.04 and Fedora 36 are not yet
supported. This will be addressed in the upcoming version 0.13.0. This will be
the last release to support Python 3.5.

**Upgrading:**

For detailed instructions on installing or upgrading, see ":doc:`upgrading`" and
":doc:`deploying`".

If you have any problems, please drop in to the `#mediagoblin IRC chat
<https://web.libera.chat/#mediagoblin>`_, report an issue on our `issue
tracker <https://todo.sr.ht/~mediagoblin/mediagoblin>`_ or drop us an email to
`mediagoblin-devel@gnu.org <mailto:mediagoblin-devel@gnu.org>`_.

**Changes:**

- Convert README to Markdown for better display on SourceHut, add goblin, fix links (Ben Sturmfels)
- Add a troubleshooting page to the docs. (Ben Sturmfels)
- Fix incorrect setuptools install location for db/migrations/env.py (Elisei Roca)
- Add a "Troubleshooting" page to the documentation (Ben Sturmfels)
- Add Ubuntu 20.04 CI build (Ben Sturmfels)
- Add cc0 license to guix package (jgart)
- Add instructions to set permissions on installation directories (Ben Sturmfels)
- Switch from `py-bcrypt` to `bcrypt` (Elisei Roca)
- Explicitly specify we don't support Python 3.10 yet (Olivier Mehani)

**Bug fixes:**

- Fix references to non-existent package.json [trac#5615] (Ben Sturmfels)
- Remove unneeded shebang from test_processing.py (Elisei Roca)
- Fix incorrect setuptools install location for db/migrations/env.py (Elisei Roca)
- Pin version of `jinja2` dependency to avoid AttributeError and Ubuntu installation issues (Dan Helfman, Olivier Mehani)
- Add support for autoconf > 2.69 [srht#12] (Peter Horvath)
- Switch to `pytest --forked` for parallel test runs as `pytest-xdist` 3.0.2 dropped `--boxed` (Ben Sturmfels)
- Fix encoding of passwords before hashing (Olivier Mehani)
- Fix remaining bcrypt issue (Olivier Mehani, Elisei Roca)
- Document need for Nginx `proxy_set_header Host` config [trac#5612] (Ben Sturmfels)


0.12.0

A docs/source/siteadmin/troubleshooting.rst => docs/source/siteadmin/troubleshooting.rst +51 -0
@@ 0,0 1,51 @@
.. MediaGoblin Documentation

   Written in 2011, 2012, 2013, 2020, 2021 by MediaGoblin contributors

   To the extent possible under law, the author(s) have dedicated all
   copyright and related and neighboring rights to this software to
   the public domain worldwide. This software is distributed without
   any warranty.

   You should have received a copy of the CC0 Public Domain
   Dedication along with this software. If not, see
   <http://creativecommons.org/publicdomain/zero/1.0/>.

.. _troubleshooting-chapter:

===============
Troubleshooting
===============

Sometimes it doesn't all go to plan! This page describes some of the problems
that community members have reported and how to fix them.


TypeError: object() takes no parameters
---------------------------------------

Backtrace::

    2021-04-04 06:04:55,244 WARNING [mediagoblin.processing] No idea what happened here, but it failed: TypeError('object() takes no parameters',)
    2021-04-04 06:04:55,262 ERROR   [waitress] Exception while serving /submit/
    ...
    File "/opt/mediagoblin/mediagoblin/media_types/video/transcoders.py", line 338, in __setup_videoscale_capsfilter
        caps_struct.set_value('pixel-aspect-ratio', Gst.Fraction(1, 1))
    TypeError: object() takes no parameters

This is caused by not having the package python3-gst-1.0 on Debian:

http://gstreamer-devel.966125.n4.nabble.com/How-to-use-Gst-Fraction-in-python-td4679228.html


alembic.util.exc.CommandError: Can't locate revision identified by 'e9212d3a12d3'
---------------------------------------------------------------------------------

This is caused when you've enabled a plugin, run dbupdate and then disabled the
plugin again. Currently we recommend reinstalling the plugin, but we understand
this is not ideal. See the outstanding issue raised here:

https://issues.mediagoblin.org/ticket/5447

It's possible that manually manipulating the ``alembic_version`` table may help
you, but that approach is only recommended for experienced developers.

M docs/source/siteadmin/upgrading.rst => docs/source/siteadmin/upgrading.rst +17 -11
@@ 28,31 28,37 @@ MediaGoblin/Celery processes before upgrading.
Upgrade
-------

1. Update to the latest release.  In your ``mediagoblin`` directory, run::
1. Switch to the user you used to deploy MediaGoblin, which may be "mediagoblin"
   if you followed the deployment guide::

     git fetch && git checkout -q v0.12.0 && git submodule update
     sudo su mediagoblin --shell=/bin/bash

2. Note down any plugins you have installed by reviewing your
2. Update to the latest release.  In your ``mediagoblin`` directory, run::

     git fetch && git checkout -q v0.12.1 && git submodule update

3. Note down any plugins you have installed by reviewing your
   ``mediagoblin.ini`` configuration. These will be removed by the following
   steps and must be re-installed.

3. Remove your existing installation::
4. Remove your existing installation::

     make distclean

4. Recreate the virtual environment and install MediaGoblin::
5. Recreate the virtual environment and install MediaGoblin::

     ./bootstrap.sh && ./configure && make

     ./bootstrap.sh && ./configure &&
     make
   You may need to update file permissions as mentioned in ":doc:`deploying`".

5. Re-install any ":doc:`plugins`" you had previously installed. Skipping these
6. Re-install any ":doc:`plugins`" you had previously installed. Skipping these
   may result in errors updating the database.

6. Update the database::
7. Update the database::

     ./bin/gmg dbupdate

7. Restart the Paster and Celery processes. If you followed ":doc:`deploying`",
8. Restart the Paster and Celery processes. If you followed ":doc:`deploying`",
   this may be something like::

     sudo systemctl restart mediagoblin-paster.service


@@ 63,7 69,7 @@ Upgrade
     sudo journalctl -u mediagoblin-paster.service -f
     sudo journalctl -u mediagoblin-celeryd.service -f

8. View your site and hover your cursor over the "MediaGoblin" link in the
9. View your site and hover your cursor over the "MediaGoblin" link in the
   footer to confirm the version number you're running.



M extlib/README => extlib/README +6 -6
@@ 3,15 3,15 @@
=========================

This directory contains two kinds of things: external dependencies
specified in package.json (which gets installed into the node_modules
specified in bower.json (which gets installed into the node_modules
directory), and full copies of third-party code, which we call
embedded code copies.


External dependencies specified in package.json
External dependencies specified in bower.json
===============================================

package.json is a file that specifies external code dependencies. We
bower.json is a file that specifies external code dependencies. We
download those using the "npm" tool. As a developer of MediaGoblin,
install npm however is convenient for you (for example, apt-get
install npm).


@@ 19,16 19,16 @@ install npm).
If you are "merely installing" MediaGoblin (and aren't attempting to
change its code), you should know that the MediaGoblin team's main
release download, also known as the MediaGoblin mulltipack tarball,
contains a copy of all the code specified via package.json.
contains a copy of all the code specified via bower.json.

As a general rule, always specify dependencies in package.json using
As a general rule, always specify dependencies in bower.json using
"==" to pin to a specific release that you have tested MediaGoblin
with. The MediaGoblin team always welcomes patches that merely change
the version of a dependency so long as you have tested that the app
works. Doing this is a valuable and significant contribution to the
project.

Other notes about the contents of package.json:
Other notes about the contents of bower.json:

* Inconsolata is available in the npm repositories, but it does not
  include the OTF font format, and at the time of writing it appears

M guix-env.scm => guix-env.scm +11 -5
@@ 107,7 107,7 @@
;;;
;;; Run the tests:
;;;
;;;   bin/python -m pytest -rs ./mediagoblin/tests/ --boxed
;;;   bin/python -m pytest -rs ./mediagoblin/tests/ --forked
;;;
;;; or:
;;;


@@ 123,7 123,7 @@
(use-modules (ice-9 match)
             (srfi srfi-1)
             (guix packages)
             (guix licenses)
             ((guix licenses) #:prefix license:)
             (guix download)
             (guix git-download)
             (guix build-system gnu)


@@ 177,7 177,7 @@
             (setenv "PYTHONPATH"
                     (string-append (getcwd) ":"
                                    (getenv "PYTHONPATH")))
             (invoke "pytest" "mediagoblin/tests" "-rs" "--boxed"
             (invoke "pytest" "mediagoblin/tests" "-rs" "--forked"
                     ;; Skip the audio tests until updated libsndfile
                     ;; has been merged from core-updates branch.
                     "--deselect=test_audio.py::test_thumbnails"


@@ 207,7 207,7 @@
       ("python-openid" ,python-openid) ; For OpenID plugin
       ("python-pastescript" ,python-pastescript)
       ("python-pillow" ,python-pillow)
       ("python-py-bcrypt" ,python-py-bcrypt)
       ("python-bcrypt" ,python-bcrypt)
       ("python-pyld" ,python-pyld)
       ("python-pytz" ,python-pytz)
       ("python-requests" ,python-requests) ; For batchaddmedia


@@ 233,6 233,12 @@
       ("python-pygobject" ,python-pygobject)

       ;; PDF media.
       ;;
       ;; jgart suggests that we'll need to wrap the binaries used in
       ;; mediagoblin/media_types/pdf/processing.py - pdftocairo, pdfinfo, and
       ;; unoconv probably need to be wrapped to point to the executable that is
       ;; in /gnu/store. See this issue for a similar discussion about wrapping
       ;; binaries with guix: https://issues.guix.gnu.org/50833
       ("poppler" ,poppler)))
    (home-page "https://mediagoblin.org/")
    (synopsis "Web application for media publishing")


@@ 240,6 246,6 @@
     "MediaGoblin is a free software media publishing platform that anyone can
run. You can think of it as a decentralized alternative to Flickr, YouTube,
SoundCloud, etc.")
    (license agpl3+)))
    (license (list license:agpl3+ license:cc0))))

mediagoblin

D m4/python.m4 => m4/python.m4 +0 -646
@@ 1,646 0,0 @@
# Copyright 2012, 2013, 2014 Brandon Invergo <brandon@invergo.net>
#
# This file is part of pyconfigure.  This program is free
# software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# Under Section 7 of GPL version 3, you are granted additional
# permissions described in the Autoconf Configure Script Exception,
# version 3.0, as published by the Free Software Foundation.
#
# You should have received a copy of the GNU General Public License
# and a copy of the Autoconf Configure Script Exception along with
# this program; see the files COPYINGv3 and COPYING.EXCEPTION
# respectively.  If not, see <http://www.gnu.org/licenses/>.


# Many of these macros were adapted from ones written by Andrew Dalke
# and James Henstridge and are included with the Automake utility
# under the following copyright terms:
#
# Copyright (C) 1999-2012 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# Table of Contents:
#
# 1. Language selection
#    and routines to produce programs in a given language.
#
# 2. Producing programs in a given language.
#
# 3. Looking for a compiler
#    And possibly the associated preprocessor.
#
# 4. Looking for specific libs & functionality


## ----------------------- ##
## 1. Language selection.  ##
## ----------------------- ##


# AC_LANG(Python)
# ---------------
AC_LANG_DEFINE([Python], [py], [PY], [PYTHON], [],
[ac_ext=py
ac_compile='chmod +x conftest.$ac_ext >&AS_MESSAGE_LOG_FD'
ac_link='chmod +x conftest.$ac_ext && cp conftest.$ac_ext conftest >&AS_MESSAGE_LOG_FD'
])


# AC_LANG_PYTHON
# --------------
AU_DEFUN([AC_LANG_PYTHON], [AC_LANG(Python)])


## ----------------------- ##
## 2. Producing programs.  ##
## ----------------------- ##


# AC_LANG_PROGRAM(Python)([PROLOGUE], [BODY])
# -------------------------------------------
m4_define([AC_LANG_PROGRAM(Python)], [dnl
@%:@!$PYTHON
$1
m4_if([$2], [], [], [dnl
if __name__ == '__main__':
$2])])


# _AC_LANG_IO_PROGRAM(Python)
# ---------------------------
# Produce source that performs I/O.
m4_define([_AC_LANG_IO_PROGRAM(Python)],
[AC_LANG_PROGRAM([dnl
import sys
try:
    h = open('conftest.out')
except:
    sys.exit(1)
else:
    close(h)
    sys.exit(0)
], [])])


# _AC_LANG_CALL(Python)([PROLOGUE], [FUNCTION])
# ---------------------
# Produce source that calls FUNCTION
m4_define([_AC_LANG_CALL(Python)],
[AC_LANG_PROGRAM([$1], [$2])])


## -------------------------------------------- ##
## 3. Looking for Compilers and Interpreters.   ##
## -------------------------------------------- ##


AC_DEFUN([AC_LANG_COMPILER(Python)],
[AC_REQUIRE([PC_PROG_PYTHON])])


# PC_INIT([MIN-VERSION], [MAX-VERSION]) 
# -----------------------------
# Initialize pyconfigure, finding a Python interpreter with a given
# minimum and/or maximum version. 
AC_DEFUN([PC_INIT],
[PC_PROG_PYTHON([], [$1], [$2])
dnl If we found something, do a sanity check that the interpreter really
dnl has the version its name would suggest.
m4_ifval([PYTHON],
        [PC_PYTHON_VERIFY_VERSION([>=], [pc_min_ver], [],
                  [AC_MSG_FAILURE([No compatible Python interpreter found. If you're sure that you have one, try setting the PYTHON environment variable to the location of the interpreter.])])])
m4_ifval([PYTHON],
        [PC_PYTHON_VERIFY_VERSION([<=], [pc_max_ver], [],
                  [AC_MSG_FAILURE([No compatible Python interpreter found. If you're sure that you have one, try setting the PYTHON environment variable to the location of the interpreter.])])])
])# PC_INIT

# PC_PROG_PYTHON([PROG-TO-CHECK-FOR], [MIN-VERSION], [MAX-VERSION])
# ---------------------------------
# Find a Python interpreter.  Python versions prior to 2.0 are not
# supported. (2.0 was released on October 16, 2000).
AC_DEFUN_ONCE([PC_PROG_PYTHON],
[AC_ARG_VAR([PYTHON], [the Python interpreter])
dnl The default minimum version is 2.0
m4_define_default([pc_min_ver], m4_ifval([$2], [$2], [2.0]))
dnl The default maximum version is 3.3
m4_define_default([pc_max_ver], m4_ifval([$3], [$3], [4.0]))
dnl Build up a list of possible interpreter names. 
m4_define_default([_PC_PYTHON_INTERPRETER_LIST],
    [[python] \
dnl If we want some Python 3 versions (max version >= 3.0), 
dnl also search for "python3"
     m4_if(m4_version_compare(pc_max_ver, [2.9]), [1], [python3], []) \
dnl If we want some Python 2 versions (min version <= 2.7),
dnl also search for "python2".
     m4_if(m4_version_compare(pc_min_ver, [2.8]), [-1], [python2], []) \
dnl Construct a comma-separated list of interpreter names (python2.6, 
dnl python2.7, etc). We only care about the first 3 characters of the
dnl version strings (major-dot-minor; not 
dnl major-dot-minor-dot-bugfix[-dot-whatever])
     m4_foreach([pc_ver], 
                    m4_esyscmd_s(seq -s[[", "]] -f["[[%.1f]]"] m4_substr(pc_max_ver, [0], [3]) -0.1 m4_substr(pc_min_ver, [0], [3])),
dnl Remove python2.8 and python2.9 since they will never exist
                    [m4_bmatch(pc_ver, [2.[89]], [], [python]pc_ver)])])
dnl Do the actual search at last.
m4_ifval([$1],
	[AC_PATH_PROGS(PYTHON, [$1 _PC_PYTHON_INTERPRETER_LIST])],
	[AC_PATH_PROGS(PYTHON, [_PC_PYTHON_INTERPRETER_LIST])])
])# PC_PROG_PYTHON
  

# PC_PYTHON_PROG_PYTHON_CONFIG(PROG-TO-CHECK-FOR)
# ----------------------------------------------
# Find the python-config program
AC_DEFUN([PC_PYTHON_PROG_PYTHON_CONFIG],
[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
AC_ARG_VAR([PYTHON_CONFIG], [the Python-config program])
dnl python-config's binary name is normally based on the Python interpreter's
dnl binary name (i.e. python2.7 -> python2.7-config)
m4_define([_PYTHON_BASENAME], [`basename $PYTHON`])
m4_ifval([$1],
	[AC_PATH_PROGS(PYTHON_CONFIG, [$1 _PYTHON_BASENAME-config])],
	[AC_PATH_PROG(PYTHON_CONFIG, _PYTHON_BASENAME-config)])
]) # PC_PYTHON_PROG_PYTHON_CONFIG


# PC_PYTHON_VERIFY_VERSION([RELATION], [VERSION], [ACTION-IF-TRUE], [ACTION-IF-FALSE])
# ---------------------------------------------------------------------------
# Run ACTION-IF-TRUE if the Python interpreter PROG has version [RELATION] VERSION.
# i.e if RELATION is "<", check if PROG has a version number less than VERSION.
# Run ACTION-IF-FALSE otherwise.
# Specify RELATION as any mathematical comparison "<", ">", "<=", ">=", "==" or "!="
# This test uses sys.hexversion instead of the string equivalent (first
# word of sys.version), in order to cope with versions such as 2.2c1.
# This supports Python 2.0 or higher. (2.0 was released on October 16, 2000).
AC_DEFUN([PC_PYTHON_VERIFY_VERSION],
[m4_define([pc_python_safe_ver], m4_bpatsubsts($2, [\.], [_]))
AC_CACHE_CHECK([if Python $1 '$2'],
    [[pc_cv_python_req_version_]pc_python_safe_ver],
    [AC_LANG_PUSH(Python)[]dnl
     AC_RUN_IFELSE(
        [AC_LANG_PROGRAM([dnl
import sys
], [dnl
    # split strings by '.' and convert to numeric.  Append some zeros
    # because we need at least 4 digits for the hex conversion.
    # map returns an iterator in Python 3.0 and a list in 2.x
    reqver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]]
    reqverhex = 0
    # xrange is not present in Python 3.0 and range returns an iterator
    for i in list(range(4)):
        reqverhex = (reqverhex << 8) + reqver[[i]]
    # the final 8 bits are "0xf0" for final versions, which are all
    # we'll test against, since it's doubtful that a released software
    # will depend on an alpha- or beta-state Python.
    reqverhex += 0xf0
    if sys.hexversion $1 reqverhex:
        sys.exit()
    else:
        sys.exit(1)
])], 
         [[pc_cv_python_req_version_]pc_python_safe_ver=yes], 
         [[pc_cv_python_req_version_]pc_python_safe_ver=no])
     AC_LANG_POP(Python)[]dnl
    ])
AS_IF([test "$[pc_cv_python_req_version_]pc_python_safe_ver" = "no"], [$4], [$3])
])# PC_PYTHON_VERIFY_VERSION


# PC_PYTHON_CHECK_VERSION
# -----------------------
# Query Python for its version number.  Getting [:3] seems to be
# the best way to do this; it's what "site.py" does in the standard
# library.
AC_DEFUN([PC_PYTHON_CHECK_VERSION],
[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
AC_CACHE_CHECK([for $1 version], 
    [pc_cv_python_version],
    [AC_LANG_PUSH(Python)[]dnl
     AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
import sys
], [dnl
    sys.stdout.write(sys.version[[:3]])
])],
                   [pc_cv_python_version=`./conftest`],
                   [AC_MSG_FAILURE([failed to run Python program])])
     AC_LANG_POP(Python)[]dnl
    ])
AC_SUBST([PYTHON_VERSION], [$pc_cv_python_version])
])# PC_PYTHON_CHECK_VERSION


# PC_PYTHON_CHECK_PREFIX
# ----------------------
# Use the value of $prefix for the corresponding value of
# PYTHON_PREFIX. This is made a distinct variable so it can be
# overridden if need be.  However, general consensus is that you
# shouldn't need this ability. 
AC_DEFUN([PC_PYTHON_CHECK_PREFIX],
[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
dnl Try to get it with python-config otherwise do it from within Python
AC_CACHE_CHECK([for Python prefix], [pc_cv_python_prefix],
[if test -x "$PYTHON_CONFIG"; then
    pc_cv_python_prefix=`$PYTHON_CONFIG --prefix 2>&AS_MESSAGE_LOG_FD`
else
    AC_LANG_PUSH(Python)[]dnl
    AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
import sys
], [dnl
    sys.stdout.write(sys.prefix)
])], [pc_cv_python_prefix=`./conftest`;
      if test $? != 0; then
         AC_MSG_FAILURE([could not determine Python prefix])
      fi],
      [AC_MSG_FAILURE([failed to run Python program])])
    AC_LANG_POP(Python)[]dnl
fi])
AC_SUBST([PYTHON_PREFIX], [$pc_cv_python_prefix])])


# PC_PYTHON_CHECK_EXEC_PREFIX
# --------------------------
# Like above, but for $exec_prefix
AC_DEFUN([PC_PYTHON_CHECK_EXEC_PREFIX],
[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
dnl Try to get it with python-config otherwise do it from within Python
AC_CACHE_CHECK([for Python exec-prefix], [pc_cv_python_exec_prefix],
[if test -x "$PYTHON_CONFIG"; then
    pc_cv_python_exec_prefix=`$PYTHON_CONFIG --exec-prefix 2>&AS_MESSAGE_LOG_FD`
else
    AC_LANG_PUSH(Python)[]dnl
    AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
import sys
], [dnl
    sys.stdout.write(sys.exec_prefix)
])],
        [pc_cv_python_exec_prefix=`./conftest`;
         if test $? != 0; then
            AC_MSG_FAILURE([could not determine Python exec_prefix])
         fi],
         [AC_MSG_FAILURE([failed to run Python program])])
    AC_LANG_POP(Python)[]dnl
fi
])
AC_SUBST([PYTHON_EXEC_PREFIX], [$pc_cv_python_exec_prefix])])


# PC_PYTHON_CHECK_INCLUDES
# ------------------------
# Find the Python header file include flags (ie
# '-I/usr/include/python')
AC_DEFUN([PC_PYTHON_CHECK_INCLUDES],
[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
dnl Try to find the headers location with python-config otherwise guess
AC_CACHE_CHECK([for Python includes], [pc_cv_python_includes],
[if test -x "$PYTHON_CONFIG"; then
    pc_cv_python_includes=`$PYTHON_CONFIG --includes 2>&AS_MESSAGE_LOG_FD`
else
    pc_cv_python_includes="[-I$includedir/$_PYTHON_BASENAME]m4_ifdef(PYTHON_ABI_FLAGS,
    PYTHON_ABI_FLAGS,)"
fi
])
AC_SUBST([PYTHON_INCLUDES], [$pc_cv_python_includes])])


# PC_PYTHON_CHECK_HEADERS([ACTION-IF-PRESENT], [ACTION-IF-ABSENT])
# -----------------------
# Check for the presence and usability of Python.h
AC_DEFUN([PC_PYTHON_CHECK_HEADERS],
[AC_REQUIRE([PC_PYTHON_CHECK_INCLUDES])[]dnl
pc_cflags_store=$CPPFLAGS
CPPFLAGS="$CFLAGS $PYTHON_INCLUDES"
AC_CHECK_HEADER([Python.h], [$1], [$2])
CPPFLAGS=$pc_cflags_store
])


# PC_PYTHON_CHECK_LIBS
# --------------------
# Find the Python lib flags (ie '-lpython')
AC_DEFUN([PC_PYTHON_CHECK_LIBS],
[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
dnl Try to find the lib flags with python-config otherwise guess
AC_CACHE_CHECK([for Python libs], [pc_cv_python_libs],
[if test -x "$PYTHON_CONFIG"; then
    pc_cv_python_libs=`$PYTHON_CONFIG --libs 2>&AS_MESSAGE_LOG_FD`
else
    pc_cv_python_libs="[-l$_PYTHON_BASENAME]m4_ifdef(PYTHON_ABI_FLAGS, PYTHON_ABI_FLAGS,)"
fi
])
AC_SUBST([PYTHON_LIBS], [$pc_cv_python_libs])])


# PC_PYTHON_TEST_LIBS(LIBRARY-FUNCTION, [ACTION-IF-PRESENT], [ACTION-IF-ABSENT])
# -------------------
# Verify that the Python libs can be loaded
AC_DEFUN([PC_PYTHON_TEST_LIBS],
[AC_REQUIRE([PC_PYTHON_CHECK_LIBS])[]dnl
pc_libflags_store=$LIBS
for lflag in $PYTHON_LIBS; do
    case $lflag in
    	 -lpython*@:}@
		LIBS="$LIBS $lflag"
		pc_libpython=`echo $lflag | sed -e 's/^-l//'`
		;;
         *@:}@;;
    esac
done
AC_CHECK_LIB([$pc_libpython], [$1], [$2], [$3])])


# PC_PYTHON_CHECK_CFLAGS
# ----------------------
# Find the Python CFLAGS
AC_DEFUN([PC_PYTHON_CHECK_CFLAGS],
[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
dnl Try to find the CFLAGS with python-config otherwise give up
AC_CACHE_CHECK([for Python CFLAGS], [pc_cv_python_cflags],
[if test -x "$PYTHON_CONFIG"; then
    pc_cv_python_cflags=`$PYTHON_CONFIG --cflags 2>&AS_MESSAGE_LOG_FD`
else
    pc_cv_python_cflags=
fi
])
AC_SUBST([PYTHON_CFLAGS], [$pc_cv_python_cflags])])


# PC_PYTHON_CHECK_LDFLAGS
# -----------------------
# Find the Python LDFLAGS
AC_DEFUN([PC_PYTHON_CHECK_LDFLAGS],
[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
dnl Try to find the LDFLAGS with python-config otherwise give up
AC_CACHE_CHECK([for Python LDFLAGS], [pc_cv_python_ldflags],
[if test -x "$PYTHON_CONFIG"; then
    pc_cv_python_ldflags=`$PYTHON_CONFIG --ldflags 2>&AS_MESSAGE_LOG_FD`
else
    pc_cv_python_ldflags=
fi
])
AC_SUBST([PYTHON_LDFLAGS], [$pc_cv_python_ldflags])])


# PC_PYTHON_CHECK_EXTENSION_SUFFIX
# --------------------------------
# Find the Python extension suffix (i.e. '.cpython-32.so')
AC_DEFUN([PC_PYTHON_CHECK_EXTENSION_SUFFIX],
[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
dnl Try to find the suffix with python-config otherwise give up
AC_CACHE_CHECK([for Python extension suffix], [pc_cv_python_extension_suffix],
[if test -x "$PYTHON_CONFIG"; then
     pc_cv_python_extension_suffix=`$PYTHON_CONFIG --extension-suffix 2>&AS_MESSAGE_LOG_FD`
else
    pc_cv_python_extension_suffix=
fi
])
AC_SUBST([PYTHON_EXTENSION_SUFFIX], [$pc_cv_python_extension_suffix])])


# PC_PYTHON_CHECK_ABI_FLAGS
# -------------------------
# Find the Python ABI flags
AC_DEFUN([PC_PYTHON_CHECK_ABI_FLAGS],
[AC_REQUIRE([PC_PYTHON_PROG_PYTHON_CONFIG])[]dnl
dnl Try to find the ABI flags with python-config otherwise give up
AC_CACHE_CHECK([for Python ABI flags], [pc_cv_python_abi_flags],
[if test -x "$PYTHON_CONFIG"; then
     pc_cv_python_abi_flags=`$PYTHON_CONFIG --abiflags 2>&AS_MESSAGE_LOG_FD`
else
    pc_cv_python_abi_flags=
fi
])
AC_SUBST([PYTHON_ABI_FLAGS], [$pc_cv_python_abi_flags])])


# PC_PYTHON_CHECK_PLATFORM
# ------------------------
# At times (like when building shared libraries) you may want
# to know which OS platform Python thinks this is.
AC_DEFUN([PC_PYTHON_CHECK_PLATFORM],
[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
dnl Get the platform from within Python (sys.platform)
AC_CACHE_CHECK([for Python platform], [pc_cv_python_platform],
    [AC_LANG_PUSH(Python)[]dnl
     AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
import sys
], [dnl
    sys.stdout.write(sys.platform)
])], [pc_cv_python_platform=`./conftest`;
     if test $? != 0; then
        AC_MSG_FAILURE([could not determine Python platform])
     fi],
     [AC_MSG_FAILURE([failed to run Python program])])
    AC_LANG_POP(Python)[]dnl
   ])
AC_SUBST([PYTHON_PLATFORM], [$pc_cv_python_platform])
])


# PC_PYTHON_CHECK_SITE_DIR
# ---------------------
# The directory to which new libraries are installed (i.e. the
# "site-packages" directory.
AC_DEFUN([PC_PYTHON_CHECK_SITE_DIR],
[AC_REQUIRE([PC_PROG_PYTHON])AC_REQUIRE([PC_PYTHON_CHECK_PREFIX])[]dnl
AC_CACHE_CHECK([for Python site-packages directory],
    [pc_cv_python_site_dir],
    [AC_LANG_PUSH(Python)[]dnl
    if test "x$prefix" = xNONE
     then
       pc_py_prefix=$ac_default_prefix
     else
       pc_py_prefix=$prefix
     fi
     AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
import sys
from platform import python_implementation
# sysconfig in CPython 2.7 doesn't work in virtualenv
# <https://github.com/pypa/virtualenv/issues/118>
try:
    import sysconfig
except:
    can_use_sysconfig = False
else:
    can_use_sysconfig = True
if can_use_sysconfig:
    if python_implementation() == "CPython" and sys.version[[:3]] == '2.7':
        can_use_sysconfig = False
if not can_use_sysconfig:        
    from distutils import sysconfig
    sitedir = sysconfig.get_python_lib(False, False, prefix='$pc_py_prefix')
else:
    sitedir = sysconfig.get_path('purelib', vars={'base':'$pc_py_prefix'})
], [dnl
    sys.stdout.write(sitedir)
])], [pc_cv_python_site_dir=`./conftest`],
     [AC_MSG_FAILURE([failed to run Python program])])
     AC_LANG_POP(Python)[]dnl
     case $pc_cv_python_site_dir in
     $pc_py_prefix*)
       pc__strip_prefix=`echo "$pc_py_prefix" | sed 's|.|.|g'`
       pc_cv_python_site_dir=`echo "$pc_cv_python_site_dir" | sed "s,^$pc__strip_prefix/,,"`
       ;;
     *)
       case $pc_py_prefix in
         /usr|/System*) ;;
         *)
	  pc_cv_python_site_dir=lib/python$PYTHON_VERSION/site-packages
	  ;;
       esac
       ;;
     esac
     ])
AC_SUBST([pythondir], [\${prefix}/$pc_cv_python_site_dir])])# PC_PYTHON_CHECK_SITE_DIR

# PC_PYTHON_SITE_PACKAGE_DIR
# --------------------------
# $PACKAGE directory under PYTHON_SITE_DIR
AC_DEFUN([PC_PYTHON_SITE_PACKAGE_DIR],
[AC_REQUIRE([PC_PYTHON_CHECK_SITE_DIR])[]dnl
AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE_NAME])])


# PC_PYTHON_CHECK_EXEC_DIR
# ------------------------
# directory for installing python extension modules (shared libraries)
AC_DEFUN([PC_PYTHON_CHECK_EXEC_DIR],
[AC_REQUIRE([PC_PROG_PYTHON])AC_REQUIRE([PC_PYTHON_CHECK_EXEC_PREFIX])[]dnl
  AC_CACHE_CHECK([for Python extension module directory],
    [pc_cv_python_exec_dir],
    [AC_LANG_PUSH(Python)[]dnl
    if test "x$pc_cv_python_exec_prefix" = xNONE
     then
       pc_py_exec_prefix=$pc_cv_python_prefix
     else
       pc_py_exec_prefix=$pc_cv_python_exec_prefix
     fi
     AC_LINK_IFELSE([AC_LANG_PROGRAM([dnl
import sys
from platform import python_implementation
# sysconfig in CPython 2.7 doesn't work in virtualenv
# <https://github.com/pypa/virtualenv/issues/118>
try:
    import sysconfig
except:
    can_use_sysconfig = False
else:
    can_use_sysconfig = True
if can_use_sysconfig:
    if python_implementation() == "CPython" and sys.version[[:3]] == '2.7':
        can_use_sysconfig = False
if not can_use_sysconfig:        
    from distutils import sysconfig
    sitedir = sysconfig.get_python_lib(False, False, prefix='$pc_py__exec_prefix')
else:
    sitedir = sysconfig.get_path('purelib', vars={'platbase':'$pc_py_exec_prefix'})
], [dnl
    sys.stdout.write(sitedir)
])], [pc_cv_python_exec_dir=`./conftest`],
     [AC_MSG_FAILURE([failed to run Python program])])
     AC_LANG_POP(Python)[]dnl
     case $pc_cv_python_exec_dir in
     $pc_py_exec_prefix*)
       pc__strip_prefix=`echo "$pc_py_exec_prefix" | sed 's|.|.|g'`
       pc_cv_python_exec_dir=`echo "$pc_cv_python_exec_dir" | sed "s,^$pc__strip_prefix/,,"`
       ;;
     *)
       case $pc_py_exec_prefix in
         /usr|/System*) ;;
         *)
	   pc_cv_python_exec_dir=lib/python$PYTHON_VERSION/site-packages
	   ;;
       esac
       ;;
     esac
    ])
AC_SUBST([pyexecdir], [\${exec_prefix}/$pc_cv_python_pyexecdir])]) #PY_PYTHON_CHECK_EXEC_LIB_DIR


# PC_PYTHON_EXEC_PACKAGE_DIR
# --------------------------
# $PACKAGE directory under PYTHON_SITE_DIR
AC_DEFUN([PC_PYTHON_EXEC_PACKAGE_DIR],
[AC_REQUIRE([PC_PYTHON_CHECK_EXEC_DIR])[]dnl
AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE_NAME])])


## -------------------------------------------- ##
## 4. Looking for specific libs & functionality ##
## -------------------------------------------- ##


# PC_PYTHON_CHECK_MODULE(LIBRARY, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# ----------------------------------------------------------------------
# Macro for checking if a Python library is installed
AC_DEFUN([PC_PYTHON_CHECK_MODULE],
[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
m4_define([pc_python_safe_mod], m4_bpatsubsts($1, [\.], [_]))
AC_CACHE_CHECK([for Python '$1' library],
    [[pc_cv_python_module_]pc_python_safe_mod],
    [AC_LANG_PUSH(Python)[]dnl
     AC_RUN_IFELSE(
	[AC_LANG_PROGRAM([dnl
import sys
try:
    import $1
except:
    sys.exit(1)
else:
    sys.exit(0)
], [])],
	[[pc_cv_python_module_]pc_python_safe_mod="yes"],
	[[pc_cv_python_module_]pc_python_safe_mod="no"])
     AC_LANG_POP(Python)[]dnl
    ])
AS_IF([test "$[pc_cv_python_module_]pc_python_safe_mod" = "no"], [$3], [$2])
])# PC_PYTHON_CHECK_MODULE


# PC_PYTHON_CHECK_FUNC([LIBRARY], FUNCTION, ARGS, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# ---------------------------------------------------------------------------------------
# Check to see if a given function call, optionally from a module, can
# be successfully called
AC_DEFUN([PC_PYTHON_CHECK_FUNC],
[AC_REQUIRE([PC_PROG_PYTHON])[]dnl
m4_define([pc_python_safe_mod], m4_bpatsubsts($1, [\.], [_]))
AC_CACHE_CHECK([for Python m4_ifnblank($1, '$1.$2()', '$2()') function],
    [[pc_cv_python_func_]pc_python_safe_mod[_$2]],
    [AC_LANG_PUSH(Python)[]dnl
     AC_RUN_IFELSE(
	[AC_LANG_PROGRAM([dnl
import sys
m4_ifnblank([$1], [dnl
try:
    import $1
except:
    sys.exit(1)
], [])], 
[
m4_ifnblank([$1], [
    try:
        $1.$2($3)], [
    try:
        $2($3)])
    except:
        sys.exit(1)
    else:
        sys.exit(0)
])],
	[[pc_cv_python_func_]pc_python_safe_mod[_$2]="yes"],
	[[pc_cv_python_func_]pc_python_safe_mod[_$2]="no"])
     AC_LANG_POP(Python)[]dnl
    ])
AS_IF([test "$[pc_cv_python_func_]pc_python_safe_mod[_$2]" = "no"], [$5], [$4])
])# PC_PYTHON_CHECK_FUNC

M mediagoblin.example.ini => mediagoblin.example.ini +10 -4
@@ 15,9 15,15 @@
direct_remote_path = /mgoblin_static/
email_sender_address = "notice@mediagoblin.example.org"

## Uncomment and change to your DB's appropiate setting.
## Default is a local sqlite db "mediagoblin.db".
## Don't forget to run `./bin/gmg dbupdate` after having changed it.
## Uncomment and change to your DB's appropiate setting. The default is a local
## sqlite db "mediagoblin.db".  Don't forget to run `./bin/gmg dbupdate` after
## having changed it.
##
## For a database on a remote server, use the format:
## sql_engine = postgresql://user:password@hostname:5432/dbname
##
## For a local database, use the format:
## sql_engine = postgresql:///dbname
# sql_engine = postgresql:///mediagoblin

# Set to false to enable sending notices


@@ 64,7 70,7 @@ base_url = /mgoblin_media/
# CELERY_DEFAULT_QUEUE = "default"

# Place plugins here, each in their own subsection of [plugins].
# See http://docs.mediagoblin.org/siteadmin/plugins.html for details.
# See https://docs.mediagoblin.org/en/master/siteadmin/plugins.html for details.
[plugins]
[[mediagoblin.plugins.geolocation]]
[[mediagoblin.plugins.basic_auth]]

M mediagoblin/_version.py => mediagoblin/_version.py +1 -1
@@ 23,4 23,4 @@

# see http://www.python.org/dev/peps/pep-0386/

__version__ = "0.12.0"
__version__ = "0.12.1"

M mediagoblin/api/views.py => mediagoblin/api/views.py +5 -4
@@ 20,13 20,14 @@ import mimetypes

from werkzeug.datastructures import FileStorage

from mediagoblin.decorators import oauth_required, require_active_login
from mediagoblin.decorators import oauth_required
from mediagoblin.api.decorators import user_has_privilege
from mediagoblin.db.models import User, LocalUser, MediaEntry, Comment, TextComment, Activity
from mediagoblin.db.models import (
    LocalUser, MediaEntry, TextComment, Activity, Location)
from mediagoblin.tools.federation import create_activity, create_generator
from mediagoblin.tools.routing import extract_url_arguments
from mediagoblin.tools.response import redirect, json_response, json_error, \
                                       render_404, render_to_response
from mediagoblin.tools.response import (
    redirect, json_response, json_error, render_to_response)
from mediagoblin.meddleware.csrf import csrf_exempt
from mediagoblin.submit.lib import new_upload_entry, api_upload_request, \
                                    api_add_to_feed

M mediagoblin/app.py => mediagoblin/app.py +0 -1
@@ 30,7 30,6 @@ try:
except ImportError:
    from werkzeug.wsgi import SharedDataMiddleware
from mediagoblin import meddleware, __version__
from mediagoblin.db.util import check_db_up_to_date
from mediagoblin.tools import common, session, translate, template
from mediagoblin.tools.response import render_http_exception
from mediagoblin.tools.theme import register_themes

M mediagoblin/db/migration_tools.py => mediagoblin/db/migration_tools.py +0 -3
@@ 19,11 19,8 @@ import logging
import os
import pkg_resources

from alembic import command
from alembic.config import Config
from alembic.migration import MigrationContext

from mediagoblin.db.base import Base
from mediagoblin.tools.common import simple_printer
from sqlalchemy import Table
from sqlalchemy.sql import select

M mediagoblin/db/migrations.py => mediagoblin/db/migrations.py +3 -5
@@ 31,7 31,7 @@ import pytz
import dateutil.tz
from sqlalchemy import (MetaData, Table, Column, Boolean, SmallInteger,
                        Integer, Unicode, UnicodeText, DateTime,
                        ForeignKey, Date, Index)
                        ForeignKey, Date)
from sqlalchemy.exc import ProgrammingError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.sql import and_


@@ 42,10 42,8 @@ from mediagoblin.tools import crypto
from mediagoblin.db.extratypes import JSONEncoded, MutationDict
from mediagoblin.db.migration_tools import (
    RegisterMigration, inspect_table, replace_table_hack, model_iteration_hack)
from mediagoblin.db.models import (MediaEntry, Collection, Comment, User,
                                   Privilege, Generator, LocalUser, Location,
                                   Client, RequestToken, AccessToken)
from mediagoblin.db.extratypes import JSONEncoded, MutationDict
from mediagoblin.db.models import (
    MediaEntry, Collection, Comment, User, Privilege, LocalUser, Location)


MIGRATIONS = {}

M mediagoblin/db/migrations/env.py => mediagoblin/db/migrations/env.py +0 -1
@@ 1,5 1,4 @@
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig

# this is the Alembic Config object, which provides

M mediagoblin/db/models.py => mediagoblin/db/models.py +6 -6
@@ 22,11 22,10 @@ TODO: indexes on foreignkeys, where useful.
import logging
import datetime

from sqlalchemy import Column, Integer, Unicode, UnicodeText, DateTime, \
        Boolean, ForeignKey, UniqueConstraint, PrimaryKeyConstraint, \
        SmallInteger, Date, types, Float
from sqlalchemy.orm import relationship, backref, with_polymorphic, validates, \
        class_mapper
from sqlalchemy import (
    Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey,
    UniqueConstraint, PrimaryKeyConstraint, SmallInteger, Date, Float)
from sqlalchemy.orm import relationship, backref, class_mapper
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.sql import and_
from sqlalchemy.sql.expression import desc


@@ 35,7 34,7 @@ from sqlalchemy.util import memoized_property

from mediagoblin.db.extratypes import (PathTupleWithSlashes, JSONEncoded,
                                       MutationDict)
from mediagoblin.db.base import Base, DictReadAttrProxy, FakeCursor
from mediagoblin.db.base import Base, DictReadAttrProxy
from mediagoblin.db.mixin import UserMixin, MediaEntryMixin, \
        CollectionMixin, CollectionItemMixin, ActivityMixin, TextCommentMixin, \
        CommentingMixin


@@ 49,6 48,7 @@ from pytz import UTC

_log = logging.getLogger(__name__)


class GenericModelReference(Base):
    """
    Represents a relationship to any model that is defined with a integer pk

M mediagoblin/decorators.py => mediagoblin/decorators.py +2 -2
@@ 23,8 23,8 @@ from urllib.parse import urljoin

from mediagoblin import mg_globals as mgg
from mediagoblin import messages
from mediagoblin.db.models import MediaEntry, LocalUser, TextComment, \
                                  AccessToken, Comment
from mediagoblin.db.models import (
    MediaEntry, LocalUser, AccessToken, Comment)
from mediagoblin.tools.response import (
    redirect, render_404,
    render_user_banned, json_response)

M mediagoblin/edit/views.py => mediagoblin/edit/views.py +4 -7
@@ 16,10 16,8 @@
from datetime import datetime

from itsdangerous import BadSignature
from pyld import jsonld
from werkzeug.exceptions import Forbidden
from werkzeug.utils import secure_filename
from jsonschema import ValidationError, Draft4Validator

from mediagoblin import messages
from mediagoblin import mg_globals


@@ 31,10 29,9 @@ from mediagoblin.edit.lib import may_edit_media
from mediagoblin.decorators import (require_active_login, active_user_from_url,
                            get_media_entry_by_id, user_may_alter_collection,
                            get_user_collection, user_has_privilege,
                            user_not_banned, user_may_delete_media)
                            user_not_banned)
from mediagoblin.tools.crypto import get_timed_signer_url
from mediagoblin.tools.metadata import (compact_and_validate, DEFAULT_CHECKER,
                                        DEFAULT_SCHEMA)
from mediagoblin.tools.metadata import compact_and_validate
from mediagoblin.tools.mail import email_debug_message
from mediagoblin.tools.response import (render_to_response,
                                        redirect, redirect_obj, render_404)


@@ 44,7 41,7 @@ from mediagoblin.tools.text import (
    convert_to_tag_list_of_dicts, media_tags_as_string)
from mediagoblin.tools.url import slugify
from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used
from mediagoblin.db.models import User, LocalUser, Client, AccessToken, Location
from mediagoblin.db.models import User, LocalUser, AccessToken, Location

import mimetypes



@@ 67,7 64,7 @@ def edit_media(request, media):
        license=media.license)

    form = forms.EditForm(
        request.method=='POST' and request.form or None,
        request.method == 'POST' and request.form or None,
        **defaults)

    if request.method == 'POST' and form.validate():

M mediagoblin/gmg_commands/addmedia.py => mediagoblin/gmg_commands/addmedia.py +1 -2
@@ 20,8 20,7 @@ import os
from mediagoblin.db.models import LocalUser
from mediagoblin.gmg_commands import util as commands_util
from mediagoblin.submit.lib import (
    submit_media, get_upload_file_limits,
    FileUploadLimit, UserUploadLimit, UserPastUploadLimit)
    submit_media, FileUploadLimit, UserUploadLimit, UserPastUploadLimit)

from mediagoblin import mg_globals


M mediagoblin/gmg_commands/assetlink.py => mediagoblin/gmg_commands/assetlink.py +0 -2
@@ 17,9 17,7 @@
import os

from mediagoblin import mg_globals
from mediagoblin.init import setup_global_and_app_config
from mediagoblin.gmg_commands import util as commands_util
from mediagoblin.tools.theme import register_themes
from mediagoblin.tools.translate import pass_to_ugettext as _
from mediagoblin.tools.common import simple_printer
from mediagoblin.tools import pluginapi

M mediagoblin/gmg_commands/batchaddmedia.py => mediagoblin/gmg_commands/batchaddmedia.py +1 -1
@@ 38,7 38,7 @@ This command allows the administrator to upload many media files at once."""
    subparser.epilog = _("""For more information about how to properly run this
script (and how to format the metadata csv file), read the MediaGoblin
documentation page on command line uploading
<http://docs.mediagoblin.org/siteadmin/commandline-upload.html>""")
<https://docs.mediagoblin.org/en/master/siteadmin/commandline-upload.html>""")
    subparser.add_argument(
        'username',
        help=_("Name of user these media entries belong to"))

M mediagoblin/gmg_commands/dbupdate.py => mediagoblin/gmg_commands/dbupdate.py +2 -2
@@ 117,9 117,9 @@ def run_foundations(db, global_config):
            foundations = import_component(
                '{}.models:FOUNDATIONS'.format(plugin))
            all_foundations.append((plugin, foundations))
        except ImportError as exc:
        except ImportError:
            continue
        except AttributeError as exc:
        except AttributeError:
            continue

    for name, foundations in all_foundations:

M mediagoblin/gmg_commands/reprocess.py => mediagoblin/gmg_commands/reprocess.py +0 -2
@@ 22,8 22,6 @@ from mediagoblin import mg_globals
from mediagoblin.db.models import MediaEntry
from mediagoblin.gmg_commands import util as commands_util
from mediagoblin.submit.lib import run_process_media
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
from mediagoblin.tools.pluginapi import hook_handle
from mediagoblin.processing import (
    ProcessorDoesNotExist, ProcessorNotEligible,
    get_entry_and_processing_manager, get_processing_manager_for_type,

M mediagoblin/media_types/blog/views.py => mediagoblin/media_types/blog/views.py +9 -14
@@ 15,38 15,33 @@
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import logging
_log = logging.getLogger(__name__)

from datetime import datetime

from werkzeug.exceptions import Forbidden
from mediagoblin.tools import pluginapi

from mediagoblin import messages, mg_globals

from mediagoblin.media_types.blog import forms as blog_forms
from mediagoblin.media_types.blog.models import Blog, BlogPostData
from mediagoblin.media_types.blog.models import Blog
from mediagoblin.media_types.blog.lib import (
        may_edit_blogpost, set_blogpost_state, get_all_blogposts_of_blog,
        get_blog_by_slug)
    may_edit_blogpost, set_blogpost_state, get_blog_by_slug)

from mediagoblin.decorators import (require_active_login, active_user_from_url,
                            get_media_entry_by_id, user_may_alter_collection,
                            get_user_collection, uses_pagination)
from mediagoblin.decorators import (
    require_active_login, active_user_from_url, get_media_entry_by_id,
    uses_pagination)
from mediagoblin.tools.pagination import Pagination
from mediagoblin.tools.response import (render_to_response,
                                        redirect, render_404)
from mediagoblin.tools.translate import pass_to_ugettext as _
from mediagoblin.tools.template import render_template
from mediagoblin.tools.text import (
    convert_to_tag_list_of_dicts, media_tags_as_string, clean_html,
    convert_to_tag_list_of_dicts, media_tags_as_string,
    cleaned_markdown_conversion)

from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used
from mediagoblin.db.models import User, Collection, MediaEntry, LocalUser
from mediagoblin.db.models import MediaEntry, LocalUser

from mediagoblin.notifications import add_comment_subscription

_log = logging.getLogger(__name__)


@require_active_login
def blog_edit(request):

M mediagoblin/media_types/video/transcoders.py => mediagoblin/media_types/video/transcoders.py +0 -2
@@ 20,9 20,7 @@ import sys
import logging
import multiprocessing

from mediagoblin import mg_globals as mgg
from mediagoblin.media_types.tools import discover
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
from .util import ACCEPTED_RESOLUTIONS

#os.environ['GST_DEBUG'] = '4,python:4'

M mediagoblin/moderation/views.py => mediagoblin/moderation/views.py +4 -6
@@ 84,8 84,6 @@ def moderation_users_detail(request):
    ).first()
    active_reports = user.reports_filed_on.filter(
        Report.resolved==None).limit(5)
    closed_reports = user.reports_filed_on.filter(
        Report.resolved!=None).all()
    privileges = Privilege.query
    user_banned = UserBan.query.get(user.id)
    ban_form = moderation_forms.BanForm()


@@ 93,11 91,11 @@ def moderation_users_detail(request):
    return render_to_response(
        request,
        'mediagoblin/moderation/user.html',
        {'user':user,
        {'user': user,
         'privileges': privileges,
         'reports':active_reports,
         'user_banned':user_banned,
         'ban_form':ban_form})
         'reports': active_reports,
         'user_banned': user_banned,
         'ban_form': ban_form})

@require_admin_or_moderator_login
@allow_reporting

M mediagoblin/plugins/api/tools.py => mediagoblin/plugins/api/tools.py +3 -4
@@ 15,11 15,9 @@
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import logging
import json

from functools import wraps
from werkzeug.exceptions import Forbidden
from werkzeug.wrappers import Response

from urllib.parse import urljoin



@@ 48,10 46,11 @@ class Auth:
    method.
    '''
    def trigger(self, request):
        raise NotImplemented()
        raise NotImplementedError()

    def __call__(self, request, *args, **kw):
        raise NotImplemented()
        raise NotImplementedError()


def get_entry_serializable(entry, urlgen):
    '''

M mediagoblin/plugins/api/views.py => mediagoblin/plugins/api/views.py +3 -3
@@ 26,9 26,9 @@ from mediagoblin.decorators import require_active_login
from mediagoblin.meddleware.csrf import csrf_exempt
from mediagoblin.media_types import FileTypeNotSupported
from mediagoblin.plugins.api.tools import api_auth, get_entry_serializable
from mediagoblin.submit.lib import \
    check_file_field, submit_media, get_upload_file_limits, \
    FileUploadLimit, UserUploadLimit, UserPastUploadLimit
from mediagoblin.submit.lib import (
    check_file_field, submit_media, FileUploadLimit, UserUploadLimit,
    UserPastUploadLimit)

_log = logging.getLogger(__name__)


M mediagoblin/plugins/archivalook/tools.py => mediagoblin/plugins/archivalook/tools.py +2 -2
@@ 13,10 13,10 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
from mediagoblin.db.models import MediaEntry, User, LocalUser
from mediagoblin.db.models import MediaEntry, LocalUser
from mediagoblin.plugins.archivalook.models import FeaturedMedia
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
from mediagoblin.plugins.archivalook.models import FeaturedMedia


def get_media_entry_from_uploader_slug(uploader_username, slug):
    """

M mediagoblin/plugins/archivalook/views.py => mediagoblin/plugins/archivalook/views.py +2 -2
@@ 31,7 31,7 @@ from mediagoblin.plugins.archivalook.models import FeaturedMedia
from mediagoblin.plugins.archivalook.utils import feature_template
from mediagoblin.plugins.archivalook.tools import (promote_feature,
                                                    demote_feature)
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _


@user_not_banned
def root_view(request):


@@ 126,7 126,7 @@ def feature_media(request, media, **kwargs):
    already_featured_media_ids = [f.media_entry.id 
        for f in FeaturedMedia.query.all()]
    if not media.id in already_featured_media_ids:
        new_feature = automatically_add_new_feature(media)
        automatically_add_new_feature(media)
    return redirect(
        request, 'index')


M mediagoblin/plugins/basic_auth/tools.py => mediagoblin/plugins/basic_auth/tools.py +7 -5
@@ 40,7 40,10 @@ def bcrypt_check_password(raw_pass, stored_hash, extra_salt=None):
    if extra_salt:
        raw_pass = "{}:{}".format(extra_salt, raw_pass)

    hashed_pass = bcrypt.hashpw(raw_pass.encode('utf-8'), stored_hash)
    raw_pass = raw_pass.encode('utf-8')
    stored_hash = stored_hash.encode('utf-8')

    hashed_pass = bcrypt.hashpw(raw_pass, stored_hash)

    # Reduce risk of timing attacks by hashing again with a random
    # number (thx to zooko on this advice, which I hopefully


@@ 66,8 69,7 @@ def bcrypt_gen_password_hash(raw_pass, extra_salt=None):
    if extra_salt:
        raw_pass = "{}:{}".format(extra_salt, raw_pass)

    return str(
        bcrypt.hashpw(raw_pass.encode('utf-8'), bcrypt.gensalt()))
    return bcrypt.hashpw(raw_pass.encode('utf-8'), bcrypt.gensalt()).decode()


def fake_login_attempt():


@@ 81,9 83,9 @@ def fake_login_attempt():
    """
    rand_salt = bcrypt.gensalt(5)

    hashed_pass = bcrypt.hashpw(str(random.random()), rand_salt)
    hashed_pass = bcrypt.hashpw(str(random.random()).encode('utf8'), rand_salt)

    randplus_stored_hash = bcrypt.hashpw(str(random.random()), rand_salt)
    randplus_stored_hash = bcrypt.hashpw(str(random.random()).encode('utf8'), rand_salt)
    randplus_hashed_pass = bcrypt.hashpw(hashed_pass, rand_salt)

    randplus_stored_hash == randplus_hashed_pass

M mediagoblin/plugins/ldap/views.py => mediagoblin/plugins/ldap/views.py +1 -1
@@ 16,7 16,7 @@

from mediagoblin import mg_globals, messages
from mediagoblin.auth.tools import register_user
from mediagoblin.db.models import User, LocalUser
from mediagoblin.db.models import LocalUser
from mediagoblin.decorators import allow_registration, auth_enabled
from mediagoblin.plugins.ldap import forms
from mediagoblin.plugins.ldap.tools import LDAP

M mediagoblin/plugins/openid/__init__.py => mediagoblin/plugins/openid/__init__.py +1 -1
@@ 13,8 13,8 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import uuid

from sqlalchemy import or_


M mediagoblin/plugins/piwigo/views.py => mediagoblin/plugins/piwigo/views.py +1 -2
@@ 24,10 24,9 @@ from mediagoblin.tools.translate import pass_to_ugettext as _
from mediagoblin.meddleware.csrf import csrf_exempt
from mediagoblin.auth.tools import check_login_simple
from mediagoblin.submit.lib import \
    submit_media, check_file_field, get_upload_file_limits, \
    submit_media, check_file_field, \
    FileUploadLimit, UserUploadLimit, UserPastUploadLimit


from mediagoblin.user_pages.lib import add_media_to_collection
from mediagoblin.db.models import Collection


M mediagoblin/plugins/subtitles/models.py => mediagoblin/plugins/subtitles/models.py +3 -2
@@ 13,11 13,12 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from sqlalchemy import Column, Integer, Unicode, ForeignKey
from sqlalchemy.orm import relationship

from mediagoblin.db.models import User
from mediagoblin.db.base import Base,MediaEntry
from mediagoblin.db.base import Base, MediaEntry


class MediaSubtitleFile(Base):
    __tablename__ = "core__subtitle_files"

M mediagoblin/plugins/subtitles/views.py => mediagoblin/plugins/subtitles/views.py +3 -7
@@ 16,24 16,20 @@

from datetime import datetime

from itsdangerous import BadSignature
from werkzeug.exceptions import Forbidden
from werkzeug.utils import secure_filename

from mediagoblin import messages
from mediagoblin import mg_globals

from mediagoblin.plugins.subtitles import forms
from mediagoblin.decorators import (require_active_login, active_user_from_url,
from mediagoblin.decorators import (require_active_login,
                            get_media_entry_by_id, user_may_delete_media)
from mediagoblin.tools.metadata import (compact_and_validate, DEFAULT_CHECKER,
                                        DEFAULT_SCHEMA)
from mediagoblin.tools.response import (render_to_response,
                                        redirect, redirect_obj, render_404)
                                        redirect)

import mimetypes

from mediagoblin.plugins.subtitles.tools import open_subtitle,save_subtitle
from mediagoblin.plugins.subtitles.tools import open_subtitle, save_subtitle

UNSAFE_MIMETYPES = [
        'text/html',

M mediagoblin/submit/views.py => mediagoblin/submit/views.py +1 -1
@@ 109,7 109,7 @@ def submit_start(request):
                                user=request.user.username)
            except FileTypeNotSupported as e:
                submit_form.file.errors.append(e)
            except Exception as e:
            except Exception:
                raise

    return render_to_response(

M mediagoblin/tests/test_processing.py => mediagoblin/tests/test_processing.py +0 -2
@@ 1,5 1,3 @@
#!/usr/bin/env python

from mediagoblin import processing

class TestProcessing:

M mediagoblin/tools/pluginapi.py => mediagoblin/tools/pluginapi.py +0 -2
@@ 58,8 58,6 @@ Lifecycle

import logging

from functools import wraps

from mediagoblin import mg_globals



M mediagoblin/user_pages/views.py => mediagoblin/user_pages/views.py +7 -8
@@ 19,9 19,8 @@ import datetime
import json

from mediagoblin import messages, mg_globals
from mediagoblin.db.models import (MediaEntry, MediaTag, Collection, Comment,
                                   CollectionItem, LocalUser, Activity, \
                                   GenericModelReference)
from mediagoblin.db.models import (MediaEntry, MediaTag, Collection,
                                   CollectionItem, LocalUser, Activity)
from mediagoblin.plugins.api.tools import get_media_file_paths
from mediagoblin.tools.response import render_to_response, render_404, \
    redirect, redirect_obj


@@ 31,8 30,8 @@ from mediagoblin.tools.pagination import Pagination
from mediagoblin.tools.federation import create_activity
from mediagoblin.tools.feeds import AtomFeedWithLinks
from mediagoblin.user_pages import forms as user_forms
from mediagoblin.user_pages.lib import (send_comment_email,
	add_media_to_collection, build_report_object)
from mediagoblin.user_pages.lib import (
    add_media_to_collection, build_report_object)
from mediagoblin.notifications import trigger_notification, \
    add_comment_subscription, mark_comment_notification_seen
from mediagoblin.tools.pluginapi import hook_transform


@@ 50,6 49,7 @@ from werkzeug.wrappers import Response
_log = logging.getLogger(__name__)
_log.setLevel(logging.DEBUG)


@user_not_banned
@uses_pagination
def user_home(request, page):


@@ 64,7 64,7 @@ def user_home(request, page):
            {'user': user})

    cursor = MediaEntry.query.\
        filter_by(actor = user.id).order_by(MediaEntry.created.desc())
        filter_by(actor=user.id).order_by(MediaEntry.created.desc())

    pagination = Pagination(page, cursor)
    media_entries = pagination()


@@ 438,7 438,6 @@ def collection_item_confirm_remove(request, collection_item):
    form = user_forms.ConfirmCollectionItemRemoveForm(request.form)

    if request.method == 'POST' and form.validate():
        username = collection_item.in_collection.get_actor.username
        collection = collection_item.in_collection

        if form.confirm.data is True:


@@ 639,7 638,7 @@ def collection_atom_feed(request):
                'rel': 'hub',
                'href': push_url})

    feed = AtomFeed(
    feed = AtomFeedWithLinks(
                "MediaGoblin: Feed for %s's collection %s" %
                (request.matchdict['user'], collection.title),
                feed_url=request.url,

M runtests.sh => runtests.sh +2 -2
@@ 64,8 64,8 @@ if [ "$need_arg" = 1 ]
then
  testdir="$basedir/mediagoblin/tests"
  set -x
  exec "$PYTEST" "$@" "$testdir" --boxed
  exec "$PYTEST" "$@" "$testdir" --forked
else
  set -x
  exec "$PYTEST" "$@" --boxed
  exec "$PYTEST" "$@" --forked
fi

M setup.cfg => setup.cfg +17 -9
@@ 36,7 36,8 @@ classifiers=[

[options]
packages = find:
python_requires = >=3.6
# We now use f-strings internally and allow Python requirements do too.
python_requires = <3.10
zip_safe = False
include_package_data = True
install_requires =


@@ 44,18 45,18 @@ install_requires =
    Babel>=1.3
    celery>=3.0,<4.3.0  # Removed the "sqlite" transport alias in 4.3.0
                        # making tests fail.
    certifi>=2017.4.17  # Required by requests on Fedora 33 (bin/gmg fails)
    certifi>=2017.4.17  # Required by requests on Fedora 33 (bin/gmg fails).
    ConfigObj
    email-validator
    ExifRead>=2.0.0
    feedgenerator
    itsdangerous
    jinja2<3.0.0  # 3.0.0 uses f-strings (Python >= 3.7) breaking Debian 9.
    jinja2<3.1.0  # 3.1.0 removes deprecated autoescape https://github.com/mattrobenolt/jinja2-cli/issues/101.
    jsonschema
    Markdown
    oauthlib
    PasteScript
    py-bcrypt
    bcrypt
    PyLD<2.0.0  # Breaks a Python 3 test if >= 2.0.0.
    python-dateutil
    pytz


@@ 68,6 69,17 @@ install_requires =
    werkzeug>=0.7,<2.0.0  # 2.0.0 breaks legacy API and submission tests.
    wtforms>2.1,<3.0  # Removed the "ext" module in 3.0.

    # Temporary fix for Ubuntu 20.04 until we are using pip.
    importlib-metadata>=4.4
    zipp>=3.1.0  # Minimum version of sub-dependency for importlib-metadata 6.0.0 on Ubuntu 20.4.

    # Temporary fixes for Debian 11.
    sphinxcontrib-qthelp
    sphinxcontrib-jsmath
    sphinxcontrib-htmlhelp
    sphinxcontrib-devhelp
    sphinxcontrib-applehelp

    # For now we're expecting that users will install this from
    # their package managers.
    # 'lxml',


@@ 77,6 89,7 @@ install_requires =
test =
    pytest>=2.3.1
    pytest-xdist
    pytest-forked
    WebTest>=2.0.18

[options.entry_points]


@@ 92,8 105,3 @@ zc.buildout =
    make_user_dev_dirs = mediagoblin.buildout_recipes:MakeUserDevDirs
babel.extractors =
    jinja2 = jinja2.ext:babel_extract

[options.data_files]
# Running gmg dbupdate fails with missing env.py because env.py isn't
# being included in the Python package (no __init__.py).
mediagoblin = mediagoblin/db/migrations/env.py

M tox.ini => tox.ini +1 -1
@@ 7,7 7,7 @@ sitepackages = False
usedevelop = True
# for ExifRead 2.0.0
install_command = pip install --process-dependency-links --pre {opts} {packages}
commands = py.test ./mediagoblin/tests --boxed -k '{posargs}'
commands = py.test ./mediagoblin/tests --forked -k '{posargs}'
deps =
 lxml
 Pillow