Merge branch 'bugfix/share-mastodon' into 'develop'
authorlambda <lain@soykaf.club>
Tue, 2 Apr 2019 12:47:40 +0000 (12:47 +0000)
committerlambda <lain@soykaf.club>
Tue, 2 Apr 2019 12:47:40 +0000 (12:47 +0000)
[OStatus] adds status to pleroma instance if the url given is a status

See merge request pleroma/pleroma!1002

93 files changed:
.gitlab-ci.yml
AGPL-3 [moved from LICENSE with 100% similarity]
CC-BY-NC-ND-4.0 [new file with mode: 0644]
CC-BY-SA-4.0 [new file with mode: 0644]
COPYING [new file with mode: 0644]
README.md
config/config.exs
config/test.exs
docs/admin/backup.md [new file with mode: 0644]
docs/admin/updating.md [new file with mode: 0644]
docs/api/admin_api.md [moved from docs/Admin-API.md with 76% similarity]
docs/api/differences_in_mastoapi_responses.md [moved from docs/Differences-in-MastodonAPI-Responses.md with 100% similarity]
docs/api/pleroma_api.md [moved from docs/Pleroma-API.md with 100% similarity]
docs/clients.md [moved from docs/Clients.md with 100% similarity]
docs/config.md
docs/config/General-tips-for-customizing-Pleroma-FE.md [new file with mode: 0644]
docs/config/custom_emoji.md [moved from docs/Custom-Emoji.md with 97% similarity]
docs/config/hardening.md [new file with mode: 0644]
docs/config/howto_mediaproxy.md [new file with mode: 0644]
docs/config/howto_proxy.md [new file with mode: 0644]
docs/config/howto_user_recomendation.md [new file with mode: 0644]
docs/config/i2p.md [new file with mode: 0644]
docs/config/mrf.md [moved from docs/Message-Rewrite-Facility-configuration.md with 98% similarity]
docs/config/onion_federation.md [new file with mode: 0644]
docs/config/small_customizations.md [new file with mode: 0644]
docs/config/static_dir.md [moved from docs/static_dir.md with 100% similarity]
docs/installation/alpine_linux_en.md [new file with mode: 0644]
docs/installation/arch_linux_en.md [new file with mode: 0644]
docs/installation/centos7_en.md [new file with mode: 0644]
docs/installation/debian_based_en.md [new file with mode: 0644]
docs/installation/debian_based_jp.md [new file with mode: 0644]
docs/installation/netbsd_en.md [new file with mode: 0644]
docs/installation/openbsd_en.md [new file with mode: 0644]
docs/installation/openbsd_fi.md [new file with mode: 0644]
docs/introduction.md [new file with mode: 0644]
lib/mix/tasks/pleroma/user.ex
lib/pleroma/PasswordResetToken.ex
lib/pleroma/application.ex
lib/pleroma/emails/mailer.ex
lib/pleroma/flake_id.ex
lib/pleroma/gopher/server.ex
lib/pleroma/jobs.ex [deleted file]
lib/pleroma/list.ex
lib/pleroma/plugs/user_fetcher_plug.ex
lib/pleroma/user.ex
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/activity_pub/views/user_view.ex
lib/pleroma/web/admin_api/admin_api_controller.ex
lib/pleroma/web/admin_api/search.ex [new file with mode: 0644]
lib/pleroma/web/channels/user_socket.ex
lib/pleroma/web/common_api/utils.ex
lib/pleroma/web/controller_helper.ex
lib/pleroma/web/federator/federator.ex
lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
lib/pleroma/web/mastodon_api/views/app_view.ex [new file with mode: 0644]
lib/pleroma/web/mastodon_api/websocket_handler.ex
lib/pleroma/web/oauth/oauth_controller.ex
lib/pleroma/web/oauth/token.ex
lib/pleroma/web/router.ex
lib/pleroma/web/streamer.ex
lib/pleroma/web/twitter_api/controllers/util_controller.ex
lib/pleroma/web/twitter_api/twitter_api.ex
lib/pleroma/web/twitter_api/twitter_api_controller.ex
mix.exs
mix.lock
priv/repo/migrations/20190325215156_update_status_reply_count.exs [deleted file]
priv/static/images/pleroma-fox-tan-smol.png [new file with mode: 0644]
priv/static/images/pleroma-fox-tan.png [new file with mode: 0644]
priv/static/images/pleroma-tan.png [new file with mode: 0644]
test/jobs_test.exs [deleted file]
test/support/factory.ex
test/support/jobs_worker_mock.ex [deleted file]
test/tasks/user_test.exs
test/user_test.exs
test/web/activity_pub/activity_pub_controller_test.exs
test/web/activity_pub/activity_pub_test.exs
test/web/activity_pub/transmogrifier_test.exs
test/web/activity_pub/views/user_view_test.exs
test/web/admin_api/admin_api_controller_test.exs
test/web/admin_api/search_test.exs [new file with mode: 0644]
test/web/mastodon_api/mastodon_api_controller_test.exs
test/web/mastodon_api/notification_view_test.exs
test/web/mastodon_api/status_view_test.exs
test/web/oauth/oauth_controller_test.exs
test/web/ostatus/activity_representer_test.exs
test/web/ostatus/incoming_documents/delete_handling_test.exs
test/web/ostatus/ostatus_test.exs
test/web/salmon/salmon_test.exs
test/web/twitter_api/twitter_api_controller_test.exs
test/web/twitter_api/twitter_api_test.exs
test/web/twitter_api/views/activity_view_test.exs
test/web/twitter_api/views/user_view_test.exs

index d5f2a762a418dcac45d710c1e89f8f2f46b0b15a..c07f1a5d34f9028945a997fe65ffbc776eb40491 100644 (file)
@@ -1,9 +1,5 @@
 image: elixir:1.8.1
 
-services:
-  - name: postgres:9.6.2
-    command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
-
 variables:
   POSTGRES_DB: pleroma_test
   POSTGRES_USER: postgres
@@ -17,29 +13,68 @@ cache:
           - deps
           - _build
 stages:
-  - lint
+  - build
   - test
-  - analysis
+  - deploy
 
 before_script:
   - mix local.hex --force
   - mix local.rebar --force
+
+build:
+  stage: build
+  script:
   - mix deps.get
   - mix compile --force
-  - mix ecto.create
-  - mix ecto.migrate
 
-lint:
-  stage: lint
+docs-build:
+  stage: build
+  only:
+  - master@pleroma/pleroma
+  - develop@pleroma/pleroma
+  variables:
+    MIX_ENV: dev
   script:
-    - mix format --check-formatted
+    - mix deps.get
+    - mix compile
+    - mix docs
+  artifacts:
+    paths:
+      - priv/static/doc
 
 unit-testing:
   stage: test
+  services:
+  - name: postgres:9.6.2
+    command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
   script:
+    - mix ecto.create
+    - mix ecto.migrate
     - mix test --trace --preload-modules
 
+lint:
+  stage: test
+  script:
+    - mix format --check-formatted
+
 analysis:
-  stage: analysis
+  stage: test
   script:
+    - mix deps.get
     - mix credo --strict --only=warnings,todo,fixme,consistency,readability
+
+
+docs-deploy:
+  stage: deploy
+  image: alpine:3.9
+  only:
+  - master@pleroma/pleroma
+  - develop@pleroma/pleroma
+  before_script:
+    - apk update && apk add openssh-client rsync
+  script:
+    - mkdir -p ~/.ssh
+    - echo "${SSH_HOST_KEY}" > ~/.ssh/known_hosts
+    - eval $(ssh-agent -s)
+    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
+    - rsync -hrvz --delete -e "ssh -p ${SSH_PORT}" priv/static/doc/ "${SSH_USER_HOST_LOCATION}/${CI_COMMIT_REF_NAME}" 
diff --git a/LICENSE b/AGPL-3
similarity index 100%
rename from LICENSE
rename to AGPL-3
diff --git a/CC-BY-NC-ND-4.0 b/CC-BY-NC-ND-4.0
new file mode 100644 (file)
index 0000000..4865442
--- /dev/null
@@ -0,0 +1,403 @@
+Attribution-NonCommercial-NoDerivatives 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+     Considerations for licensors: Our public licenses are
+     intended for use by those authorized to give the public
+     permission to use material in ways otherwise restricted by
+     copyright and certain other rights. Our licenses are
+     irrevocable. Licensors should read and understand the terms
+     and conditions of the license they choose before applying it.
+     Licensors should also secure all rights necessary before
+     applying our licenses so that the public can reuse the
+     material as expected. Licensors should clearly mark any
+     material not subject to the license. This includes other CC-
+     licensed material, or material used under an exception or
+     limitation to copyright. More considerations for licensors:
+       wiki.creativecommons.org/Considerations_for_licensors
+
+     Considerations for the public: By using one of our public
+     licenses, a licensor grants the public permission to use the
+     licensed material under specified terms and conditions. If
+     the licensor's permission is not necessary for any reason--for
+     example, because of any applicable exception or limitation to
+     copyright--then that use is not regulated by the license. Our
+     licenses grant only permissions under copyright and certain
+     other rights that a licensor has authority to grant. Use of
+     the licensed material may still be restricted for other
+     reasons, including because others have copyright or other
+     rights in the material. A licensor may make special requests,
+     such as asking that all changes be marked or described.
+     Although not required by our licenses, you are encouraged to
+     respect those requests where reasonable. More considerations
+     for the public: 
+       wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-NonCommercial-NoDerivatives 4.0
+International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-NonCommercial-NoDerivatives 4.0 International Public
+License ("Public License"). To the extent this Public License may be
+interpreted as a contract, You are granted the Licensed Rights in
+consideration of Your acceptance of these terms and conditions, and the
+Licensor grants You such rights in consideration of benefits the
+Licensor receives from making the Licensed Material available under
+these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+  a. Adapted Material means material subject to Copyright and Similar
+     Rights that is derived from or based upon the Licensed Material
+     and in which the Licensed Material is translated, altered,
+     arranged, transformed, or otherwise modified in a manner requiring
+     permission under the Copyright and Similar Rights held by the
+     Licensor. For purposes of this Public License, where the Licensed
+     Material is a musical work, performance, or sound recording,
+     Adapted Material is always produced where the Licensed Material is
+     synched in timed relation with a moving image.
+
+  b. Copyright and Similar Rights means copyright and/or similar rights
+     closely related to copyright including, without limitation,
+     performance, broadcast, sound recording, and Sui Generis Database
+     Rights, without regard to how the rights are labeled or
+     categorized. For purposes of this Public License, the rights
+     specified in Section 2(b)(1)-(2) are not Copyright and Similar
+     Rights.
+
+  c. Effective Technological Measures means those measures that, in the
+     absence of proper authority, may not be circumvented under laws
+     fulfilling obligations under Article 11 of the WIPO Copyright
+     Treaty adopted on December 20, 1996, and/or similar international
+     agreements.
+
+  d. Exceptions and Limitations means fair use, fair dealing, and/or
+     any other exception or limitation to Copyright and Similar Rights
+     that applies to Your use of the Licensed Material.
+
+  e. Licensed Material means the artistic or literary work, database,
+     or other material to which the Licensor applied this Public
+     License.
+
+  f. Licensed Rights means the rights granted to You subject to the
+     terms and conditions of this Public License, which are limited to
+     all Copyright and Similar Rights that apply to Your use of the
+     Licensed Material and that the Licensor has authority to license.
+
+  g. Licensor means the individual(s) or entity(ies) granting rights
+     under this Public License.
+
+  h. NonCommercial means not primarily intended for or directed towards
+     commercial advantage or monetary compensation. For purposes of
+     this Public License, the exchange of the Licensed Material for
+     other material subject to Copyright and Similar Rights by digital
+     file-sharing or similar means is NonCommercial provided there is
+     no payment of monetary compensation in connection with the
+     exchange.
+
+  i. Share means to provide material to the public by any means or
+     process that requires permission under the Licensed Rights, such
+     as reproduction, public display, public performance, distribution,
+     dissemination, communication, or importation, and to make material
+     available to the public including in ways that members of the
+     public may access the material from a place and at a time
+     individually chosen by them.
+
+  j. Sui Generis Database Rights means rights other than copyright
+     resulting from Directive 96/9/EC of the European Parliament and of
+     the Council of 11 March 1996 on the legal protection of databases,
+     as amended and/or succeeded, as well as other essentially
+     equivalent rights anywhere in the world.
+
+  k. You means the individual or entity exercising the Licensed Rights
+     under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+  a. License grant.
+
+       1. Subject to the terms and conditions of this Public License,
+          the Licensor hereby grants You a worldwide, royalty-free,
+          non-sublicensable, non-exclusive, irrevocable license to
+          exercise the Licensed Rights in the Licensed Material to:
+
+            a. reproduce and Share the Licensed Material, in whole or
+               in part, for NonCommercial purposes only; and
+
+            b. produce and reproduce, but not Share, Adapted Material
+               for NonCommercial purposes only.
+
+       2. Exceptions and Limitations. For the avoidance of doubt, where
+          Exceptions and Limitations apply to Your use, this Public
+          License does not apply, and You do not need to comply with
+          its terms and conditions.
+
+       3. Term. The term of this Public License is specified in Section
+          6(a).
+
+       4. Media and formats; technical modifications allowed. The
+          Licensor authorizes You to exercise the Licensed Rights in
+          all media and formats whether now known or hereafter created,
+          and to make technical modifications necessary to do so. The
+          Licensor waives and/or agrees not to assert any right or
+          authority to forbid You from making technical modifications
+          necessary to exercise the Licensed Rights, including
+          technical modifications necessary to circumvent Effective
+          Technological Measures. For purposes of this Public License,
+          simply making modifications authorized by this Section 2(a)
+          (4) never produces Adapted Material.
+
+       5. Downstream recipients.
+
+            a. Offer from the Licensor -- Licensed Material. Every
+               recipient of the Licensed Material automatically
+               receives an offer from the Licensor to exercise the
+               Licensed Rights under the terms and conditions of this
+               Public License.
+
+            b. No downstream restrictions. You may not offer or impose
+               any additional or different terms or conditions on, or
+               apply any Effective Technological Measures to, the
+               Licensed Material if doing so restricts exercise of the
+               Licensed Rights by any recipient of the Licensed
+               Material.
+
+       6. No endorsement. Nothing in this Public License constitutes or
+          may be construed as permission to assert or imply that You
+          are, or that Your use of the Licensed Material is, connected
+          with, or sponsored, endorsed, or granted official status by,
+          the Licensor or others designated to receive attribution as
+          provided in Section 3(a)(1)(A)(i).
+
+  b. Other rights.
+
+       1. Moral rights, such as the right of integrity, are not
+          licensed under this Public License, nor are publicity,
+          privacy, and/or other similar personality rights; however, to
+          the extent possible, the Licensor waives and/or agrees not to
+          assert any such rights held by the Licensor to the limited
+          extent necessary to allow You to exercise the Licensed
+          Rights, but not otherwise.
+
+       2. Patent and trademark rights are not licensed under this
+          Public License.
+
+       3. To the extent possible, the Licensor waives any right to
+          collect royalties from You for the exercise of the Licensed
+          Rights, whether directly or through a collecting society
+          under any voluntary or waivable statutory or compulsory
+          licensing scheme. In all other cases the Licensor expressly
+          reserves any right to collect such royalties, including when
+          the Licensed Material is used other than for NonCommercial
+          purposes.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+  a. Attribution.
+
+       1. If You Share the Licensed Material, You must:
+
+            a. retain the following if it is supplied by the Licensor
+               with the Licensed Material:
+
+                 i. identification of the creator(s) of the Licensed
+                    Material and any others designated to receive
+                    attribution, in any reasonable manner requested by
+                    the Licensor (including by pseudonym if
+                    designated);
+
+                ii. a copyright notice;
+
+               iii. a notice that refers to this Public License;
+
+                iv. a notice that refers to the disclaimer of
+                    warranties;
+
+                 v. a URI or hyperlink to the Licensed Material to the
+                    extent reasonably practicable;
+
+            b. indicate if You modified the Licensed Material and
+               retain an indication of any previous modifications; and
+
+            c. indicate the Licensed Material is licensed under this
+               Public License, and include the text of, or the URI or
+               hyperlink to, this Public License.
+
+          For the avoidance of doubt, You do not have permission under
+          this Public License to Share Adapted Material.
+
+       2. You may satisfy the conditions in Section 3(a)(1) in any
+          reasonable manner based on the medium, means, and context in
+          which You Share the Licensed Material. For example, it may be
+          reasonable to satisfy the conditions by providing a URI or
+          hyperlink to a resource that includes the required
+          information.
+
+       3. If requested by the Licensor, You must remove any of the
+          information required by Section 3(a)(1)(A) to the extent
+          reasonably practicable.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+     to extract, reuse, reproduce, and Share all or a substantial
+     portion of the contents of the database for NonCommercial purposes
+     only and provided You do not Share Adapted Material;
+
+  b. if You include all or a substantial portion of the database
+     contents in a database in which You have Sui Generis Database
+     Rights, then the database in which You have Sui Generis Database
+     Rights (but not its individual contents) is Adapted Material; and
+
+  c. You must comply with the conditions in Section 3(a) if You Share
+     all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+  c. The disclaimer of warranties and limitation of liability provided
+     above shall be interpreted in a manner that, to the extent
+     possible, most closely approximates an absolute disclaimer and
+     waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+  a. This Public License applies for the term of the Copyright and
+     Similar Rights licensed here. However, if You fail to comply with
+     this Public License, then Your rights under this Public License
+     terminate automatically.
+
+  b. Where Your right to use the Licensed Material has terminated under
+     Section 6(a), it reinstates:
+
+       1. automatically as of the date the violation is cured, provided
+          it is cured within 30 days of Your discovery of the
+          violation; or
+
+       2. upon express reinstatement by the Licensor.
+
+     For the avoidance of doubt, this Section 6(b) does not affect any
+     right the Licensor may have to seek remedies for Your violations
+     of this Public License.
+
+  c. For the avoidance of doubt, the Licensor may also offer the
+     Licensed Material under separate terms or conditions or stop
+     distributing the Licensed Material at any time; however, doing so
+     will not terminate this Public License.
+
+  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+     License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+  a. The Licensor shall not be bound by any additional or different
+     terms or conditions communicated by You unless expressly agreed.
+
+  b. Any arrangements, understandings, or agreements regarding the
+     Licensed Material not stated herein are separate from and
+     independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+  a. For the avoidance of doubt, this Public License does not, and
+     shall not be interpreted to, reduce, limit, restrict, or impose
+     conditions on any use of the Licensed Material that could lawfully
+     be made without permission under this Public License.
+
+  b. To the extent possible, if any provision of this Public License is
+     deemed unenforceable, it shall be automatically reformed to the
+     minimum extent necessary to make it enforceable. If the provision
+     cannot be reformed, it shall be severed from this Public License
+     without affecting the enforceability of the remaining terms and
+     conditions.
+
+  c. No term or condition of this Public License will be waived and no
+     failure to comply consented to unless expressly agreed to by the
+     Licensor.
+
+  d. Nothing in this Public License constitutes or may be interpreted
+     as a limitation upon, or waiver of, any privileges and immunities
+     that apply to the Licensor or You, including from the legal
+     processes of any jurisdiction or authority.
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the “Licensor.” The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
+
diff --git a/CC-BY-SA-4.0 b/CC-BY-SA-4.0
new file mode 100644 (file)
index 0000000..4681ab8
--- /dev/null
@@ -0,0 +1,427 @@
+Attribution-ShareAlike 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+     Considerations for licensors: Our public licenses are
+     intended for use by those authorized to give the public
+     permission to use material in ways otherwise restricted by
+     copyright and certain other rights. Our licenses are
+     irrevocable. Licensors should read and understand the terms
+     and conditions of the license they choose before applying it.
+     Licensors should also secure all rights necessary before
+     applying our licenses so that the public can reuse the
+     material as expected. Licensors should clearly mark any
+     material not subject to the license. This includes other CC-
+     licensed material, or material used under an exception or
+     limitation to copyright. More considerations for licensors:
+       wiki.creativecommons.org/Considerations_for_licensors
+
+     Considerations for the public: By using one of our public
+     licenses, a licensor grants the public permission to use the
+     licensed material under specified terms and conditions. If
+     the licensor's permission is not necessary for any reason--for
+     example, because of any applicable exception or limitation to
+     copyright--then that use is not regulated by the license. Our
+     licenses grant only permissions under copyright and certain
+     other rights that a licensor has authority to grant. Use of
+     the licensed material may still be restricted for other
+     reasons, including because others have copyright or other
+     rights in the material. A licensor may make special requests,
+     such as asking that all changes be marked or described.
+     Although not required by our licenses, you are encouraged to
+     respect those requests where reasonable. More considerations
+     for the public:
+       wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution-ShareAlike 4.0 International Public
+License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution-ShareAlike 4.0 International Public License ("Public
+License"). To the extent this Public License may be interpreted as a
+contract, You are granted the Licensed Rights in consideration of Your
+acceptance of these terms and conditions, and the Licensor grants You
+such rights in consideration of benefits the Licensor receives from
+making the Licensed Material available under these terms and
+conditions.
+
+
+Section 1 -- Definitions.
+
+  a. Adapted Material means material subject to Copyright and Similar
+     Rights that is derived from or based upon the Licensed Material
+     and in which the Licensed Material is translated, altered,
+     arranged, transformed, or otherwise modified in a manner requiring
+     permission under the Copyright and Similar Rights held by the
+     Licensor. For purposes of this Public License, where the Licensed
+     Material is a musical work, performance, or sound recording,
+     Adapted Material is always produced where the Licensed Material is
+     synched in timed relation with a moving image.
+
+  b. Adapter's License means the license You apply to Your Copyright
+     and Similar Rights in Your contributions to Adapted Material in
+     accordance with the terms and conditions of this Public License.
+
+  c. BY-SA Compatible License means a license listed at
+     creativecommons.org/compatiblelicenses, approved by Creative
+     Commons as essentially the equivalent of this Public License.
+
+  d. Copyright and Similar Rights means copyright and/or similar rights
+     closely related to copyright including, without limitation,
+     performance, broadcast, sound recording, and Sui Generis Database
+     Rights, without regard to how the rights are labeled or
+     categorized. For purposes of this Public License, the rights
+     specified in Section 2(b)(1)-(2) are not Copyright and Similar
+     Rights.
+
+  e. Effective Technological Measures means those measures that, in the
+     absence of proper authority, may not be circumvented under laws
+     fulfilling obligations under Article 11 of the WIPO Copyright
+     Treaty adopted on December 20, 1996, and/or similar international
+     agreements.
+
+  f. Exceptions and Limitations means fair use, fair dealing, and/or
+     any other exception or limitation to Copyright and Similar Rights
+     that applies to Your use of the Licensed Material.
+
+  g. License Elements means the license attributes listed in the name
+     of a Creative Commons Public License. The License Elements of this
+     Public License are Attribution and ShareAlike.
+
+  h. Licensed Material means the artistic or literary work, database,
+     or other material to which the Licensor applied this Public
+     License.
+
+  i. Licensed Rights means the rights granted to You subject to the
+     terms and conditions of this Public License, which are limited to
+     all Copyright and Similar Rights that apply to Your use of the
+     Licensed Material and that the Licensor has authority to license.
+
+  j. Licensor means the individual(s) or entity(ies) granting rights
+     under this Public License.
+
+  k. Share means to provide material to the public by any means or
+     process that requires permission under the Licensed Rights, such
+     as reproduction, public display, public performance, distribution,
+     dissemination, communication, or importation, and to make material
+     available to the public including in ways that members of the
+     public may access the material from a place and at a time
+     individually chosen by them.
+
+  l. Sui Generis Database Rights means rights other than copyright
+     resulting from Directive 96/9/EC of the European Parliament and of
+     the Council of 11 March 1996 on the legal protection of databases,
+     as amended and/or succeeded, as well as other essentially
+     equivalent rights anywhere in the world.
+
+  m. You means the individual or entity exercising the Licensed Rights
+     under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+  a. License grant.
+
+       1. Subject to the terms and conditions of this Public License,
+          the Licensor hereby grants You a worldwide, royalty-free,
+          non-sublicensable, non-exclusive, irrevocable license to
+          exercise the Licensed Rights in the Licensed Material to:
+
+            a. reproduce and Share the Licensed Material, in whole or
+               in part; and
+
+            b. produce, reproduce, and Share Adapted Material.
+
+       2. Exceptions and Limitations. For the avoidance of doubt, where
+          Exceptions and Limitations apply to Your use, this Public
+          License does not apply, and You do not need to comply with
+          its terms and conditions.
+
+       3. Term. The term of this Public License is specified in Section
+          6(a).
+
+       4. Media and formats; technical modifications allowed. The
+          Licensor authorizes You to exercise the Licensed Rights in
+          all media and formats whether now known or hereafter created,
+          and to make technical modifications necessary to do so. The
+          Licensor waives and/or agrees not to assert any right or
+          authority to forbid You from making technical modifications
+          necessary to exercise the Licensed Rights, including
+          technical modifications necessary to circumvent Effective
+          Technological Measures. For purposes of this Public License,
+          simply making modifications authorized by this Section 2(a)
+          (4) never produces Adapted Material.
+
+       5. Downstream recipients.
+
+            a. Offer from the Licensor -- Licensed Material. Every
+               recipient of the Licensed Material automatically
+               receives an offer from the Licensor to exercise the
+               Licensed Rights under the terms and conditions of this
+               Public License.
+
+            b. Additional offer from the Licensor -- Adapted Material.
+               Every recipient of Adapted Material from You
+               automatically receives an offer from the Licensor to
+               exercise the Licensed Rights in the Adapted Material
+               under the conditions of the Adapter's License You apply.
+
+            c. No downstream restrictions. You may not offer or impose
+               any additional or different terms or conditions on, or
+               apply any Effective Technological Measures to, the
+               Licensed Material if doing so restricts exercise of the
+               Licensed Rights by any recipient of the Licensed
+               Material.
+
+       6. No endorsement. Nothing in this Public License constitutes or
+          may be construed as permission to assert or imply that You
+          are, or that Your use of the Licensed Material is, connected
+          with, or sponsored, endorsed, or granted official status by,
+          the Licensor or others designated to receive attribution as
+          provided in Section 3(a)(1)(A)(i).
+
+  b. Other rights.
+
+       1. Moral rights, such as the right of integrity, are not
+          licensed under this Public License, nor are publicity,
+          privacy, and/or other similar personality rights; however, to
+          the extent possible, the Licensor waives and/or agrees not to
+          assert any such rights held by the Licensor to the limited
+          extent necessary to allow You to exercise the Licensed
+          Rights, but not otherwise.
+
+       2. Patent and trademark rights are not licensed under this
+          Public License.
+
+       3. To the extent possible, the Licensor waives any right to
+          collect royalties from You for the exercise of the Licensed
+          Rights, whether directly or through a collecting society
+          under any voluntary or waivable statutory or compulsory
+          licensing scheme. In all other cases the Licensor expressly
+          reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+  a. Attribution.
+
+       1. If You Share the Licensed Material (including in modified
+          form), You must:
+
+            a. retain the following if it is supplied by the Licensor
+               with the Licensed Material:
+
+                 i. identification of the creator(s) of the Licensed
+                    Material and any others designated to receive
+                    attribution, in any reasonable manner requested by
+                    the Licensor (including by pseudonym if
+                    designated);
+
+                ii. a copyright notice;
+
+               iii. a notice that refers to this Public License;
+
+                iv. a notice that refers to the disclaimer of
+                    warranties;
+
+                 v. a URI or hyperlink to the Licensed Material to the
+                    extent reasonably practicable;
+
+            b. indicate if You modified the Licensed Material and
+               retain an indication of any previous modifications; and
+
+            c. indicate the Licensed Material is licensed under this
+               Public License, and include the text of, or the URI or
+               hyperlink to, this Public License.
+
+       2. You may satisfy the conditions in Section 3(a)(1) in any
+          reasonable manner based on the medium, means, and context in
+          which You Share the Licensed Material. For example, it may be
+          reasonable to satisfy the conditions by providing a URI or
+          hyperlink to a resource that includes the required
+          information.
+
+       3. If requested by the Licensor, You must remove any of the
+          information required by Section 3(a)(1)(A) to the extent
+          reasonably practicable.
+
+  b. ShareAlike.
+
+     In addition to the conditions in Section 3(a), if You Share
+     Adapted Material You produce, the following conditions also apply.
+
+       1. The Adapter's License You apply must be a Creative Commons
+          license with the same License Elements, this version or
+          later, or a BY-SA Compatible License.
+
+       2. You must include the text of, or the URI or hyperlink to, the
+          Adapter's License You apply. You may satisfy this condition
+          in any reasonable manner based on the medium, means, and
+          context in which You Share Adapted Material.
+
+       3. You may not offer or impose any additional or different terms
+          or conditions on, or apply any Effective Technological
+          Measures to, Adapted Material that restrict exercise of the
+          rights granted under the Adapter's License You apply.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+     to extract, reuse, reproduce, and Share all or a substantial
+     portion of the contents of the database;
+
+  b. if You include all or a substantial portion of the database
+     contents in a database in which You have Sui Generis Database
+     Rights, then the database in which You have Sui Generis Database
+     Rights (but not its individual contents) is Adapted Material,
+     including for purposes of Section 3(b); and
+
+  c. You must comply with the conditions in Section 3(a) if You Share
+     all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+  c. The disclaimer of warranties and limitation of liability provided
+     above shall be interpreted in a manner that, to the extent
+     possible, most closely approximates an absolute disclaimer and
+     waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+  a. This Public License applies for the term of the Copyright and
+     Similar Rights licensed here. However, if You fail to comply with
+     this Public License, then Your rights under this Public License
+     terminate automatically.
+
+  b. Where Your right to use the Licensed Material has terminated under
+     Section 6(a), it reinstates:
+
+       1. automatically as of the date the violation is cured, provided
+          it is cured within 30 days of Your discovery of the
+          violation; or
+
+       2. upon express reinstatement by the Licensor.
+
+     For the avoidance of doubt, this Section 6(b) does not affect any
+     right the Licensor may have to seek remedies for Your violations
+     of this Public License.
+
+  c. For the avoidance of doubt, the Licensor may also offer the
+     Licensed Material under separate terms or conditions or stop
+     distributing the Licensed Material at any time; however, doing so
+     will not terminate this Public License.
+
+  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+     License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+  a. The Licensor shall not be bound by any additional or different
+     terms or conditions communicated by You unless expressly agreed.
+
+  b. Any arrangements, understandings, or agreements regarding the
+     Licensed Material not stated herein are separate from and
+     independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+  a. For the avoidance of doubt, this Public License does not, and
+     shall not be interpreted to, reduce, limit, restrict, or impose
+     conditions on any use of the Licensed Material that could lawfully
+     be made without permission under this Public License.
+
+  b. To the extent possible, if any provision of this Public License is
+     deemed unenforceable, it shall be automatically reformed to the
+     minimum extent necessary to make it enforceable. If the provision
+     cannot be reformed, it shall be severed from this Public License
+     without affecting the enforceability of the remaining terms and
+     conditions.
+
+  c. No term or condition of this Public License will be waived and no
+     failure to comply consented to unless expressly agreed to by the
+     Licensor.
+
+  d. Nothing in this Public License constitutes or may be interpreted
+     as a limitation upon, or waiver of, any privileges and immunities
+     that apply to the Licensor or You, including from the legal
+     processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the “Licensor.” The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..ceec519
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,48 @@
+Unless otherwise stated this repository is copyright © 2017-2019
+Pleroma Authors <https://pleroma.social/>, and is distributed under
+The GNU Affero General Public License Version 3, you should have received a
+copy of the license file as AGPL-3.
+
+---
+
+The following files are copyright © 2019 shitposter.club, and are distributed
+under the Creative Commons Attribution-ShareAlike 4.0 International license,
+you should have received a copy of the license file as CC-BY-SA-4.0.
+
+priv/static/images/pleroma-fox-tan.png
+priv/static/images/pleroma-fox-tan-smol.png
+priv/static/images/pleroma-tan.png
+
+---
+
+The following files are copyright © 2017-2019 Pleroma Authors
+<https://pleroma.social/>, and are distributed under the Creative Commons
+Attribution-ShareAlike 4.0 International license, you should have received
+a copy of the license file as CC-BY-SA-4.0.
+
+priv/static/images/avi.png
+priv/static/images/banner.png
+priv/static/instance/thumbnail.jpeg
+
+---
+
+All photos published on Unsplash can be used for free. You can use them for
+commercial and noncommercial purposes. You do not need to ask permission from
+or provide credit to the photographer or Unsplash, although it is appreciated
+when possible.
+
+More precisely, Unsplash grants you an irrevocable, nonexclusive, worldwide
+copyright license to download, copy, modify, distribute, perform, and use
+photos from Unsplash for free, including for commercial purposes, without
+permission from or attributing the photographer or Unsplash. This license
+does not include the right to compile photos from Unsplash to replicate
+a similar or competing service.
+
+priv/static/images/city.jpg
+
+---
+
+The files present under the priv/static/finmoji directory are copyright
+Finland <https://finland.fi/emoji/>, and are distributed under the Creative
+Commons Attribution-NonCommercial-NoDerivatives 4.0 International license, you
+should have received a copy of the license file as CC-BY-NC-ND-4.0.
index 4f22445d0121555fc81ddfa22d5e83110a4628fe..c45190fc301b10979fb4ba2d1232c106980b7af0 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,14 +1,16 @@
 # Pleroma
 
+**Note**: This readme as well as complete documentation is also availible at <https://docs-develop.pleroma.social>
+
 ## About Pleroma
 
 Pleroma is a microblogging server software that can federate (= exchange messages with) other servers that support the same federation standards (OStatus and ActivityPub). What that means is that you can host a server for yourself or your friends and stay in control of your online identity, but still exchange messages with people on larger servers. Pleroma will federate with all servers that implement either OStatus or ActivityPub, like Friendica, GNU Social, Hubzilla, Mastodon, Misskey, Peertube, and Pixelfed.
 
 Pleroma is written in Elixir, high-performance and can run on small devices like a Raspberry Pi.
 
-For clients it supports both the [GNU Social API with Qvitter extensions](https://twitter-api.readthedocs.io/en/latest/index.html) and the [Mastodon client API](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md).
+For clients it supports both the [GNU Social API with Qvitter extensions](https://twitter-api.readthedocs.io/en/latest/index.html) and the [Mastodon client API](https://docs.joinmastodon.org/api/guidelines/).
 
-- [Client Applications for Pleroma](docs/Clients.md)
+- [Client Applications for Pleroma](https://docs-develop.pleroma.social/clients.html)
 
 No release has been made yet, but several servers have been online for months already. If you want to run your own server, feel free to contact us at @lain@pleroma.soykaf.com or in our dev chat at #pleroma on freenode or via matrix at <https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org>.
 
@@ -28,7 +30,7 @@ While we don’t provide docker files, other people have written very good ones.
 
 * Run `mix deps.get` to install elixir dependencies.
 * Run `mix pleroma.instance gen`. This will ask you questions about your instance and generate a configuration file in `config/generated_config.exs`. Check that and copy it to either `config/dev.secret.exs` or `config/prod.secret.exs`. It will also create a `config/setup_db.psql`, which you should run as the PostgreSQL superuser (i.e., `sudo -u postgres psql -f config/setup_db.psql`). It will create the database, user, and password you gave `mix pleroma.gen.instance` earlier, as well as set up the necessary extensions in the database. PostgreSQL superuser privileges are only needed for this step.
-* For these next steps, the default will be to run pleroma using the dev configuration file, `config/dev.secret.exs`. To run them using the prod config file, prefix each command at the shell with `MIX_ENV=prod`. For example: `MIX_ENV=prod mix phx.server`. Documentation for the config can be found at [`docs/config.md`](docs/config.md)
+* For these next steps, the default will be to run pleroma using the dev configuration file, `config/dev.secret.exs`. To run them using the prod config file, prefix each command at the shell with `MIX_ENV=prod`. For example: `MIX_ENV=prod mix phx.server`. Documentation for the config can be found at [`docs/config.md`](docs/config.md) in the repository, or at the "Configuration" page on <https://docs-develop.pleroma.social/config.html>
 * Run `mix ecto.migrate` to run the database migrations. You will have to do this again after certain updates.
 * You can check if your instance is configured correctly by running it with `mix phx.server` and checking the instance info endpoint at `/api/v1/instance`. If it shows your uri, name and email correctly, you are configured correctly. If it shows something like `localhost:4000`, your configuration is probably wrong, unless you are running a local development setup.
 * The common and convenient way for adding HTTPS is by using Nginx as a reverse proxy. You can look at example Nginx configuration in `installation/pleroma.nginx`. If you need TLS/SSL certificates for HTTPS, you can look get some for free with letsencrypt: <https://letsencrypt.org/>. The simplest way to obtain and install a certificate is to use [Certbot.](https://certbot.eff.org) Depending on your specific setup, certbot may be able to get a certificate and configure your web server automatically.
@@ -66,7 +68,7 @@ This is useful for running Pleroma inside Tor or I2P.
 
 ## Customization and contribution
 
-The [Pleroma Wiki](https://git.pleroma.social/pleroma/pleroma/wikis/home) offers manuals and guides on how to further customize your instance to your liking and how you can contribute to the project.
+The [Pleroma Documentation](https://docs-develop.pleroma.social/readme.html) offers manuals and guides on how to further customize your instance to your liking and how you can contribute to the project.
 
 ## Troubleshooting
 
index bd8922b772355b5b0cf21ac651bd6486b1042d17..dccf7b2637c21d6fa7e7fb6b6c221e8b6f12039b 100644 (file)
@@ -348,10 +348,10 @@ config :pleroma, Pleroma.Web.Federator.RetryQueue,
   initial_timeout: 30,
   max_retries: 5
 
-config :pleroma, Pleroma.Jobs,
-  federator_incoming: [max_jobs: 50],
-  federator_outgoing: [max_jobs: 50],
-  mailer: [max_jobs: 10]
+config :pleroma_job_queue, :queues,
+  federator_incoming: 50,
+  federator_outgoing: 50,
+  mailer: 10
 
 config :pleroma, :fetch_initial_posts,
   enabled: false,
@@ -378,6 +378,8 @@ config :pleroma, :ldap,
   base: System.get_env("LDAP_BASE") || "dc=example,dc=com",
   uid: System.get_env("LDAP_UID") || "cn"
 
+config :pleroma, Pleroma.Mailer, adapter: Swoosh.Adapters.Sendmail
+
 # Import environment specific config. This must remain at the bottom
 # of this file so it overrides the configuration defined above.
 import_config "#{Mix.env()}.exs"
index 3691e5bd1070af80c04b8bcf260adf47074b9d57..6a7b9067eebcd0fa6e42a952adc44623fad8ffb4 100644 (file)
@@ -48,7 +48,7 @@ config :web_push_encryption, :vapid_details,
 
 config :web_push_encryption, :http_client, Pleroma.Web.WebPushHttpClientMock
 
-config :pleroma, Pleroma.Jobs, testing: [max_jobs: 2]
+config :pleroma_job_queue, disabled: true
 
 try do
   import_config "test.secret.exs"
diff --git a/docs/admin/backup.md b/docs/admin/backup.md
new file mode 100644 (file)
index 0000000..2c70e7b
--- /dev/null
@@ -0,0 +1,17 @@
+# Backup/Restore your instance
+
+## Backup
+
+1. Stop the Pleroma service.
+2. Go to the working directory of Pleroma (default is `/opt/pleroma`)
+3. Run `sudo -Hu postgres pg_dump -d <pleroma_db> --format=custom -f </path/to/backup_location/pleroma.pgdump>`
+4. Copy `pleroma.pgdump`, `config/prod.secret.exs` and the `uploads` folder to your backup destination. If you have other modifications, copy those changes too.
+5. Restart the Pleroma service.
+
+## Restore
+
+1. Stop the Pleroma service.
+2. Go to the working directory of Pleroma (default is `/opt/pleroma`)
+3. Copy the above mentioned files back to their original position.
+4. Run `sudo -Hu postgres pg_restore -d <pleroma_db> -v -1 </path/to/backup_location/pleroma.pgdump>`
+5. Restart the Pleroma service.
diff --git a/docs/admin/updating.md b/docs/admin/updating.md
new file mode 100644 (file)
index 0000000..84e6ef1
--- /dev/null
@@ -0,0 +1,9 @@
+# Updating your instance
+1. Go to the working directory of Pleroma (default is `/opt/pleroma`)
+2. Run `git pull`. This pulls the latest changes from upstream.
+3. Run `mix deps.get`. This pulls in any new dependencies.
+4. Stop the Pleroma service.
+5. Run `mix ecto.migrate`[^1]. This task performs database migrations, if there were any.
+6. Start the Pleroma service.
+
+[^1]: Prefix with `MIX_ENV=prod` to run it using the production config file.
similarity index 76%
rename from docs/Admin-API.md
rename to docs/api/admin_api.md
index 2edb31f3c2e71c6ac4b4a63083e386960c3cc80f..53b68ffd46d8d51e4c09eb5eec11fa5dfe989300 100644 (file)
@@ -8,10 +8,15 @@ Authentication is required and the user must be an admin.
 
 - Method `GET`
 - Query Params:
-  - `query`: **string** *optional* search term
-  - `local_only`: **bool** *optional* whether to return only local users
-  - `page`: **integer** *optional* page number
-  - `page_size`: **integer** *optional* number of users per page (default is `50`)
+  - *optional* `query`: **string** search term
+  - *optional* `filters`: **string** comma-separated string of filters:
+    - `local`: only local users
+    - `external`: only external users
+    - `active`: only active users
+    - `deactivated`: only deactivated users
+  - *optional* `page`: **integer** page number
+  - *optional* `page_size`: **integer** number of users per page (default is `50`)
+- Example: `https://mypleroma.org/api/pleroma/admin/users?query=john&filters=local,active&page=1&page_size=10`
 - Response:
 
 ```JSON
@@ -22,7 +27,13 @@ Authentication is required and the user must be an admin.
     {
       "deactivated": bool,
       "id": integer,
-      "nickname": string
+      "nickname": string,
+      "roles": {
+        "admin": bool,
+        "moderator": bool
+      },
+      "local": bool,
+      "tags": array
     },
     ...
   ]
@@ -99,7 +110,7 @@ Authentication is required and the user must be an admin.
 
 Note: Available `:permission_group` is currently moderator and admin. 404 is returned when the permission group doesn’t exist.
 
-### Get user user permission groups membership
+### Get user user permission groups membership per permission group
 
 - Method: `GET`
 - Params: none
@@ -138,6 +149,17 @@ Note: Available `:permission_group` is currently moderator and admin. 404 is ret
   - `nickname`
   - `status` BOOLEAN field, false value means deactivation.
 
+## `/api/pleroma/admin/users/:nickname`
+
+### Retrive the details of a user
+
+- Method: `GET`
+- Params:
+  - `nickname`
+- Response:
+  - On failure: `Not found`
+  - On success: JSON of the user
+
 ## `/api/pleroma/admin/relay`
 
 ### Follow a Relay
similarity index 100%
rename from docs/Pleroma-API.md
rename to docs/api/pleroma_api.md
similarity index 100%
rename from docs/Clients.md
rename to docs/clients.md
index c1246ee25760ef833ff2f4e5457ee41f69ab552c..97a0e6ffa57087317409d606ddc687d070e2165b 100644 (file)
@@ -193,6 +193,44 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i
 * `port`: Port to bind to
 * `dstport`: Port advertised in urls (optional, defaults to `port`)
 
+## Pleroma.Web.Endpoint
+`Phoenix` endpoint configuration, all configuration options can be viewed [here](https://hexdocs.pm/phoenix/Phoenix.Endpoint.html#module-dynamic-configuration), only common options are listed here
+* `http` - a list containing http protocol configuration, all configuration options can be viewed [here](https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html#module-options), only common options are listed here
+  - `ip` - a tuple consisting of 4 integers
+  - `port`
+* `url` - a list containing the configuration for generating urls, accepts
+  - `host` - the host without the scheme and a post (e.g `example.com`, not `https://example.com:2020`)
+  - `scheme` - e.g `http`, `https` 
+  - `port`
+  - `path`
+
+
+**Important note**: if you modify anything inside these lists, default `config.exs` values will be overwritten, which may result in breakage, to make sure this does not happen please copy the default value for the list from `config.exs` and modify/add only what you need
+
+Example: 
+```elixir
+config :pleroma, Pleroma.Web.Endpoint,
+  url: [host: "example.com", port: 2020, scheme: "https"],
+  http: [
+    # start copied from config.exs
+    dispatch: [
+      {:_,
+       [
+         {"/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
+         {"/websocket", Phoenix.Endpoint.CowboyWebSocket,
+          {Phoenix.Transports.WebSocket,
+           {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, websocket_config}}},
+         {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
+       ]}
+    # end copied from config.exs
+    ],
+    port: 8080,
+    ip: {127, 0, 0, 1}
+  ]
+```
+
+This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls starting with `https://example.com:2020`
+
 ## :activitypub
 * ``accept_blocks``: Whether to accept incoming block activities from other instances
 * ``unfollow_blocked``: Whether blocks result in people getting unfollowed
@@ -253,25 +291,25 @@ You can then do
 curl "http://localhost:4000/api/pleroma/admin/invite_token?admin_token=somerandomtoken"
 ```
 
-## Pleroma.Jobs
+## :pleroma_job_queue
 
-A list of job queues and their settings.
+[Pleroma Job Queue](https://git.pleroma.social/pleroma/pleroma_job_queue) configuration: a list of queues with maximum concurrent jobs.
 
-Job queue settings:
-
-* `max_jobs`: The maximum amount of parallel jobs running at the same time.
+Pleroma has the following queues:
+* `federator_outgoing` - Outgoing federation
+* `federator_incoming` - Incoming federation
+* `mailer` - Email sender, see [`Pleroma.Mailer`](#pleroma-mailer)
 
 Example:
 
-```exs
-config :pleroma, Pleroma.Jobs,
-  federator_incoming: [max_jobs: 50],
-  federator_outgoing: [max_jobs: 50]
+```elixir
+config :pleroma_job_queue, :queues,
+  federator_incoming: 50,
+  federator_outgoing: 50
 ```
 
 This config contains two queues: `federator_incoming` and `federator_outgoing`. Both have the `max_jobs` set to `50`.
 
-
 ## Pleroma.Web.Federator.RetryQueue
 
 * `enabled`: If set to `true`, failed federation jobs will be retried
diff --git a/docs/config/General-tips-for-customizing-Pleroma-FE.md b/docs/config/General-tips-for-customizing-Pleroma-FE.md
new file mode 100644 (file)
index 0000000..15c4882
--- /dev/null
@@ -0,0 +1,17 @@
+# General tips for customizing Pleroma FE
+There are some configuration scripts for Pleroma BE and FE:
+
+1. `config/prod.secret.exs`
+1. `config/config.exs`
+1. `priv/static/static/config.json`
+
+The `prod.secret.exs` affects first. `config.exs` is for fallback or default. `config.json` is for GNU-social-BE-Pleroma-FE instances.
+
+Usually all you have to do is:
+
+1. Copy the section in the `config/config.exs` which you want to activate.
+1. Paste into `config/prod.secret.exs`.
+1. Edit `config/prod.secret.exs`.
+1. Restart the Pleroma daemon.
+
+`prod.secret.exs` is for the `MIX_ENV=prod` environment. `dev.secret.exs` is for the `MIX_ENV=dev` environment respectively.
similarity index 97%
rename from docs/Custom-Emoji.md
rename to docs/config/custom_emoji.md
index 9d90e5822dbf5d65ce7a6a3b92c8475e14e6b20b..e833d2080dc76ed158a39cc1f4c3497c09d2606e 100644 (file)
@@ -1,4 +1,4 @@
-# Custom emoji
+# Custom Emoji
 
 To add custom emoji:
 * Add the image file(s) to `priv/static/emoji/custom`
diff --git a/docs/config/hardening.md b/docs/config/hardening.md
new file mode 100644 (file)
index 0000000..b54c288
--- /dev/null
@@ -0,0 +1,103 @@
+# Hardening your instance
+Here are some suggestions which improve the security of parts of your Pleroma instance.
+
+## Configuration file
+
+These changes should go into `prod.secret.exs` or `dev.secret.exs`, depending on your `MIX_ENV` value.
+
+### `http`
+
+> Recommended value: `[ip: {127, 0, 0, 1}]`
+
+This sets the Pleroma application server to only listen to the localhost interface. This way, you can only reach your server over the Internet by going through the reverse proxy. By default, Pleroma listens on all interfaces.
+
+### `secure_cookie_flag`
+
+> Recommended value: `true`
+
+This sets the `secure` flag on Pleroma’s session cookie. This makes sure, that the cookie is only accepted over encrypted HTTPs connections. This implicitly renames the cookie from `pleroma_key` to `__Host-pleroma-key` which enforces some restrictions. (see [cookie prefixes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Cookie_prefixes))
+
+### `:http_security`
+
+> Recommended value: `true`
+
+This will send additional HTTP security headers to the clients, including:
+
+* `X-XSS-Protection: "1; mode=block"`
+* `X-Permitted-Cross-Domain-Policies: "none"`
+* `X-Frame-Options: "DENY"`
+* `X-Content-Type-Options: "nosniff"`
+* `X-Download-Options: "noopen"`
+
+A content security policy (CSP) will also be set:
+
+```csp
+content-security-policy:
+  default-src 'none';
+  base-uri 'self';
+  frame-ancestors 'none';
+  img-src 'self' data: https:;
+  media-src 'self' https:;
+  style-src 'self' 'unsafe-inline';
+  font-src 'self';
+  script-src 'self';
+  connect-src 'self' wss://example.tld;
+  manifest-src 'self';
+  upgrade-insecure-requests;
+```
+
+#### `sts`
+
+> Recommended value: `true`
+
+An additional “Strict transport security” header will be sent with the configured `sts_max_age` parameter. This tells the browser, that the domain should only be accessed over a secure HTTPs connection.
+
+#### `ct_max_age`
+
+An additional “Expect-CT” header will be sent with the configured `ct_max_age` parameter. This enforces the use of TLS certificates that are published in the certificate transparency log. (see [Expect-CT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT))
+
+#### `referrer_policy`
+
+> Recommended value: `same-origin`
+
+If you click on a link, your browser’s request to the other site will include from where it is coming from. The “Referrer policy” header tells the browser how and if it should send this information. (see [Referrer policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy))
+
+## systemd
+
+A systemd unit example is provided at `installation/pleroma.service`.
+
+### PrivateTmp
+
+> Recommended value: `true`
+
+Use private `/tmp` and `/var/tmp` folders inside a new file system namespace, which are discarded after the process stops.
+
+### ProtectHome
+
+> Recommended value: `true`
+
+The `/home`, `/root`, and `/run/user` folders can not be accessed by this service anymore. If your Pleroma user has its home folder in one of the restricted places, or use one of these folders as its working directory, you have to set this to `false`.
+
+### ProtectSystem
+
+> Recommended value: `full`
+
+Mount `/usr`, `/boot`, and `/etc` as read-only for processes invoked by this service.
+
+### PrivateDevices
+
+> Recommended value: `true`
+
+Sets up a new `/dev` mount for the process and only adds API pseudo devices like `/dev/null`, `/dev/zero` or `/dev/random` but not physical devices. This may not work on devices like the Raspberry Pi, where you need to set this to `false`.
+
+### NoNewPrivileges
+
+> Recommended value: `true`
+
+Ensures that the service process and all its children can never gain new privileges through `execve()`.
+
+### CapabilityBoundingSet
+
+> Recommended value: `~CAP_SYS_ADMIN`
+
+Drops the sysadmin capability from the daemon.
diff --git a/docs/config/howto_mediaproxy.md b/docs/config/howto_mediaproxy.md
new file mode 100644 (file)
index 0000000..fb73111
--- /dev/null
@@ -0,0 +1,32 @@
+# How to activate mediaproxy
+## Explanation
+
+Without the `mediaproxy` function, Pleroma don't store any remote content like pictures, video etc. locally. So every time you open Pleroma, the content is loaded from the source server, from where the post is coming. This can result in slowly loading content or/and increased bandwidth usage on the source server.
+With the `mediaproxy` function you can use the cache ability of nginx, to cache these content, so user can access it faster, cause it's loaded from your server.
+
+## Activate it
+
+* Edit your nginx config and add the following location: 
+```
+location /proxy {
+        proxy_cache pleroma_media_cache;
+        proxy_cache_lock on;
+        proxy_pass http://localhost:4000;
+}
+```
+Also add the following on top of the configuration, outside of the `server` block:
+```
+proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g inactive=720m use_temp_path=off;
+```
+If you came here from one of the installation guides, take a look at the example configuration `/installation/pleroma.nginx`, where this part is already included.
+
+* Append the following to your `prod.secret.exs` or `dev.secret.exs` (depends on which mode your instance is running):
+```
+config :pleroma, :media_proxy,
+      enabled: true,
+      redirect_on_failure: true
+      #base_url: "https://cache.pleroma.social"
+```
+If you want to use a subdomain to serve the files, uncomment `base_url`, change the url and add a comma after `true` in the previous line.
+
+* Restart nginx and Pleroma
diff --git a/docs/config/howto_proxy.md b/docs/config/howto_proxy.md
new file mode 100644 (file)
index 0000000..10a6352
--- /dev/null
@@ -0,0 +1,12 @@
+# How to configure upstream proxy for federation
+If you want to proxify all http requests (e.g. for TOR) that pleroma makes to an upstream proxy server, edit you config file (`dev.secret.exs` or `prod.secret.exs`) and add the following:
+
+```
+config :pleroma, :http,
+  proxy_url: "127.0.0.1:8123"
+```
+
+The other way to do it, for example, with Tor you would most likely add something like this:
+```
+config :pleroma, :http, proxy_url: {:socks5, :localhost, 9050}
+```
diff --git a/docs/config/howto_user_recomendation.md b/docs/config/howto_user_recomendation.md
new file mode 100644 (file)
index 0000000..27c0760
--- /dev/null
@@ -0,0 +1,31 @@
+# How to activate user recommendation (Who to follow panel)
+![who-to-follow-panel-small](/uploads/9de1b1300436c32461d272945f1bc23e/who-to-follow-panel-small.png)
+
+To show the *who to follow* panel, edit `config/prod.secret.exs` in the Pleroma backend. Following code activates the *who to follow* panel:
+
+```elixir
+config :pleroma, :suggestions,
+  enabled: true,
+  third_party_engine:
+    "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-match-suggestions-api.cgi?{{host}}+{{user}}",
+  timeout: 300_000,
+  limit: 23,
+  web: "https://vinayaka.distsn.org/?{{host}}+{{user}}"
+
+```
+
+`config/config.exs` already includes this code, but `enabled:` is `false`.
+
+`/api/v1/suggestions` is also provided when *who to follow* panel is enabled.
+
+For advanced customization, following code shows the newcomers of the fediverse at the *who to follow* panel:
+
+```elixir
+config :pleroma, :suggestions,
+  enabled: true,
+  third_party_engine:
+    "http://vinayaka.distsn.org/cgi-bin/vinayaka-user-new-suggestions-api.cgi?{{host}}+{{user}}",
+  timeout: 60_000,
+  limit: 23,
+  web: "https://vinayaka.distsn.org/user-new.html"
+```
diff --git a/docs/config/i2p.md b/docs/config/i2p.md
new file mode 100644 (file)
index 0000000..62ced8b
--- /dev/null
@@ -0,0 +1,196 @@
+# I2P Federation and Accessability
+
+This guide is going to focus on the Pleroma federation aspect. The actual installation is neatly explained in the official documentation, and more likely to remain up-to-date.
+It might be added to this guide if there will be a need for that.
+
+We're going to use I2PD for its lightweightness over the official client.
+Follow the documentation according to your distro: https://i2pd.readthedocs.io/en/latest/user-guide/install/#installing
+
+How to run it: https://i2pd.readthedocs.io/en/latest/user-guide/run/
+
+## I2P Federation
+
+There are 2 ways to go about this.
+One using the config, and one using external software (fedproxy). The external software works better so far.
+
+### Using the Config
+
+**Warning:** So far, everytime I followed this way of federating using I2P, the rest of my federation stopped working. I'm leaving this here in case it will help with making it work.
+
+Assuming you're running in prod, cd to your Pleroma folder and append the following to `config/prod.secret.exs`:
+```
+config :pleroma, :http, proxy_url: {:socks5, :localhost, 4447}
+```
+And then run the following:
+```
+su pleroma
+MIX_ENV=prod mix deps.get
+MIX_ENV=prod mix ecto.migrate
+exit
+```
+You can restart I2PD here and finish if you don't wish to make your instance viewable or accessible over I2P.
+```
+systemctl stop i2pd.service --no-block
+systemctl start i2pd.service
+```
+*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes).
+
+You can change the socks proxy port in `/etc/i2pd/i2pd.conf`.
+
+### Using Fedproxy
+
+Fedproxy passes through clearnet requests direct to where they are going. It doesn't force anything over Tor.
+
+To use [fedproxy](https://github.com/majestrate/fedproxy) you'll need to install Golang.
+```
+apt install golang
+```
+Use a different user than pleroma or root. Run the following to add the Gopath to your ~/.bashrc.
+```
+echo "export GOPATH=/home/ren/.go" >> ~/.bashrc
+```
+Restart that bash session (you can exit and log back in).
+Run the following to get fedproxy.
+```
+go get -u github.com/majestrate/fedproxy$
+cp $(GOPATH)/bin/fedproxy /usr/local/bin/fedproxy
+```
+And then the following to start it for I2P only.
+```
+fedproxy 127.0.0.1:2000 127.0.0.1:4447
+```
+If you want to also use it for Tor, add `127.0.0.1:9050` to that command.
+You'll also need to modify your Pleroma config.
+
+Assuming you're running in prod, cd to your Pleroma folder and append the following to `config/prod.secret.exs`:
+```
+config :pleroma, :http, proxy_url: {:socks5, :localhost, 2000}
+```
+And then run the following:
+```
+su pleroma
+MIX_ENV=prod mix deps.get
+MIX_ENV=prod mix ecto.migrate
+exit
+```
+You can restart I2PD here and finish if you don't wish to make your instance viewable or accessible over I2P.
+
+```
+systemctl stop i2pd.service --no-block
+systemctl start i2pd.service
+```
+*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes).
+
+You can change the socks proxy port in `/etc/i2pd/i2pd.conf`.
+
+## I2P Instance Access
+
+Make your instance accessible using I2P.
+
+Add the following to your I2PD config `/etc/i2pd/tunnels.conf`:
+```
+[pleroma]
+type = http
+host = 127.0.0.1
+port = 14447
+keys = pleroma.dat
+```
+Restart I2PD:
+```
+systemctl stop i2pd.service --no-block
+systemctl start i2pd.service
+```
+*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes).
+
+Now you'll have to find your address.
+To do that you can download and use I2PD tools.[^1]  
+Or you'll need to access your web-console on localhost:7070.
+If you don't have a GUI, you'll have to SSH tunnel into it like this:
+`ssh -L 7070:127.0.0.1:7070 user@ip -p port`.
+Now you can access it at localhost:7070.
+Go to I2P tunnels page. Look for Server tunnels and you will see an address that ends with `.b32.i2p` next to "pleroma".
+This is your site's address.
+
+### I2P-only Instance
+
+If creating an I2P-only instance, open `config/prod.secret.exs` and under "config :pleroma, Pleroma.Web.Endpoint," edit "https" and "port: 443" to the following:
+```
+   url: [host: "i2paddress", scheme: "http", port: 80],
+```
+In addition to that, replace the existing nginx config's contents with the example below.
+
+### Existing Instance (Clearnet Instance)
+
+If not an I2P-only instance, add the nginx config below to your existing config at `/etc/nginx/sites-enabled/pleroma.nginx`.
+
+And for both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself seperately from the clearnet (if your instance is also on the clearnet).
+Copy the following into the `config/prod.secret.exs` in your Pleroma folder (/home/pleroma/pleroma/):
+```
+config :pleroma, :http_security,
+  enabled: false
+```
+
+Use this as the Nginx config:
+```
+proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g inactive=720m use_temp_path=off;
+# The above already exists in a clearnet instance's config.
+# If not, add it.
+
+server {
+    listen 127.0.0.1:14447;
+    server_name youri2paddress;
+
+    # Comment to enable logs
+    access_log /dev/null;
+    error_log /dev/null;
+
+    gzip_vary on;
+    gzip_proxied any;
+    gzip_comp_level 6;
+    gzip_buffers 16 8k;
+    gzip_http_version 1.1;
+    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/activity+json application/atom+xml;
+
+    client_max_body_size 16m;
+
+    location / {
+
+        add_header X-XSS-Protection "1; mode=block";
+        add_header X-Permitted-Cross-Domain-Policies none;
+        add_header X-Frame-Options DENY;
+        add_header X-Content-Type-Options nosniff;
+        add_header Referrer-Policy same-origin;
+        add_header X-Download-Options noopen;
+
+        proxy_http_version 1.1;
+        proxy_set_header Upgrade $http_upgrade;
+        proxy_set_header Connection "upgrade";
+        proxy_set_header Host $http_host;
+
+        proxy_pass http://localhost:4000;
+
+        client_max_body_size 16m;
+    }
+
+    location /proxy {
+        proxy_cache pleroma_media_cache;
+        proxy_cache_lock on;
+        proxy_ignore_client_abort on;
+        proxy_pass http://localhost:4000;
+    }
+}
+```
+reload Nginx:
+```
+systemctl stop i2pd.service --no-block
+systemctl start i2pd.service
+```
+*Notice:* The stop command initiates a graceful shutdown process, i2pd stops after finishing to route transit tunnels (maximum 10 minutes).
+
+You should now be able to both access your instance using I2P and federate with other I2P instances!
+
+[^1]: [I2PD tools](https://github.com/purplei2p/i2pd-tools) to print information about a router info file or an I2P private key, generate an I2P private key, and generate vanity addresses.
+
+### Possible Issues
+
+Will be added when encountered.
similarity index 98%
rename from docs/Message-Rewrite-Facility-configuration.md
rename to docs/config/mrf.md
index 35ce52ea944406b7d0d027f90fd8168f6af2088d..2cc16cef0d2a60e09dab456893672ab3c9c9cd7f 100644 (file)
@@ -1,4 +1,4 @@
-# Message Rewrite Facility configuration
+# Message Rewrite Facility
 The Message Rewrite Facility (MRF) is a subsystem that is implemented as a series of hooks that allows the administrator to rewrite or discard messages.
 
 Possible uses include:
@@ -70,7 +70,7 @@ As discussed above, the MRF system is a modular system that supports pluggable p
 
 For example, here is a sample policy module which rewrites all messages to "new message content":
 
-```!elixir
+```elixir
 # This is a sample MRF policy which rewrites all Notes to have "new message
 # content."
 defmodule Site.RewritePolicy do
@@ -116,4 +116,4 @@ config :pleroma, :instance,
   ]
 ```
 
-Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL.  As such, you are obligated to release the sources to your custom MRF policy modules upon request.
\ No newline at end of file
+Please note that the Pleroma developers consider custom MRF policy modules to fall under the purview of the AGPL.  As such, you are obligated to release the sources to your custom MRF policy modules upon request.
diff --git a/docs/config/onion_federation.md b/docs/config/onion_federation.md
new file mode 100644 (file)
index 0000000..99f1049
--- /dev/null
@@ -0,0 +1,159 @@
+# Easy Onion Federation (Tor)
+Tor can free people from the necessity of a domain, in addition to helping protect their privacy. As Pleroma's goal is to empower the people and let as many as possible host an instance with as little resources as possible, the ability to host an instance with a small, cheap computer like a RaspberryPi along with Tor, would be a great way to achieve that.  
+In addition, federating with such instances will also help furthering that goal.
+
+This is a guide to show you how it can be easily done.
+
+This guide assumes you already got Pleroma working, and that it's running on the default port 4000.  
+Currently only has an Nginx example.
+
+To install Tor on Debian / Ubuntu:
+```
+apt -yq install tor
+```
+If using an old server version (older than Debian Stretch or Ubuntu 18.04), install from backports or PPA.
+I recommend using a newer server version instead.
+
+To have the newest, V3 onion addresses (which I recommend) in Debian, install Tor from backports.
+If you do not have backports, uncomment the stretch-backports links at the end of `/etc/apt/sources.list`.
+Then install:
+```
+apt update
+apt -t stretch-backports  -yq install tor
+```
+**WARNING:** Onion instances not using a Tor version supporting V3 addresses will not be able to federate with you. 
+
+Create the hidden service for your Pleroma instance in `/etc/tor/torrc`:
+```
+HiddenServiceDir /var/lib/tor/pleroma_hidden_service/
+HiddenServicePort 80 127.0.0.1:8099
+HiddenServiceVersion 3  # Remove if Tor version is below 0.3 ( tor --version )
+```
+Restart Tor to generate an adress:
+```
+systemctl restart tor@default.service
+```
+Get the address:
+```
+cat /var/lib/tor/pleroma_hidden_service/hostname
+```
+
+# Federation
+
+Next, edit your Pleroma config.
+If running in prod, cd to your Pleroma directory, edit `config/prod.secret.exs`
+and append this line:
+```
+config :pleroma, :http, proxy_url: {:socks5, :localhost, 9050}
+```
+In your Pleroma directory, assuming you're running prod,
+run the following:
+```
+su pleroma
+MIX_ENV=prod mix deps.get
+MIX_ENV=prod mix ecto.migrate
+exit
+```
+restart Pleroma (if using systemd):
+```
+systemctl restart pleroma
+```
+
+# Tor Instance Access
+
+Make your instance accessible using Tor.
+
+## Tor-only Instance
+If creating a Tor-only instance, open `config/prod.secret.exs` and under "config :pleroma, Pleroma.Web.Endpoint," edit "https" and "port: 443" to the following:
+```
+   url: [host: "onionaddress", scheme: "http", port: 80],
+```
+In addition to that, replace the existing nginx config's contents with the example below.
+
+## Existing Instance (Clearnet Instance)
+If not a Tor-only instance, 
+add the nginx config below to your existing config at `/etc/nginx/sites-enabled/pleroma.nginx`.
+
+---
+For both cases, disable CSP in Pleroma's config (STS is disabled by default) so you can define those yourself seperately from the clearnet (if your instance is also on the clearnet).
+Copy the following into the `config/prod.secret.exs` in your Pleroma folder (/home/pleroma/pleroma/):
+```
+config :pleroma, :http_security,
+  enabled: false
+```
+
+Use this as the Nginx config:
+```
+proxy_cache_path /tmp/pleroma-media-cache levels=1:2 keys_zone=pleroma_media_cache:10m max_size=10g inactive=720m use_temp_path=off;
+# The above already exists in a clearnet instance's config.
+# If not, add it.
+
+server {
+    listen 127.0.0.1:8099;
+    server_name youronionaddress;
+
+    # Comment to enable logs
+    access_log /dev/null;
+    error_log /dev/null;
+
+    gzip_vary on;
+    gzip_proxied any;
+    gzip_comp_level 6;
+    gzip_buffers 16 8k;
+    gzip_http_version 1.1;
+    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/activity+json application/atom+xml;
+
+    client_max_body_size 16m;
+
+    location / {
+
+        add_header X-XSS-Protection "1; mode=block";
+        add_header X-Permitted-Cross-Domain-Policies none;
+        add_header X-Frame-Options DENY;
+        add_header X-Content-Type-Options nosniff;
+        add_header Referrer-Policy same-origin;
+        add_header X-Download-Options noopen;
+
+        proxy_http_version 1.1;
+        proxy_set_header Upgrade $http_upgrade;
+        proxy_set_header Connection "upgrade";
+        proxy_set_header Host $http_host;
+
+        proxy_pass http://localhost:4000;
+
+        client_max_body_size 16m;
+    }
+
+    location /proxy {
+        proxy_cache pleroma_media_cache;
+        proxy_cache_lock on;
+        proxy_ignore_client_abort on;
+        proxy_pass http://localhost:4000;
+    }
+}
+```
+reload Nginx:
+```
+systemctl reload nginx
+```
+
+You should now be able to both access your instance using Tor and federate with other Tor instances!
+
+---
+
+### Possible Issues
+
+*  In Debian, make sure your hidden service folder `/var/lib/tor/pleroma_hidden_service/` and its contents, has debian-tor as both owner and group by using 
+```
+ls -la /var/lib/tor/
+```
+If it's not, run:
+```
+chown -R debian-tor:debian-tor /var/lib/tor/pleroma_hidden_service/
+```
+* Make sure *only* the owner has *only* read and write permissions.
+If not, run:
+```
+chmod -R 600 /var/lib/tor/pleroma_hidden_service/
+```
+* If you have trouble logging in to the Mastodon Frontend when using Tor, use the Tor Browser Bundle.
diff --git a/docs/config/small_customizations.md b/docs/config/small_customizations.md
new file mode 100644 (file)
index 0000000..09e8d60
--- /dev/null
@@ -0,0 +1,35 @@
+# Small customizations
+Replace `dev.secret.exs` with `prod.secret.exs` according to your setup.
+
+# Thumbnail
+
+Replace `priv/static/instance/thumbnail.jpeg` with your selfie or other neat picture. It will appear in [Pleroma Instances](http://distsn.org/pleroma-instances.html).
+
+# Instance-specific panel
+
+![instance-specific panel demo](/uploads/296b19ec806b130e0b49b16bfe29ce8a/image.png)
+
+To show the instance specific panel, set `show_instance_panel` to `true` in `config/dev.secret.exs`. You can modify its content by editing `priv/static/instance/panel.html`.
+
+# Background
+
+You can change the background of your Pleroma instance by uploading it to `priv/static/static`, and then changing `"background"` in `config/dev.secret.exs` accordingly.
+
+# Logo
+
+![logo modification demo](/uploads/c70b14de60fa74245e7f0dcfa695ebff/image.png)
+
+If you want to give a brand to your instance, look no further. You can change the logo of your instance by uploading it to `priv/static/static`, and then changing `logo` in `config/dev.secret.exs` accordingly.
+
+# Theme
+
+All users of your instance will be able to change the theme they use by going to the settings (the cog in the top-right hand corner). However, if you wish to change the default theme, you can do so by editing `theme` in `config/dev.secret.exs` accordingly.
+
+# Terms of Service
+
+Terms of Service will be shown to all users on the registration page. It's the best place where to write down the rules for your instance. You can modify the rules by changing `priv/static/static/terms-of-service.html`.
+
+# Message Visibility
+
+To enable message visibility options when posting like in the Mastodon frontend, set
+`scope_options_enabled` to `true` in `config/dev.secret.exs`.
similarity index 100%
rename from docs/static_dir.md
rename to docs/config/static_dir.md
diff --git a/docs/installation/alpine_linux_en.md b/docs/installation/alpine_linux_en.md
new file mode 100644 (file)
index 0000000..c493816
--- /dev/null
@@ -0,0 +1,215 @@
+# Installing on Alpine Linux
+## Installation
+
+This guide is a step-by-step installation guide for Alpine Linux. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.linode.com/docs/tools-reference/custom-kernels-distros/install-alpine-linux-on-your-linode/#configuration). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su -l <username> -s $SHELL -c 'command'` instead.
+
+### Required packages
+
+* `postgresql`
+* `elixir`
+* `erlang`
+* `erlang-parsetools`
+* `erlang-xmerl`
+* `git`
+* Development Tools
+
+#### Optional packages used in this guide
+
+* `nginx` (preferred, example configs for other reverse proxies can be found in the repo)
+* `certbot` (or any other ACME client for Let’s Encrypt certificates)
+
+### Prepare the system
+
+* First make sure to have the community repository enabled:
+
+```shell
+echo "https://nl.alpinelinux.org/alpine/latest-stable/community" | sudo tee -a /etc/apk/repository
+```
+
+* Then update the system, if not already done:
+
+```shell
+sudo apk update
+sudo apk upgrade
+```
+
+* Install some tools, which are needed later:
+
+```shell
+sudo apk add git build-base
+```
+
+### Install Elixir and Erlang
+
+* Install Erlang and Elixir:
+
+```shell
+sudo apk add erlang erlang-runtime-tools erlang-xmerl elixir
+```
+
+* Install `erlang-eldap` if you want to enable ldap authenticator
+
+```shell
+sudo apk add erlang-eldap
+```
+### Install PostgreSQL
+
+* Install Postgresql server:
+
+```shell
+sudo apk add postgresql postgresql-contrib
+```
+
+* Initialize database:
+
+```shell
+sudo /etc/init.d/postgresql start
+```
+
+* Enable and start postgresql server:
+
+```shell
+sudo rc-update add postgresql
+```
+
+### Install PleromaBE
+
+* Add a new system user for the Pleroma service:
+
+```shell
+sudo adduser -S -s /bin/false -h /opt/pleroma -H pleroma
+```
+
+**Note**: To execute a single command as the Pleroma system user, use `sudo -Hu pleroma command`. You can also switch to a shell by using `sudo -Hu pleroma $SHELL`. If you don’t have and want `sudo` on your system, you can use `su` as root user (UID 0) for a single command by using `su -l pleroma -s $SHELL -c 'command'` and `su -l pleroma -s $SHELL` for starting a shell.
+
+* Git clone the PleromaBE repository and make the Pleroma user the owner of the directory:
+
+```shell
+sudo mkdir -p /opt/pleroma
+sudo chown -R pleroma:pleroma /opt/pleroma
+sudo -Hu pleroma git clone https://git.pleroma.social/pleroma/pleroma /opt/pleroma
+```
+
+* Change to the new directory:
+
+```shell
+cd /opt/pleroma
+```
+
+* Install the dependencies for Pleroma and answer with `yes` if it asks you to install `Hex`:
+
+```shell
+sudo -Hu pleroma mix deps.get
+```
+
+* Generate the configuration: `sudo -Hu pleroma mix pleroma.instance gen`
+  * Answer with `yes` if it asks you to install `rebar3`.
+  * This may take some time, because parts of pleroma get compiled first.
+  * After that it will ask you a few questions about your instance and generates a configuration file in `config/generated_config.exs`.
+
+* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for productive instance, `dev.secret.exs` for development instances):
+
+```shell
+mv config/{generated_config.exs,prod.secret.exs}
+```
+
+* The previous command creates also the file `config/setup_db.psql`, with which you can create the database:
+
+```shell
+sudo -Hu postgres psql -f config/setup_db.psql
+```
+
+* Now run the database migration:
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix ecto.migrate
+```
+
+* Now you can start Pleroma already
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix phx.server
+```
+
+### Finalize installation
+
+If you want to open your newly installed instance to the world, you should run nginx or some other webserver/proxy in front of Pleroma and you should consider to create an OpenRC service file for Pleroma.
+
+#### Nginx
+
+* Install nginx, if not already done:
+
+```shell
+sudo apk add nginx
+```
+
+* Setup your SSL cert, using your method of choice or certbot. If using certbot, first install it:
+
+```shell
+sudo apk add certbot
+```
+
+and then set it up:
+
+```shell
+sudo mkdir -p /var/lib/letsencrypt/
+sudo certbot certonly --email <your@emailaddress> -d <yourdomain> --standalone
+```
+
+If that doesn’t work, make sure, that nginx is not already running. If it still doesn’t work, try setting up nginx first (change ssl “on” to “off” and try again).
+
+* Copy the example nginx configuration to the nginx folder
+
+```shell
+sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf
+```
+
+* Before starting nginx edit the configuration and change it to your needs (e.g. change servername, change cert paths)
+* Enable and start nginx:
+
+```shell
+sudo rc-update add nginx
+sudo service nginx start
+```
+
+If you need to renew the certificate in the future, uncomment the relevant location block in the nginx config and run:
+
+```shell
+sudo certbot certonly --email <your@emailaddress> -d <yourdomain> --webroot -w /var/lib/letsencrypt/
+```
+
+#### OpenRC service
+
+* Copy example service file:
+
+```shell
+sudo cp /opt/pleroma/installation/init.d/pleroma /etc/init.d/pleroma
+```
+
+* Make sure to start it during the boot
+
+```shell
+sudo rc-update add pleroma
+```
+
+#### Create your first user
+
+If your instance is up and running, you can create your first user with administrative rights with the following task:
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new <username> <your@emailaddress> --admin
+```
+
+#### Further reading
+
+* [Admin tasks](Admin tasks)
+* [Backup your instance](Backup-your-instance)
+* [Configuration tips](General tips for customizing pleroma fe)
+* [Hardening your instance](Hardening-your-instance)
+* [How to activate mediaproxy](How-to-activate-mediaproxy)
+* [Small Pleroma-FE customizations](Small customizations)
+* [Updating your instance](Updating-your-instance)
+
+## Questions
+
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
diff --git a/docs/installation/arch_linux_en.md b/docs/installation/arch_linux_en.md
new file mode 100644 (file)
index 0000000..4b3bbbb
--- /dev/null
@@ -0,0 +1,214 @@
+# Installing on Arch Linux
+## Installation
+
+This guide will assume that you have administrative rights, either as root or a user with [sudo permissions](https://wiki.archlinux.org/index.php/Sudo). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.
+
+### Required packages
+
+* `postgresql`
+* `elixir`
+* `erlang-unixodbc`
+* `git`
+* `base-devel`
+
+#### Optional packages used in this guide
+
+* `nginx` (preferred, example configs for other reverse proxies can be found in the repo)
+* `certbot` (or any other ACME client for Let’s Encrypt certificates)
+
+### Prepare the system
+
+* First update the system, if not already done:
+
+```shell
+sudo pacman -Syu
+```
+
+* Install some of the above mentioned programs:
+
+```shell
+sudo pacman -S git base-devel elixir erlang-unixodbc
+```
+
+### Install PostgreSQL
+
+[Arch Wiki article](https://wiki.archlinux.org/index.php/PostgreSQL)
+
+* Install the `postgresql` package:
+
+```shell
+sudo pacman -S postgresql
+```
+
+* Initialize the database cluster:
+
+```shell
+sudo -iu postgres initdb -D /var/lib/postgres/data
+```
+
+* Start and enable the `postgresql.service`
+
+```shell
+sudo systemctl enable --now postgresql.service
+```
+
+### Install PleromaBE
+
+* Add a new system user for the Pleroma service:
+
+```shell
+sudo useradd -r -s /bin/false -m -d /var/lib/pleroma -U pleroma
+```
+
+**Note**: To execute a single command as the Pleroma system user, use `sudo -Hu pleroma command`. You can also switch to a shell by using `sudo -Hu pleroma $SHELL`. If you don’t have and want `sudo` on your system, you can use `su` as root user (UID 0) for a single command by using `su -l pleroma -s $SHELL -c 'command'` and `su -l pleroma -s $SHELL` for starting a shell.
+
+* Git clone the PleromaBE repository and make the Pleroma user the owner of the directory:
+
+```shell
+sudo mkdir -p /opt/pleroma
+sudo chown -R pleroma:pleroma /opt/pleroma
+sudo -Hu pleroma git clone https://git.pleroma.social/pleroma/pleroma /opt/pleroma
+```
+
+* Change to the new directory:
+
+```shell
+cd /opt/pleroma
+```
+
+* Install the dependencies for Pleroma and answer with `yes` if it asks you to install `Hex`:
+
+```shell
+sudo -Hu pleroma mix deps.get
+```
+
+* Generate the configuration: `sudo -Hu pleroma mix pleroma.instance gen`
+  * Answer with `yes` if it asks you to install `rebar3`.
+  * This may take some time, because parts of pleroma get compiled first.
+  * After that it will ask you a few questions about your instance and generates a configuration file in `config/generated_config.exs`.
+
+* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for productive instance, `dev.secret.exs` for development instances):
+
+```shell
+mv config/{generated_config.exs,prod.secret.exs}
+```
+
+* The previous command creates also the file `config/setup_db.psql`, with which you can create the database:
+
+```shell
+sudo -Hu postgres psql -f config/setup_db.psql
+```
+
+* Now run the database migration:
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix ecto.migrate
+```
+
+* Now you can start Pleroma already
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix phx.server
+```
+
+### Finalize installation
+
+If you want to open your newly installed instance to the world, you should run nginx or some other webserver/proxy in front of Pleroma and you should consider to create a systemd service file for Pleroma.
+
+#### Nginx
+
+* Install nginx, if not already done:
+
+```shell
+sudo pacman -S nginx
+```
+
+* Create directories for available and enabled sites:
+
+```shell
+sudo mkdir -p /etc/nginx/sites-{available,enabled}
+```
+
+* Append the following line at the end of the `http` block in `/etc/nginx/nginx.conf`:
+
+```Nginx
+include sites-enabled/*;
+```
+
+* Setup your SSL cert, using your method of choice or certbot. If using certbot, first install it:
+
+```shell
+sudo pacman -S certbot certbot-nginx
+```
+
+and then set it up:
+
+```shell
+sudo mkdir -p /var/lib/letsencrypt/
+sudo certbot certonly --email <your@emailaddress> -d <yourdomain> --standalone
+```
+
+If that doesn’t work, make sure, that nginx is not already running. If it still doesn’t work, try setting up nginx first (change ssl “on” to “off” and try again).
+
+---
+
+* Copy the example nginx configuration and activate it:
+
+```shell
+sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.nginx
+sudo ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx
+```
+
+* Before starting nginx edit the configuration and change it to your needs (e.g. change servername, change cert paths)
+* Enable and start nginx:
+
+```shell
+sudo systemctl enable --now nginx.service
+```
+
+If you need to renew the certificate in the future, uncomment the relevant location block in the nginx config and run:
+
+```shell
+sudo certbot certonly --email <your@emailaddress> -d <yourdomain> --webroot -w /var/lib/letsencrypt/
+```
+
+#### Other webserver/proxies
+
+You can find example configurations for them in `/opt/pleroma/installation/`.
+
+#### Systemd service
+
+* Copy example service file
+
+```shell
+sudo cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service
+```
+
+* Edit the service file and make sure that all paths fit your installation
+* Enable and start `pleroma.service`:
+
+```shell
+sudo systemctl enable --now pleroma.service
+```
+
+#### Create your first user
+
+If your instance is up and running, you can create your first user with administrative rights with the following task:
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new <username> <your@emailaddress> --admin
+```
+
+#### Further reading
+
+* [Admin tasks](Admin tasks)
+* [Backup your instance](Backup-your-instance)
+* [Configuration tips](General tips for customizing pleroma fe)
+* [Hardening your instance](Hardening-your-instance)
+* [How to activate mediaproxy](How-to-activate-mediaproxy)
+* [Small Pleroma-FE customizations](Small customizations)
+* [Updating your instance](Updating-your-instance)
+
+## Questions
+
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
diff --git a/docs/installation/centos7_en.md b/docs/installation/centos7_en.md
new file mode 100644 (file)
index 0000000..76de21e
--- /dev/null
@@ -0,0 +1,277 @@
+# Installing on CentOS 7
+## Installation
+
+This guide is a step-by-step installation guide for CentOS 7. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-create-a-sudo-user-on-centos-quickstart). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.
+
+### Required packages
+
+* `postgresql` (9,6+, CentOS 7 comes with 9.2, we will install version 11 in this guide)
+* `elixir` (1.5+)
+* `erlang`
+* `erlang-parsetools`
+* `erlang-xmerl`
+* `git`
+* Development Tools
+
+#### Optional packages used in this guide
+
+* `nginx` (preferred, example configs for other reverse proxies can be found in the repo)
+* `certbot` (or any other ACME client for Let’s Encrypt certificates)
+
+### Prepare the system
+
+* First update the system, if not already done:
+
+```shell
+sudo yum update
+```
+
+* Install some of the above mentioned programs:
+
+```shell
+sudo yum install wget git unzip
+```
+
+* Install development tools:
+
+```shell
+sudo yum group install "Development Tools"
+```
+
+### Install Elixir and Erlang
+
+* Add the EPEL repo:
+
+```shell
+sudo yum install epel-release
+sudo yum -y update
+```
+
+* Install Erlang repository:
+
+```shell
+wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
+sudo rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
+```
+
+* Install Erlang:
+
+```shell
+sudo yum install erlang erlang-parsetools erlang-xmerl
+```
+
+* Download [latest Elixir release from Github](https://github.com/elixir-lang/elixir/releases/tag/v1.8.1) (Example for the newest version at the time when this manual was written)
+
+```shell
+wget -P /tmp/ https://github.com/elixir-lang/elixir/releases/download/v1.8.1/Precompiled.zip
+```
+
+* Create folder where you want to install Elixir, we’ll use:
+
+```shell
+sudo mkdir -p /opt/elixir
+```
+
+* Unzip downloaded file there:
+
+```shell
+sudo unzip /tmp/Precompiled.zip -d /opt/elixir
+```
+
+* Create symlinks for the pre-compiled binaries:
+
+```shell
+for e in elixir elixirc iex mix; do sudo ln -s /opt/elixir/bin/${e} /usr/local/bin/${e}; done
+```
+
+### Install PostgreSQL
+
+* Add the Postgresql repository:
+
+```shell
+sudo yum install https://download.postgresql.org/pub/repos/yum/11/redhat/rhel-7-x86_64/pgdg-centos11-11-2.noarch.rpm
+```
+
+* Install the Postgresql server:
+
+```shell
+sudo yum install postgresql11-server postgresql11-contrib
+```
+
+* Initialize database:
+
+```shell
+sudo /usr/pgsql-11/bin/postgresql-11-setup initdb
+```
+
+* Open configuration file `/var/lib/pgsql/11/data/pg_hba.conf` and change the following lines from:
+
+```plain
+# IPv4 local connections:
+host    all             all             127.0.0.1/32            ident
+# IPv6 local connections:
+host    all             all             ::1/128                 ident
+```
+
+to
+
+```plain
+# IPv4 local connections:
+host    all             all             127.0.0.1/32            md5
+# IPv6 local connections:
+host    all             all             ::1/128                 md5
+```
+
+* Enable and start postgresql server:
+
+```shell
+sudo systemctl enable --now postgresql-11.service
+```
+
+### Install PleromaBE
+
+* Add a new system user for the Pleroma service:
+
+```shell
+sudo useradd -r -s /bin/false -m -d /var/lib/pleroma -U pleroma
+```
+
+**Note**: To execute a single command as the Pleroma system user, use `sudo -Hu pleroma command`. You can also switch to a shell by using `sudo -Hu pleroma $SHELL`. If you don’t have and want `sudo` on your system, you can use `su` as root user (UID 0) for a single command by using `su -l pleroma -s $SHELL -c 'command'` and `su -l pleroma -s $SHELL` for starting a shell.
+
+* Git clone the PleromaBE repository and make the Pleroma user the owner of the directory:
+
+```shell
+sudo mkdir -p /opt/pleroma
+sudo chown -R pleroma:pleroma /opt/pleroma
+sudo -Hu pleroma git clone https://git.pleroma.social/pleroma/pleroma /opt/pleroma
+```
+
+* Change to the new directory:
+
+```shell
+cd /opt/pleroma
+```
+
+* Install the dependencies for Pleroma and answer with `yes` if it asks you to install `Hex`:
+
+```shell
+sudo -Hu pleroma mix deps.get
+```
+
+* Generate the configuration: `sudo -Hu pleroma mix pleroma.instance gen`
+  * Answer with `yes` if it asks you to install `rebar3`.
+  * This may take some time, because parts of pleroma get compiled first.
+  * After that it will ask you a few questions about your instance and generates a configuration file in `config/generated_config.exs`.
+
+* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for productive instance, `dev.secret.exs` for development instances):
+
+```shell
+mv config/{generated_config.exs,prod.secret.exs}
+```
+
+* The previous command creates also the file `config/setup_db.psql`, with which you can create the database:
+
+```shell
+sudo -Hu postgres psql -f config/setup_db.psql
+```
+
+* Now run the database migration:
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix ecto.migrate
+```
+
+* Now you can start Pleroma already
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix phx.server
+```
+
+### Finalize installation
+
+If you want to open your newly installed instance to the world, you should run nginx or some other webserver/proxy in front of Pleroma and you should consider to create a systemd service file for Pleroma.
+
+#### Nginx
+
+* Install nginx, if not already done:
+
+```shell
+sudo yum install nginx
+```
+
+* Setup your SSL cert, using your method of choice or certbot. If using certbot, first install it:
+
+```shell
+sudo yum install certbot-nginx
+```
+
+and then set it up:
+
+```shell
+sudo mkdir -p /var/lib/letsencrypt/
+sudo certbot certonly --email <your@emailaddress> -d <yourdomain> --standalone
+```
+
+If that doesn’t work, make sure, that nginx is not already running. If it still doesn’t work, try setting up nginx first (change ssl “on” to “off” and try again).
+
+---
+
+* Copy the example nginx configuration to the nginx folder
+
+```shell
+sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/conf.d/pleroma.conf
+```
+
+* Before starting nginx edit the configuration and change it to your needs (e.g. change servername, change cert paths)
+* Enable and start nginx:
+
+```shell
+sudo systemctl enable --now nginx
+```
+
+If you need to renew the certificate in the future, uncomment the relevant location block in the nginx config and run:
+
+```shell
+sudo certbot certonly --email <your@emailaddress> -d <yourdomain> --webroot -w /var/lib/letsencrypt/
+```
+
+#### Other webserver/proxies
+
+You can find example configurations for them in `/opt/pleroma/installation/`.
+
+#### Systemd service
+
+* Copy example service file
+
+```shell
+sudo cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service
+```
+
+* Edit the service file and make sure that all paths fit your installation
+* Enable and start `pleroma.service`:
+
+```shell
+sudo systemctl enable --now pleroma.service
+```
+
+#### Create your first user
+
+If your instance is up and running, you can create your first user with administrative rights with the following task:
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new <username> <your@emailaddress> --admin
+```
+
+#### Further reading
+
+* [Admin tasks](Admin tasks)
+* [Backup your instance](Backup-your-instance)
+* [Configuration tips](General tips for customizing pleroma fe)
+* [Hardening your instance](Hardening-your-instance)
+* [How to activate mediaproxy](How-to-activate-mediaproxy)
+* [Small Pleroma-FE customizations](Small customizations)
+* [Updating your instance](Updating-your-instance)
+
+## Questions
+
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
diff --git a/docs/installation/debian_based_en.md b/docs/installation/debian_based_en.md
new file mode 100644 (file)
index 0000000..9613a32
--- /dev/null
@@ -0,0 +1,202 @@
+# Installing on Debian Based Distributions
+## Installation
+
+This guide will assume you are on Debian Stretch. This guide should also work with Ubuntu 16.04 and 18.04. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.
+
+### Required packages
+
+* `postgresql` (9.6+, Ubuntu 16.04 comes with 9.5, you can get a newer version from [here](https://www.postgresql.org/download/linux/ubuntu/))
+* `postgresql-contrib` (9.6+, same situtation as above)
+* `elixir` (1.5+, [install from here, Debian and Ubuntu ship older versions](https://elixir-lang.org/install.html#unix-and-unix-like) or use [asdf](https://github.com/asdf-vm/asdf) as the pleroma user)
+* `erlang-dev`
+* `erlang-tools`
+* `erlang-parsetools`
+* `erlang-eldap`, if you want to enable ldap authenticator
+* `erlang-xmerl`
+* `git`
+* `build-essential`
+
+#### Optional packages used in this guide
+
+* `nginx` (preferred, example configs for other reverse proxies can be found in the repo)
+* `certbot` (or any other ACME client for Let’s Encrypt certificates)
+
+### Prepare the system
+
+* First update the system, if not already done:
+
+```shell
+sudo apt update
+sudo apt full-upgrade
+```
+
+* Install some of the above mentioned programs:
+
+```shell
+sudo apt install git build-essential postgresql postgresql-contrib
+```
+
+### Install Elixir and Erlang
+
+* Download and add the Erlang repository:
+
+```shell
+wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
+sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb
+```
+
+* Install Elixir and Erlang:
+
+```shell
+sudo apt update
+sudo apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools
+```
+
+### Install PleromaBE
+
+* Add a new system user for the Pleroma service:
+
+```shell
+sudo useradd -r -s /bin/false -m -d /var/lib/pleroma -U pleroma
+```
+
+**Note**: To execute a single command as the Pleroma system user, use `sudo -Hu pleroma command`. You can also switch to a shell by using `sudo -Hu pleroma $SHELL`. If you don’t have and want `sudo` on your system, you can use `su` as root user (UID 0) for a single command by using `su -l pleroma -s $SHELL -c 'command'` and `su -l pleroma -s $SHELL` for starting a shell.
+
+* Git clone the PleromaBE repository and make the Pleroma user the owner of the directory:
+
+```shell
+sudo mkdir -p /opt/pleroma
+sudo chown -R pleroma:pleroma /opt/pleroma
+sudo -Hu pleroma git clone https://git.pleroma.social/pleroma/pleroma /opt/pleroma
+```
+
+* Change to the new directory:
+
+```shell
+cd /opt/pleroma
+```
+
+* Install the dependencies for Pleroma and answer with `yes` if it asks you to install `Hex`:
+
+```shell
+sudo -Hu pleroma mix deps.get
+```
+
+* Generate the configuration: `sudo -Hu pleroma mix pleroma.instance gen`
+  * Answer with `yes` if it asks you to install `rebar3`.
+  * This may take some time, because parts of pleroma get compiled first.
+  * After that it will ask you a few questions about your instance and generates a configuration file in `config/generated_config.exs`.
+
+* Check the configuration and if all looks right, rename it, so Pleroma will load it (`prod.secret.exs` for productive instance, `dev.secret.exs` for development instances):
+
+```shell
+mv config/{generated_config.exs,prod.secret.exs}
+```
+
+* The previous command creates also the file `config/setup_db.psql`, with which you can create the database:
+
+```shell
+sudo -Hu postgres psql -f config/setup_db.psql
+```
+
+* Now run the database migration:
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix ecto.migrate
+```
+
+* Now you can start Pleroma already
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix phx.server
+```
+
+### Finalize installation
+
+If you want to open your newly installed instance to the world, you should run nginx or some other webserver/proxy in front of Pleroma and you should consider to create a systemd service file for Pleroma.
+
+#### Nginx
+
+* Install nginx, if not already done:
+
+```shell
+sudo apt install nginx
+```
+
+* Setup your SSL cert, using your method of choice or certbot. If using certbot, first install it:
+
+```shell
+sudo apt install certbot
+```
+
+and then set it up:
+
+```shell
+sudo mkdir -p /var/lib/letsencrypt/
+sudo certbot certonly --email <your@emailaddress> -d <yourdomain> --standalone
+```
+
+If that doesn’t work, make sure, that nginx is not already running. If it still doesn’t work, try setting up nginx first (change ssl “on” to “off” and try again).
+
+---
+
+* Copy the example nginx configuration and activate it:
+
+```shell
+sudo cp /opt/pleroma/installation/pleroma.nginx /etc/nginx/sites-available/pleroma.nginx
+sudo ln -s /etc/nginx/sites-available/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx
+```
+
+* Before starting nginx edit the configuration and change it to your needs (e.g. change servername, change cert paths)
+* Enable and start nginx:
+
+```shell
+sudo systemctl enable --now nginx.service
+```
+
+If you need to renew the certificate in the future, uncomment the relevant location block in the nginx config and run:
+
+```shell
+sudo certbot certonly --email <your@emailaddress> -d <yourdomain> --webroot -w /var/lib/letsencrypt/
+```
+
+#### Other webserver/proxies
+
+You can find example configurations for them in `/opt/pleroma/installation/`.
+
+#### Systemd service
+
+* Copy example service file
+
+```shell
+sudo cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.service
+```
+
+* Edit the service file and make sure that all paths fit your installation
+* Enable and start `pleroma.service`:
+
+```shell
+sudo systemctl enable --now pleroma.service
+```
+
+#### Create your first user
+
+If your instance is up and running, you can create your first user with administrative rights with the following task:
+
+```shell
+sudo -Hu pleroma MIX_ENV=prod mix pleroma.user new <username> <your@emailaddress> --admin
+```
+
+#### Further reading
+
+* [Admin tasks](Admin tasks)
+* [Backup your instance](Backup-your-instance)
+* [Configuration tips](General tips for customizing pleroma fe)
+* [Hardening your instance](Hardening-your-instance)
+* [How to activate mediaproxy](How-to-activate-mediaproxy)
+* [Small Pleroma-FE customizations](Small customizations)
+* [Updating your instance](Updating-your-instance)
+
+## Questions
+
+Questions about the installation or didn’t it work as it should be, ask in [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org) or IRC Channel **#pleroma** on **Freenode**.
diff --git a/docs/installation/debian_based_jp.md b/docs/installation/debian_based_jp.md
new file mode 100644 (file)
index 0000000..ac5dcaa
--- /dev/null
@@ -0,0 +1,191 @@
+# Pleromaの入れ方
+## 日本語訳について
+
+この記事は [Installing on Debian based distributions](Installing on Debian based distributions) の日本語訳です。何かがおかしいと思ったら、原文を見てください。
+
+## インストール
+
+このガイドはDebian Stretchを仮定しています。Ubuntu 16.04でも可能です。
+
+### 必要なソフトウェア
+
+- PostgreSQL 9.6+ (postgresql-contrib-9.6 または他のバージョンの PSQL をインストールしてください)
+- Elixir 1.5 以上 ([Debianのリポジトリからインストールしないこと!!! ここからインストールすること!](https://elixir-lang.org/install.html#unix-and-unix-like))。または [asdf](https://github.com/asdf-vm/asdf) を pleroma ユーザーでインストール。
+- erlang-dev
+- erlang-tools
+- erlang-parsetools
+- erlang-xmerl (Jessieではバックポートからインストールすること!)
+- git
+- build-essential
+- openssh
+- openssl
+- nginx prefered (Apacheも動くかもしれませんが、誰もテストしていません!)
+- certbot (または何らかのACME Let's encryptクライアント)
+
+### システムを準備する
+
+* まずシステムをアップデートしてください。
+```
+apt update && apt dist-upgrade
+```
+
+* 複数のツールとpostgresqlをインストールします。あとで必要になるので。
+```
+apt install git build-essential openssl ssh sudo postgresql-9.6 postgresql-contrib-9.6
+```
+(postgresqlのバージョンは、あなたのディストロにあわせて変えてください。または、バージョン番号がいらないかもしれません。)
+
+### ElixirとErlangをインストールします
+
+* Erlangのリポジトリをダウンロードおよびインストールします。
+```
+wget -P /tmp/ https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i /tmp/erlang-solutions_1.0_all.deb
+```
+
+* ElixirとErlangをインストールします、
+```
+apt update && apt install elixir erlang-dev erlang-parsetools erlang-xmerl erlang-tools
+```
+
+### Pleroma BE (バックエンド) をインストールします
+
+*  新しいユーザーを作ります。
+```
+adduser pleroma
+``` 
+(Give it any password you want, make it STRONG)
+
+*  新しいユーザーをsudoグループに入れます。
+```
+usermod -aG sudo pleroma
+```
+
+*  新しいユーザーに変身し、ホームディレクトリに移動します。
+```
+su pleroma
+cd ~
+```
+
+*  Gitリポジトリをクローンします。
+```
+git clone https://git.pleroma.social/pleroma/pleroma
+```
+
+*  新しいディレクトリに移動します。
+```
+cd pleroma/
+```
+
+* Pleromaが依存するパッケージをインストールします。Hexをインストールしてもよいか聞かれたら、yesを入力してください。
+```
+mix deps.get
+```
+
+* コンフィギュレーションを生成します。
+```
+mix pleroma.instance gen
+```
+    * rebar3をインストールしてもよいか聞かれたら、yesを入力してください。
+    * この処理には時間がかかります。私もよく分かりませんが、何らかのコンパイルが行われているようです。
+    * あなたのインスタンスについて、いくつかの質問があります。その回答は `config/generated_config.exs` というコンフィギュレーションファイルに保存されます。
+
+**注意**: メディアプロクシを有効にすると回答して、なおかつ、キャッシュのURLは空欄のままにしている場合は、`generated_config.exs` を編集して、`base_url` で始まる行をコメントアウトまたは削除してください。そして、上にある行の `true` の後にあるコンマを消してください。
+
+* コンフィギュレーションを確認して、もし問題なければ、ファイル名を変更してください。
+```
+mv config/{generated_config.exs,prod.secret.exs}
+```
+
+* これまでのコマンドで、すでに `config/setup_db.psql` というファイルが作られています。このファイルをもとに、データベースを作成します。
+```
+sudo su postgres -c 'psql -f config/setup_db.psql'
+```
+
+* そして、データベースのミグレーションを実行します。
+```
+MIX_ENV=prod mix ecto.migrate
+```
+
+* Pleromaを起動できるようになりました。
+```
+MIX_ENV=prod mix phx.server
+```
+
+### インストールを終わらせる
+
+あなたの新しいインスタンスを世界に向けて公開するには、nginxまたは何らかのウェブサーバー (プロクシ) を使用する必要があります。また、Pleroma のためにシステムサービスファイルを作成する必要があります。
+
+#### Nginx
+
+* まだインストールしていないなら、nginxをインストールします。
+```
+apt install nginx
+```
+
+* SSLをセットアップします。他の方法でもよいですが、ここではcertbotを説明します。
+certbotを使うならば、まずそれをインストールします。
+```
+apt install certbot
+```
+そしてセットアップします。
+```
+mkdir -p /var/lib/letsencrypt/.well-known
+% certbot certonly --email your@emailaddress --webroot -w /var/lib/letsencrypt/ -d yourdomain
+```
+もしうまくいかないときは、先にnginxを設定してください。ssl "on" を "off" に変えてから再試行してください。
+
+---
+
+* nginxコンフィギュレーションの例をnginxフォルダーにコピーします。
+```
+cp /home/pleroma/pleroma/installation/pleroma.nginx /etc/nginx/sites-enabled/pleroma.nginx
+```
+
+* nginxを起動する前に、コンフィギュレーションを編集してください。例えば、サーバー名、証明書のパスなどを変更する必要があります。
+* nginxを再起動します。
+```
+systemctl reload nginx.service
+```
+
+#### Systemd サービス
+
+* サービスファイルの例をコピーします。
+```
+cp /home/pleroma/pleroma/installation/pleroma.service /usr/lib/systemd/system/pleroma.service
+```
+
+* サービスファイルを変更します。すべてのパスが正しいことを確認してください。また、`[Service]` セクションに以下の行があることを確認してください。
+```
+Environment="MIX_ENV=prod"
+```
+
+* `pleroma.service` を enable および start してください。
+```
+systemctl enable --now pleroma.service
+```
+
+#### モデレーターを作る
+
+新たにユーザーを作ったら、モデレーター権限を与えたいかもしれません。以下のタスクで可能です。
+```
+mix set_moderator username [true|false]
+```
+
+モデレーターはすべてのポストを消すことができます。将来的には他のことも可能になるかもしれません。
+
+#### メディアプロクシを有効にする
+
+`generate_config` でメディアプロクシを有効にしているなら、すでにメディアプロクシが動作しています。あとから設定を変更したいなら、[How to activate mediaproxy](How-to-activate-mediaproxy) を見てください。
+
+#### コンフィギュレーションとカスタマイズ
+
+* [Configuration tips](General tips for customizing pleroma fe)
+* [Small Pleroma-FE customizations](Small customizations)
+* [Admin tasks](Admin tasks)
+
+## 質問ある?
+
+インストールについて質問がある、もしくは、うまくいかないときは、以下のところで質問できます。
+
+* [#pleroma:matrix.org](https://matrix.heldscal.la/#/room/#freenode_#pleroma:matrix.org)
+* **Freenode** の **#pleroma** IRCチャンネル
diff --git a/docs/installation/netbsd_en.md b/docs/installation/netbsd_en.md
new file mode 100644 (file)
index 0000000..e0ac983
--- /dev/null
@@ -0,0 +1,198 @@
+# Installing on NetBSD
+
+## Required software 
+
+pkgin should have been installed by the NetBSD installer if you selected
+the right options. If it isn't installed, install it using pkg_add.
+
+Note that `postgresql11-contrib` is needed for the Postgres extensions
+Pleroma uses.
+
+The `mksh` shell is needed to run the Elixir `mix` script.
+
+`# pkgin install acmesh elixir git-base git-docs mksh nginx postgresql11-server postgresql11-client postgresql11-contrib sudo`
+
+You can also build these packages using pkgsrc:
+```
+databases/postgresql11-contrib
+databases/postgresql11-client
+databases/postgresql11-server
+devel/git-base
+devel/git-docs
+lang/elixir
+security/acmesh
+security/sudo
+shells/mksh
+www/nginx
+```
+
+Copy the rc.d scripts to the right directory:
+
+```
+# cp /usr/pkg/share/examples/rc.d/nginx /usr/pkg/share/examples/rc.d/pgsql /etc/rc.d
+```
+
+Add nginx and Postgres to `/etc/rc.conf`:
+
+```
+nginx=YES
+pgsql=YES
+```
+
+## Configuring postgres
+
+First, run `# /etc/rc.d/pgsql start`. Then, `$ sudo -Hu pgsql -g pgsql createdb`.
+
+## Configuring Pleroma
+
+Create a user for Pleroma:
+
+```
+# groupadd pleroma
+# useradd -d /home/pleroma -m -g pleroma -s /usr/pkg/bin/mksh pleroma
+# echo 'export LC_ALL="en_GB.UTF-8"' >> /home/pleroma/.profile
+# su -l pleroma -c $SHELL
+```
+
+Clone the repository:
+
+```
+$ cd /home/pleroma
+$ git clone https://git.pleroma.social/pleroma/pleroma.git
+```
+
+Configure Pleroma. Note that you need a domain name at this point:
+
+```
+$ cd /home/pleroma/pleroma
+$ mix deps.get
+$ mix pleroma.instance gen # You will be asked a few questions here.
+```
+
+Since Postgres is configured, we can now initialize the database. There should
+now be a file in `config/setup_db.psql` that makes this easier. Edit it, and
+*change the password* to a password of your choice. Make sure it is secure, since
+it'll be protecting your database. Now initialize the database:
+
+```
+$ sudo -Hu pgsql -g pgsql psql -f config/setup_db.psql
+```
+
+Postgres allows connections from all users without a password by default. To
+fix this, edit `/usr/pkg/pgsql/data/pg_hba.conf`. Change every `trust` to
+`password`.
+
+Once this is done, restart Postgres with `# /etc/rc.d/pgsql restart`.
+
+Run the database migrations.
+You will need to do this whenever you update with `git pull`:
+
+```
+$ MIX_ENV=prod mix ecto.migrate
+```
+
+## Configuring nginx
+
+Install the example configuration file
+`/home/pleroma/pleroma/installation/pleroma.nginx` to
+`/usr/pkg/etc/nginx.conf`.
+
+Note that it will need to be wrapped in a `http {}` block. You should add
+settings for the nginx daemon outside of the http block, for example:
+
+```
+user                    nginx  nginx;
+error_log               /var/log/nginx/error.log;
+worker_processes        4;
+
+events {
+}
+```
+
+Edit the defaults:
+
+* Change `ssl_certificate` and `ssl_trusted_certificate` to
+`/etc/nginx/tls/fullchain`.
+* Change `ssl_certificate_key` to `/etc/nginx/tls/key`.
+* Change `example.tld` to your instance's domain name.
+
+## Configuring acme.sh
+
+We'll be using acme.sh in Stateless Mode for TLS certificate renewal.
+
+First, get your account fingerprint:
+
+```
+$ sudo -Hu nginx -g nginx acme.sh --register-account
+```
+
+You need to add the following to your nginx configuration for the server
+running on port 80:
+
+```
+  location ~ ^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)$ {
+    default_type text/plain;
+    return 200 "$1.6fXAG9VyG0IahirPEU2ZerUtItW2DHzDzD9wZaEKpqd";
+  }
+```
+
+Replace the string after after `$1.` with your fingerprint.
+
+Start nginx:
+
+```
+# /etc/rc.d/nginx start
+```
+
+It should now be possible to issue a cert (replace `example.com`
+with your domain name):
+
+```
+$ sudo -Hu nginx -g nginx acme.sh --issue -d example.com --stateless
+```
+
+Let's add auto-renewal to `/etc/daily.local`
+(replace `example.com` with your domain):
+
+```
+/usr/pkg/bin/sudo -Hu nginx -g nginx \
+    /usr/pkg/sbin/acme.sh -r \
+    -d example.com \
+    --cert-file /etc/nginx/tls/cert \
+    --key-file /etc/nginx/tls/key \
+    --ca-file /etc/nginx/tls/ca \
+    --fullchain-file /etc/nginx/tls/fullchain \
+    --stateless
+```
+
+## Creating a startup script for Pleroma
+
+Copy the startup script to the correct location and make sure it's executable:
+
+```
+# cp /home/pleroma/pleroma/installation/netbsd/rc.d/pleroma /etc/rc.d/pleroma
+# chmod +x /etc/rc.d/pleroma
+```
+
+Add the following to `/etc/rc.conf`:
+
+```
+pleroma=YES
+pleroma_home="/home/pleroma"
+pleroma_user="pleroma"
+```
+
+Run `# /etc/rc.d/pleroma start` to start Pleroma.
+
+## Conclusion
+
+Restart nginx with `# /etc/rc.d/nginx restart` and you should be up and running.
+
+If you need further help, contact niaa on freenode.
+
+Make sure your time is in sync, or other instances will receive your posts with
+incorrect timestamps. You should have ntpd running.
+
+## Instances running NetBSD
+
+* <https://catgirl.science>
diff --git a/docs/installation/openbsd_en.md b/docs/installation/openbsd_en.md
new file mode 100644 (file)
index 0000000..633b08e
--- /dev/null
@@ -0,0 +1,222 @@
+# Installing on OpenBSD
+This guide describes the installation and configuration of pleroma (and the required software to run it) on a single OpenBSD 6.4 server.
+For any additional information regarding commands and configuration files mentioned here, check the man pages [online](https://man.openbsd.org/) or directly on your server with the man command.
+
+#### Required software
+The following packages need to be installed:
+  * elixir
+  * gmake
+  * ImageMagick
+  * git
+  * postgresql-server
+  * postgresql-contrib
+
+To install them, run the following command (with doas or as root):  
+`pkg_add elixir gmake ImageMagick git postgresql-server postgresql-contrib`
+
+Pleroma requires a reverse proxy, OpenBSD has relayd in base (and is used in this guide) and packages/ports are available for nginx (www/nginx) and apache (www/apache-httpd). Independently of the reverse proxy, [acme-client(1)](https://man.openbsd.org/acme-client) can be used to get a certificate from Let's Encrypt.
+
+#### Creating the pleroma user
+Pleroma will be run by a dedicated user, \_pleroma. Before creating it, insert the following lines in login.conf:
+```
+pleroma:\
+       :datasize-max=1536M:\
+       :datasize-cur=1536M:\
+       :openfiles-max=4096
+```
+This creates a "pleroma" login class and sets higher values than default for datasize and openfiles (see [login.conf(5)](https://man.openbsd.org/login.conf)), this is required to avoid having pleroma crash some time after starting.
+
+Create the \_pleroma user, assign it the pleroma login class and create its home directory (/home/\_pleroma/): `useradd -m -L pleroma _pleroma`
+
+#### Clone pleroma's directory
+Enter a shell as the \_pleroma user. As root, run `su _pleroma -;cd`. Then clone the repository with `git clone https://git.pleroma.social/pleroma/pleroma.git`. Pleroma is now installed in /home/\_pleroma/pleroma/, it will be configured and started at the end of this guide.
+
+#### Postgresql
+Start a shell as the \_postgresql user (as root run `su _postgresql -` then run the `initdb` command to initialize postgresql:  
+If you wish to not use the default location for postgresql's data (/var/postgresql/data), add the following switch at the end of the command: `-D <path>` and modify the `datadir` variable in the /etc/rc.d/postgresql script.
+
+When this is done, enable postgresql so that it starts on boot and start it. As root, run:
+```
+rcctl enable postgresql
+rcctl start postgresql
+```
+To check that it started properly and didn't fail right after starting, you can run `ps aux | grep postgres`, there should be multiple lines of output.
+
+#### httpd
+httpd will have three fuctions:
+  * redirect requests trying to reach the instance over http to the https URL
+  * serve a robots.txt file
+  * get Let's Encrypt certificates, with acme-client
+
+Insert the following config in httpd.conf:
+```
+# $OpenBSD: httpd.conf,v 1.17 2017/04/16 08:50:49 ajacoutot Exp $
+
+ext_inet="<IPv4 address>"
+ext_inet6="<IPv6 address>"
+
+server "default" {
+       listen on $ext_inet port 80 # Comment to disable listening on IPv4
+       listen on $ext_inet6 port 80 # Comment to disable listening on IPv6
+       listen on 127.0.0.1 port 80 # Do NOT comment this line
+
+       log syslog
+       directory no index
+
+       location "/.well-known/acme-challenge/*" {
+               root "/acme"
+               request strip 2
+       }
+
+       location "/robots.txt" { root "/htdocs/local/" }
+       location "/*" { block return 302 "https://$HTTP_HOST$REQUEST_URI" }
+}
+
+types {
+       include "/usr/share/misc/mime.types"
+}
+```
+Do not forget to change *\<IPv4/6 address\>* to your server's address(es). If httpd should only listen on one protocol family, comment one of the two first *listen* options.
+
+Create the /var/www/htdocs/local/ folder and write the content of your robots.txt in /var/www/htdocs/local/robots.txt.  
+Check the configuration with `httpd -n`, if it is OK enable and start httpd (as root):
+```
+rcctl enable httpd
+rcctl start httpd
+```
+
+#### acme-client
+acme-client is used to get SSL/TLS certificates from Let's Encrypt. 
+Insert the following configuration in /etc/acme-client.conf:
+```
+#
+# $OpenBSD: acme-client.conf,v 1.4 2017/03/22 11:14:14 benno Exp $
+#
+
+authority letsencrypt-<domain name> {
+       #agreement url "https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf"
+       api url "https://acme-v01.api.letsencrypt.org/directory"
+       account key "/etc/acme/letsencrypt-privkey-<domain name>.pem"
+}
+
+domain <domain name> {
+       domain key "/etc/ssl/private/<domain name>.key"
+       domain certificate "/etc/ssl/<domain name>.crt"
+       domain full chain certificate "/etc/ssl/<domain name>.fullchain.pem"
+       sign with letsencrypt-<domain name>
+       challengedir "/var/www/acme/"
+}
+```
+Replace *\<domain name\>* by the domain name you'll use for your instance. As root, run `acme-client -n` to check the config, then `acme-client -ADv <domain name>` to create account and domain keys, and request a certificate for the first time.  
+Make acme-client run everyday by adding it in /etc/daily.local. As root, run the following command: `echo "acme-client <domain name>" >> /etc/daily.local`.
+
+Relayd will look for certificates and keys based on the address it listens on (see next part), the easiest way to make them available to relayd is to create a link, as root run:
+```
+ln -s /etc/ssl/<domain name>.fullchain.pem /etc/ssl/<IP address>.crt
+ln -s /etc/ssl/private/<domain name>.key /etc/ssl/private/<IP address>.key
+```
+This will have to be done for each IPv4 and IPv6 address relayd listens on.
+
+#### relayd
+relayd will be used as the reverse proxy sitting in front of pleroma. 
+Insert the following configuration in /etc/relayd.conf:
+```
+# $OpenBSD: relayd.conf,v 1.4 2018/03/23 09:55:06 claudio Exp $
+
+ext_inet="<IPv4 address>"
+ext_inet6="<IPv6 address>"
+
+table <pleroma_server> { 127.0.0.1 }
+table <httpd_server> { 127.0.0.1 }
+
+http protocol plerup { # Protocol for upstream pleroma server
+       #tcp { nodelay, sack, socket buffer 65536, backlog 128 } # Uncomment and adjust as you see fit
+       tls ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305"
+       tls ecdhe secp384r1
+
+       # Forward some paths to the local server (as pleroma won't respond to them as you might want)
+       pass request quick path "/robots.txt" forward to <httpd_server>
+
+       # Append a bunch of headers
+       match request header append "X-Forwarded-For" value "$REMOTE_ADDR" # This two header and the next one are not strictly required by pleroma but adding them won't hurt
+       match request header append "X-Forwarded-By" value "$SERVER_ADDR:$SERVER_PORT"
+
+       match response header append "X-XSS-Protection" value "1; mode=block"
+       match response header append "X-Permitted-Cross-Domain-Policies" value "none"
+       match response header append "X-Frame-Options" value "DENY"
+       match response header append "X-Content-Type-Options" value "nosniff"
+       match response header append "Referrer-Policy" value "same-origin"
+       match response header append "X-Download-Options" value "noopen"
+       match response header append "Content-Security-Policy" value "default-src 'none'; base-uri 'self'; form-action 'self'; img-src 'self' data: https:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; script-src 'self'; connect-src 'self' wss://CHANGEME.tld; upgrade-insecure-requests;" # Modify "CHANGEME.tld" and set your instance's domain here
+       match request header append "Connection" value "upgrade"
+       #match response header append "Strict-Transport-Security" value "max-age=31536000; includeSubDomains" # Uncomment this only after you get HTTPS working.
+
+       # If you do not want remote frontends to be able to access your Pleroma backend server, comment these lines
+       match response header append "Access-Control-Allow-Origin" value "*"
+       match response header append "Access-Control-Allow-Methods" value "POST, PUT, DELETE, GET, PATCH, OPTIONS"
+       match response header append "Access-Control-Allow-Headers" value "Authorization, Content-Type, Idempotency-Key"
+       match response header append "Access-Control-Expose-Headers" value "Link, X-RateLimit-Reset, X-RateLimit-Limit, X-RateLimit-Remaining, X-Request-Id"
+       # Stop commenting lines here
+}
+
+relay wwwtls {
+       listen on $ext_inet port https tls # Comment to disable listening on IPv4
+       listen on $ext_inet6 port https tls # Comment to disable listening on IPv6
+
+       protocol plerup
+
+       forward to <pleroma_server> port 4000 check http "/" code 200
+       forward to <httpd_server> port 80 check http "/robots.txt" code 200
+}
+```
+Again, change *\<IPv4/6 address\>* to your server's address(es) and comment one of the two *listen* options if needed. Also change *wss://CHANGEME.tld* to *wss://\<your instance's domain name\>*.  
+Check the configuration with `relayd -n`, if it is OK enable and start relayd (as root):
+```
+rcctl enable relayd
+rcctl start relayd
+```
+
+#### pf
+Enabling and configuring pf is highly recommended.  
+In /etc/pf.conf, insert the following configuration:
+```
+# Macros
+if="<network interface>"
+authorized_ssh_clients="any"
+
+# Skip traffic on loopback interface
+set skip on lo
+
+# Default behavior
+set block-policy drop
+block in log all
+pass out quick
+
+# Security features
+match in all scrub (no-df random-id)
+block in log from urpf-failed
+
+# Rules
+pass in quick on $if inet proto icmp to ($if) icmp-type { echoreq unreach paramprob trace } # ICMP
+pass in quick on $if inet6 proto icmp6 to ($if) icmp6-type { echoreq unreach paramprob timex toobig } # ICMPv6
+pass in quick on $if proto tcp to ($if) port { http https } # relayd/httpd
+pass in quick on $if proto tcp from $authorized_ssh_clients to ($if) port ssh
+```
+Replace *\<network interface\>* by your server's network interface name (which you can get with ifconfig). Consider replacing the content of the authorized\_ssh\_clients macro by, for exemple, your home IP address, to avoid SSH connection attempts from bots.
+
+Check pf's configuration by running `pfctl -nf /etc/pf.conf`, load it with `pfctl -f /etc/pf.conf` and enable pf at boot with `rcctl enable pf`.
+
+#### Configure and start pleroma
+Enter a shell as \_pleroma (as root `su _pleroma -`) and enter pleroma's installation directory (`cd ~/pleroma/`).  
+Then follow the main installation guide:
+  * run `mix deps.get`
+  * run `mix pleroma.instance gen` and enter your instance's information when asked
+  * copy config/generated\_config.exs to config/prod.secret.exs. The default values should be sufficient but you should edit it and check that everything seems OK.
+  * exit your current shell back to a root one and run `psql -U postgres -f /home/_pleroma/config/setup_db.psql` to setup the database.
+  * return to a \_pleroma shell into pleroma's installation directory (`su _pleroma -;cd ~/pleroma`) and run `MIX_ENV=prod mix ecto.migrate`
+
+As \_pleroma in /home/\_pleroma/pleroma, you can now run `LC_ALL=en_US.UTF-8 MIX_ENV=prod mix phx.server` to start your instance.  
+In another SSH session/tmux window, check that it is working properly by running `ftp -MVo - http://127.0.0.1:4000/api/v1/instance`, you should get json output. Double-check that *uri*'s value is your instance's domain name.
+
+##### Starting pleroma at boot
+An rc script to automatically start pleroma at boot hasn't been written yet, it can be run in a tmux session (tmux is in base).
diff --git a/docs/installation/openbsd_fi.md b/docs/installation/openbsd_fi.md
new file mode 100644 (file)
index 0000000..fa6faa6
--- /dev/null
@@ -0,0 +1,110 @@
+# Pleroman asennus OpenBSD:llä
+
+Tarvitset:
+* Oman domainin
+* OpenBSD 6.3 -serverin
+* Auttavan ymmärryksen unix-järjestelmistä
+
+Komennot, joiden edessä on '#', tulee ajaa käyttäjänä `root`. Tämä on
+suositeltavaa tehdä komennon `doas` avulla, katso `doas (1)` ja `doas.conf (5)`.
+Tästä eteenpäin oletuksena on, että domain "esimerkki.com" osoittaa
+serverin IP-osoitteeseen.
+
+Jos asennuksen kanssa on ongelmia, IRC-kanava #pleroma Freenodessa tai
+Matrix-kanava #freenode_#pleroma:matrix.org ovat hyviä paikkoja löytää apua
+(englanniksi), `/msg eal kukkuu` jos haluat välttämättä puhua härmää.
+
+Asenna tarvittava ohjelmisto:
+
+`# pkg_add git elixir gmake postgresql-server-10.3 postgresql-contrib-10.3`
+
+Luo postgresql-tietokanta:
+
+`# su - _postgresql`
+
+`$ mkdir /var/postgresql/data`
+
+`$ initdb -D /var/postgresql/data -E UTF8`
+
+`$ createdb`
+
+Käynnistä tietokanta ja aseta se käynnistymään automaattisesti.
+
+`# rcctl start postgresql`
+
+`# rcctl enable postgresql`
+
+Luo käyttäjä pleromaa varten (kysyy muutaman kysymyksen):
+
+`# adduser pleroma`
+
+Vaihda pleroma-käyttäjään ja mene kotihakemistoosi:
+
+`# su - pleroma`
+
+Lataa pleroman lähdekoodi:
+
+`$ git clone https://git.pleroma.social/pleroma/pleroma.git`
+
+`$ cd pleroma`
+
+Asenna tarvittavat elixir-kirjastot:
+
+`$ mix deps.get`
+
+`$ mix deps.compile`
+
+Luo tarvittava konfiguraatio:
+
+`$ mix generate_config`
+
+`$ cp config/generated_config.exs config/prod.secret.exs`
+
+Aja luodut tietokantakomennot:
+
+`# su _postgres -c 'psql -f config/setup_db.psql'`
+
+`$ MIX_ENV=prod mix ecto.migrate`
+
+Käynnistä pleroma-prosessi:
+
+`$ MIX_ENV=prod mix compile`
+
+`$ MIX_ENV=prod mix phx.server`
+
+Tässä vaiheessa on hyvä tarkistaa että asetukset ovat oikein. Avaa selaimella,
+curlilla tai vastaavalla työkalulla `esimerkki.com:4000/api/v1/instance` ja katso
+että kohta "uri" on "https://esimerkki.com".
+
+Huom! Muista varmistaa että muuttuja MIX_ENV on "prod" mix-komentoja ajaessasi.
+Mix lukee oikean konfiguraatiotiedoston sen mukaisesti.
+
+Ohessa enimmäkseen toimivaksi todettu rc.d-skripti pleroman käynnistämiseen.
+Kirjoita se tiedostoon /etc/rc.d/pleroma. Tämän jälkeen aja
+`# chmod +x /etc/rc.d/pleroma`, ja voit käynnistää pleroman komennolla
+`# /etc/rc.d/pleroma start`.
+
+```
+#!/bin/ksh
+#/etc/rc.d/pleroma
+
+daemon="cd /home/pleroma/pleroma;MIX_ENV=prod /usr/local/bin/elixir"
+daemon_flags="--detached /usr/local/bin/mix phx.server"
+daemon_user="pleroma"
+rc_reload="NO"
+rc_bg="YES"
+
+pexp="beam"
+
+. /etc/rc.d/rc.subr
+
+rc_cmd $1
+```
+
+Tämän jälkeen tarvitset enää HTTP-serverin välittämään kutsut pleroma-prosessille.
+Tiedostosta `install/pleroma.nginx` löytyy esimerkkikonfiguraatio, ja TLS-sertifikaatit
+saat ilmaiseksi esimerkiksi [letsencryptiltä](https://certbot.eff.org/lets-encrypt/opbsd-nginx.html).
+Nginx asentuu yksinkertaisesti komennolla `# pkg_add nginx`.
+
+Kun olet valmis, avaa https://esimerkki.com selaimessasi. Luo käyttäjä ja seuraa kiinnostavia
+tyyppejä muilla palvelimilla!
diff --git a/docs/introduction.md b/docs/introduction.md
new file mode 100644 (file)
index 0000000..4af0747
--- /dev/null
@@ -0,0 +1,55 @@
+# Introduction to Pleroma
+## What is Pleroma?
+Pleroma is a federated social networking platform, compatible with GNU social, Mastodon and other OStatus and ActivityPub implementations. It is free software licensed under the AGPLv3.  
+It actually consists of two components: a backend, named simply Pleroma, and a user-facing frontend, named Pleroma-FE. It also includes the Mastodon frontend, if that's your thing.  
+It's part of what we call the fediverse, a federated network of instances which speak common protocols and can communicate with each other.  
+One account on a instance is enough to talk to the entire fediverse!
+  
+## How can I use it?
+
+Pleroma instances are already widely deployed, a list can be found here:  
+http://distsn.org/pleroma-instances.html
+
+If you don't feel like joining an existing instance, but instead prefer to deploy your own instance, that's easy too!  
+Installation instructions can be found here:  
+[main Pleroma wiki](/)
+  
+## I got an account, now what?
+Great! Now you can explore the fediverse!  
+- Open the login page for your Pleroma instance (for ex. https://pleroma.soykaf.com) and login with your username and password.  
+(If you don't have one yet, click on Register) :slightly_smiling_face:  
+
+At this point you will have two columns in front of you.
+
+### Left column
+- first block: here you can see your avatar, your nickname a bio, and statistics (Statuses, Following, Followers).  
+Under that you have a text form which allows you to post new statuses. The icon on the left is for uploading media files and attach them to your post. The number under the text form is a character counter, every instance can have a different character limit (the default is 5000).  
+If you want to mention someone, type @ + name of the person. A drop-down menu will help you in finding the right person. :slight_smile:   
+To post your status, simply press Submit.
+
+- second block: Here you can switch between the different timelines:
+  - Timeline: all the people that you follow
+  - Mentions: all the statutes where you are mentioned
+  - Public Timeline: all the statutes from the local instance
+  - The Whole Known Network: everything, local and remote!
+
+- third block: this is the Chat block, where you communicate with people on the same instance in realtime. It is local-only, for now, but we're planning to make it extendable to the entire fediverse! :sweat_smile:
+
+- fourth block: This is the Notifications block, here you will get notified whenever somebody mentions you, follows you, repeats or favorites one of your statuses.
+
+### Right column
+This is where the interesting stuff happens! :slight_smile:   
+Depending on the timeline you will see different statuses, but each status has a standard structure:
+- Icon + name + link to profile. An optional left-arrow if it's a reply to another status (hovering will reveal the replied-to status).
+- A + button on the right allows you to Expand/Collapse an entire discussion thread. It also updates in realtime!
+- A binocular icon allows you to open the status on the instance where it's originating from.
+- The text of the status, including mentions. If you click on a mention, it will automatically open the profile page of that person.
+- Four buttons (left to right): Reply, Repeat, Favorite, Delete.
+
+## Mastodon interface
+If the Pleroma interface isn't your thing, or you're just trying something new but you want to keep using the familiar Mastodon interface, we got that too! :smile:  
+Just add a "/web" after your instance url (for ex. https://pleroma.soycaf.com/web) and you'll end on the Mastodon web interface, but with a Pleroma backend! MAGIC! :fireworks:  
+For more information on the Mastodon interface, please look here:  
+https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md
+
+Remember, what you see is only the frontend part of Mastodon, the backend is still Pleroma.
index f6cca0d06e31c9bc26efdeef1a6b34a35600e1b5..0d0bea8c08a7333aad1edff65ef3a7c118df4a33 100644 (file)
@@ -6,7 +6,6 @@ defmodule Mix.Tasks.Pleroma.User do
   use Mix.Task
   import Ecto.Changeset
   alias Mix.Tasks.Pleroma.Common
-  alias Pleroma.Repo
   alias Pleroma.User
 
   @shortdoc "Manages Pleroma users"
@@ -23,7 +22,7 @@ defmodule Mix.Tasks.Pleroma.User do
   - `--password PASSWORD` - the user's password
   - `--moderator`/`--no-moderator` - whether the user is a moderator
   - `--admin`/`--no-admin` - whether the user is an admin
-  - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions 
+  - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions
 
   ## Generate an invite link.
 
@@ -33,6 +32,10 @@ defmodule Mix.Tasks.Pleroma.User do
 
       mix pleroma.user rm NICKNAME
 
+  ## Delete the user's activities.
+
+      mix pleroma.user delete_activities NICKNAME
+
   ## Deactivate or activate the user's account.
 
       mix pleroma.user toggle_activated NICKNAME
@@ -202,7 +205,7 @@ defmodule Mix.Tasks.Pleroma.User do
       {:ok, friends} = User.get_friends(user)
 
       Enum.each(friends, fn friend ->
-        user = Repo.get(User, user.id)
+        user = User.get_by_id(user.id)
 
         Mix.shell().info("Unsubscribing #{friend.nickname} from #{user.nickname}")
         User.unfollow(user, friend)
@@ -210,7 +213,7 @@ defmodule Mix.Tasks.Pleroma.User do
 
       :timer.sleep(500)
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
 
       if Enum.empty?(user.following) do
         Mix.shell().info("Successfully unsubscribed all followers from #{user.nickname}")
@@ -304,6 +307,18 @@ defmodule Mix.Tasks.Pleroma.User do
     end
   end
 
+  def run(["delete_activities", nickname]) do
+    Common.start_pleroma()
+
+    with %User{local: true} = user <- User.get_by_nickname(nickname) do
+      User.delete_user_activities(user)
+      Mix.shell().info("User #{nickname} statuses deleted.")
+    else
+      _ ->
+        Mix.shell().error("No local user #{nickname}")
+    end
+  end
+
   defp set_moderator(user, value) do
     info_cng = User.Info.admin_api_update(user.info, %{is_moderator: value})
 
index 772c239a1cc3afabed220d60513285219f9f1a3b..7afbc8751bd947e9be446db1d101801b7996643c 100644 (file)
@@ -39,7 +39,7 @@ defmodule Pleroma.PasswordResetToken do
 
   def reset_password(token, data) do
     with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
-         %User{} = user <- Repo.get(User, token.user_id),
+         %User{} = user <- User.get_by_id(token.user_id),
          {:ok, _user} <- User.reset_password(user, data),
          {:ok, token} <- Repo.update(used_changeset(token)) do
       {:ok, token}
index cc81e180565eb84ea0399692b5c48b5a4762c196..782d1d58997709635bb51099e8a6e6c982e869b4 100644 (file)
@@ -110,7 +110,6 @@ defmodule Pleroma.Application do
           worker(Pleroma.Web.Federator.RetryQueue, []),
           worker(Pleroma.Stats, []),
           worker(Pleroma.Web.Push, []),
-          worker(Pleroma.Jobs, []),
           worker(Task, [&Pleroma.Web.Federator.init/0], restart: :temporary)
         ] ++
         streamer_child() ++
index f7e3aa78b3ccc0f7b219dfbdce46d1019c5e482f..b384e6fecaff5fc0f5a050a551774342cc072c0a 100644 (file)
@@ -6,7 +6,7 @@ defmodule Pleroma.Mailer do
   use Swoosh.Mailer, otp_app: :pleroma
 
   def deliver_async(email, config \\ []) do
-    Pleroma.Jobs.enqueue(:mailer, __MODULE__, [:deliver_async, email, config])
+    PleromaJobQueue.enqueue(:mailer, __MODULE__, [:deliver_async, email, config])
   end
 
   def perform(:deliver_async, email, config), do: deliver(email, config)
index 4259d57189bec86d537a345c1b9d3036a86cbd07..58ab3650dc952de4465c30a77cbcf78f06b11e66 100644 (file)
@@ -46,7 +46,7 @@ defmodule Pleroma.FlakeId do
 
   def from_string(string) when is_binary(string) and byte_size(string) < 18 do
     case Integer.parse(string) do
-      {id, _} -> <<0::integer-size(64), id::integer-size(64)>>
+      {id, ""} -> <<0::integer-size(64), id::integer-size(64)>>
       _ -> nil
     end
   end
index 3b9629d77643a4fa3e3f9f817af76626aa4bb542..6a56a6f677c051debc6b8355b1fb442ef5e405b9 100644 (file)
@@ -38,7 +38,6 @@ end
 defmodule Pleroma.Gopher.Server.ProtocolHandler do
   alias Pleroma.Activity
   alias Pleroma.HTML
-  alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Visibility
@@ -111,7 +110,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
   end
 
   def response("/notices/" <> id) do
-    with %Activity{} = activity <- Repo.get(Activity, id),
+    with %Activity{} = activity <- Activity.get_by_id(id),
          true <- Visibility.is_public?(activity) do
       activities =
         ActivityPub.fetch_activities_for_context(activity.data["context"])
diff --git a/lib/pleroma/jobs.ex b/lib/pleroma/jobs.ex
deleted file mode 100644 (file)
index 24b7e5e..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Jobs do
-  @moduledoc """
-  A basic job queue
-  """
-  use GenServer
-
-  require Logger
-
-  def init(args) do
-    {:ok, args}
-  end
-
-  def start_link do
-    queues =
-      Pleroma.Config.get(Pleroma.Jobs)
-      |> Enum.map(fn {name, _} -> create_queue(name) end)
-      |> Enum.into(%{})
-
-    state = %{
-      queues: queues,
-      refs: %{}
-    }
-
-    GenServer.start_link(__MODULE__, state, name: __MODULE__)
-  end
-
-  def create_queue(name) do
-    {name, {:sets.new(), []}}
-  end
-
-  @doc """
-  Enqueues a job.
-
-  Returns `:ok`.
-
-  ## Arguments
-
-  - `queue_name` - a queue name(must be specified in the config).
-  - `mod` - a worker module (must have `perform` function).
-  - `args` - a list of arguments for the `perform` function of the worker module.
-  - `priority` - a job priority (`0` by default).
-
-  ## Examples
-
-  Enqueue `Module.perform/0` with `priority=1`:
-
-      iex> Pleroma.Jobs.enqueue(:example_queue, Module, [])
-      :ok
-
-  Enqueue `Module.perform(:job_name)` with `priority=5`:
-
-      iex> Pleroma.Jobs.enqueue(:example_queue, Module, [:job_name], 5)
-      :ok
-
-  Enqueue `Module.perform(:another_job, data)` with `priority=1`:
-
-      iex> data = "foobar"
-      iex> Pleroma.Jobs.enqueue(:example_queue, Module, [:another_job, data])
-      :ok
-
-  Enqueue `Module.perform(:foobar_job, :foo, :bar, 42)` with `priority=1`:
-
-      iex> Pleroma.Jobs.enqueue(:example_queue, Module, [:foobar_job, :foo, :bar, 42])
-      :ok
-
-  """
-
-  def enqueue(queue_name, mod, args, priority \\ 1)
-
-  if Mix.env() == :test do
-    def enqueue(_queue_name, mod, args, _priority) do
-      apply(mod, :perform, args)
-    end
-  else
-    @spec enqueue(atom(), atom(), [any()], integer()) :: :ok
-    def enqueue(queue_name, mod, args, priority) do
-      GenServer.cast(__MODULE__, {:enqueue, queue_name, mod, args, priority})
-    end
-  end
-
-  def handle_cast({:enqueue, queue_name, mod, args, priority}, state) do
-    {running_jobs, queue} = state[:queues][queue_name]
-
-    queue = enqueue_sorted(queue, {mod, args}, priority)
-
-    state =
-      state
-      |> update_queue(queue_name, {running_jobs, queue})
-      |> maybe_start_job(queue_name, running_jobs, queue)
-
-    {:noreply, state}
-  end
-
-  def handle_info({:DOWN, ref, :process, _pid, _reason}, state) do
-    queue_name = state.refs[ref]
-
-    {running_jobs, queue} = state[:queues][queue_name]
-
-    running_jobs = :sets.del_element(ref, running_jobs)
-
-    state =
-      state
-      |> remove_ref(ref)
-      |> update_queue(queue_name, {running_jobs, queue})
-      |> maybe_start_job(queue_name, running_jobs, queue)
-
-    {:noreply, state}
-  end
-
-  def maybe_start_job(state, queue_name, running_jobs, queue) do
-    if :sets.size(running_jobs) < Pleroma.Config.get([__MODULE__, queue_name, :max_jobs]) &&
-         queue != [] do
-      {{mod, args}, queue} = queue_pop(queue)
-      {:ok, pid} = Task.start(fn -> apply(mod, :perform, args) end)
-      mref = Process.monitor(pid)
-
-      state
-      |> add_ref(queue_name, mref)
-      |> update_queue(queue_name, {:sets.add_element(mref, running_jobs), queue})
-    else
-      state
-    end
-  end
-
-  def enqueue_sorted(queue, element, priority) do
-    [%{item: element, priority: priority} | queue]
-    |> Enum.sort_by(fn %{priority: priority} -> priority end)
-  end
-
-  def queue_pop([%{item: element} | queue]) do
-    {element, queue}
-  end
-
-  defp add_ref(state, queue_name, ref) do
-    refs = Map.put(state[:refs], ref, queue_name)
-    Map.put(state, :refs, refs)
-  end
-
-  defp remove_ref(state, ref) do
-    refs = Map.delete(state[:refs], ref)
-    Map.put(state, :refs, refs)
-  end
-
-  defp update_queue(state, queue_name, data) do
-    queues = Map.put(state[:queues], queue_name, data)
-    Map.put(state, :queues, queues)
-  end
-end
index 55c4cf6df16fde340043cd4a214363828cadcebc..110be8355985f2d628160bd36ce43114765620ca 100644 (file)
@@ -80,7 +80,7 @@ defmodule Pleroma.List do
 
   # Get lists to which the account belongs.
   def get_lists_account_belongs(%User{} = owner, account_id) do
-    user = Repo.get(User, account_id)
+    user = User.get_by_id(account_id)
 
     query =
       from(
index 5a77f683361321be000612417268d212f99ac0e6..4089aa958865d2b0dea038fb0f175dadeb64c064 100644 (file)
@@ -3,9 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Plugs.UserFetcherPlug do
-  alias Pleroma.Repo
   alias Pleroma.User
-
   import Plug.Conn
 
   def init(options) do
@@ -14,26 +12,10 @@ defmodule Pleroma.Plugs.UserFetcherPlug do
 
   def call(conn, _options) do
     with %{auth_credentials: %{username: username}} <- conn.assigns,
-         {:ok, %User{} = user} <- user_fetcher(username) do
-      conn
-      |> assign(:auth_user, user)
+         %User{} = user <- User.get_by_nickname_or_email(username) do
+      assign(conn, :auth_user, user)
     else
       _ -> conn
     end
   end
-
-  defp user_fetcher(username_or_email) do
-    {
-      :ok,
-      cond do
-        # First, try logging in as if it was a name
-        user = Repo.get_by(User, %{nickname: username_or_email}) ->
-          user
-
-        # If we get nil, we try using it as an email
-        user = Repo.get_by(User, %{email: username_or_email}) ->
-          user
-      end
-    }
-  end
 end
index 09d20b4325d7618f34c7ecc9ff7e38092cfbfb80..5012aef77aa543be08d076e2db3be6a278a51e93 100644 (file)
@@ -79,17 +79,17 @@ defmodule Pleroma.User do
   def superuser?(%User{local: true, info: %User.Info{is_moderator: true}}), do: true
   def superuser?(_), do: false
 
-  def avatar_url(user) do
+  def avatar_url(user, options \\ []) do
     case user.avatar do
       %{"url" => [%{"href" => href} | _]} -> href
-      _ -> "#{Web.base_url()}/images/avi.png"
+      _ -> !options[:no_default] && "#{Web.base_url()}/images/avi.png"
     end
   end
 
-  def banner_url(user) do
+  def banner_url(user, options \\ []) do
     case user.info.banner do
       %{"url" => [%{"href" => href} | _]} -> href
-      _ -> "#{Web.base_url()}/images/banner.png"
+      _ -> !options[:no_default] && "#{Web.base_url()}/images/banner.png"
     end
   end
 
@@ -768,52 +768,6 @@ defmodule Pleroma.User do
     Repo.all(query)
   end
 
-  @spec search_for_admin(%{
-          local: boolean(),
-          page: number(),
-          page_size: number()
-        }) :: {:ok, [Pleroma.User.t()], number()}
-  def search_for_admin(%{query: nil, local: local, page: page, page_size: page_size}) do
-    query =
-      from(u in User, order_by: u.nickname)
-      |> maybe_local_user_query(local)
-
-    paginated_query =
-      query
-      |> paginate(page, page_size)
-
-    count =
-      query
-      |> Repo.aggregate(:count, :id)
-
-    {:ok, Repo.all(paginated_query), count}
-  end
-
-  @spec search_for_admin(%{
-          query: binary(),
-          local: boolean(),
-          page: number(),
-          page_size: number()
-        }) :: {:ok, [Pleroma.User.t()], number()}
-  def search_for_admin(%{
-        query: term,
-        local: local,
-        page: page,
-        page_size: page_size
-      }) do
-    maybe_local_query = User |> maybe_local_user_query(local)
-
-    search_query = from(u in maybe_local_query, where: ilike(u.nickname, ^"%#{term}%"))
-    count = search_query |> Repo.aggregate(:count, :id)
-
-    results =
-      search_query
-      |> paginate(page, page_size)
-      |> Repo.all()
-
-    {:ok, results, count}
-  end
-
   def search(query, resolve \\ false, for_user \\ nil) do
     # Strip the beginning @ off if there is a query
     query = String.trim_leading(query, "@")
@@ -852,7 +806,7 @@ defmodule Pleroma.User do
         search_rank:
           fragment(
             """
-             CASE WHEN (?) THEN (?) * 1.3 
+             CASE WHEN (?) THEN (?) * 1.3
              WHEN (?) THEN (?) * 1.2
              WHEN (?) THEN (?) * 1.1
              ELSE (?) END
@@ -1067,6 +1021,42 @@ defmodule Pleroma.User do
     )
   end
 
+  def maybe_external_user_query(query, external) do
+    if external, do: external_user_query(query), else: query
+  end
+
+  def external_user_query(query \\ User) do
+    from(
+      u in query,
+      where: u.local == false,
+      where: not is_nil(u.nickname)
+    )
+  end
+
+  def maybe_active_user_query(query, active) do
+    if active, do: active_user_query(query), else: query
+  end
+
+  def active_user_query(query \\ User) do
+    from(
+      u in query,
+      where: fragment("not (?->'deactivated' @> 'true')", u.info),
+      where: not is_nil(u.nickname)
+    )
+  end
+
+  def maybe_deactivated_user_query(query, deactivated) do
+    if deactivated, do: deactivated_user_query(query), else: query
+  end
+
+  def deactivated_user_query(query \\ User) do
+    from(
+      u in query,
+      where: fragment("(?->'deactivated' @> 'true')", u.info),
+      where: not is_nil(u.nickname)
+    )
+  end
+
   def active_local_user_query do
     from(
       u in local_user_query(),
@@ -1098,28 +1088,27 @@ defmodule Pleroma.User do
     # Remove all relationships
     {:ok, followers} = User.get_followers(user)
 
-    followers
-    |> Enum.each(fn follower -> User.unfollow(follower, user) end)
+    Enum.each(followers, fn follower -> User.unfollow(follower, user) end)
 
     {:ok, friends} = User.get_friends(user)
 
-    friends
-    |> Enum.each(fn followed -> User.unfollow(user, followed) end)
+    Enum.each(friends, fn followed -> User.unfollow(user, followed) end)
 
-    query =
-      from(a in Activity, where: a.actor == ^user.ap_id)
-      |> Activity.with_preloaded_object()
+    delete_user_activities(user)
+  end
 
-    Repo.all(query)
-    |> Enum.each(fn activity ->
-      case activity.data["type"] do
-        "Create" ->
-          ActivityPub.delete(Object.normalize(activity))
+  def delete_user_activities(%User{ap_id: ap_id} = user) do
+    Activity
+    |> where(actor: ^ap_id)
+    |> Activity.with_preloaded_object()
+    |> Repo.all()
+    |> Enum.each(fn
+      %{data: %{"type" => "Create"}} = activity ->
+        activity |> Object.normalize() |> ActivityPub.delete()
 
-        # TODO: Do something with likes, follows, repeats.
-        _ ->
-          "Doing nothing"
-      end
+      # TODO: Do something with likes, follows, repeats.
+      _ ->
+        "Doing nothing"
     end)
 
     {:ok, user}
@@ -1241,8 +1230,8 @@ defmodule Pleroma.User do
   # this is because we have synchronous follow APIs and need to simulate them
   # with an async handshake
   def wait_and_refresh(_, %User{local: true} = a, %User{local: true} = b) do
-    with %User{} = a <- Repo.get(User, a.id),
-         %User{} = b <- Repo.get(User, b.id) do
+    with %User{} = a <- User.get_by_id(a.id),
+         %User{} = b <- User.get_by_id(b.id) do
       {:ok, a, b}
     else
       _e ->
@@ -1252,8 +1241,8 @@ defmodule Pleroma.User do
 
   def wait_and_refresh(timeout, %User{} = a, %User{} = b) do
     with :ok <- :timer.sleep(timeout),
-         %User{} = a <- Repo.get(User, a.id),
-         %User{} = b <- Repo.get(User, b.id) do
+         %User{} = a <- User.get_by_id(a.id),
+         %User{} = b <- User.get_by_id(b.id) do
       {:ok, a, b}
     else
       _e ->
index 0d9a89d0b2dc3bee4557416a25669e94244da7b5..6e1ed7ec9dc51e45c5abdc0bfcf946d6fc6ea342 100644 (file)
@@ -737,8 +737,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
     from(
       activity in query,
-      where: fragment("not ?->>'type' = 'Announce'", activity.data),
-      where: fragment("not ? = ANY(?)", activity.actor, ^muted_reblogs)
+      where:
+        fragment(
+          "not ( ?->>'type' = 'Announce' and ? = ANY(?))",
+          activity.data,
+          activity.actor,
+          ^muted_reblogs
+        )
     )
   end
 
index 2e9ffe41c40f5b2fa33049d94f7544cd450af5a0..77841278a3a63489b4ff3ebb17461343895108d3 100644 (file)
@@ -354,7 +354,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
         [state, actor, object]
       )
 
-      activity = Repo.get(Activity, activity.id)
+      activity = Activity.get_by_id(activity.id)
       {:ok, activity}
     rescue
       e ->
index 3d00dcbf29ea2271d8375de139ead7fb8e8d5d3e..5926a3294e44faa8a569acbb06c0989cc06bbdeb 100644 (file)
@@ -87,16 +87,10 @@ defmodule Pleroma.Web.ActivityPub.UserView do
         "publicKeyPem" => public_key
       },
       "endpoints" => endpoints,
-      "icon" => %{
-        "type" => "Image",
-        "url" => User.avatar_url(user)
-      },
-      "image" => %{
-        "type" => "Image",
-        "url" => User.banner_url(user)
-      },
       "tag" => user.info.source_data["tag"] || []
     }
+    |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
+    |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
     |> Map.merge(Utils.make_json_ld_header())
   end
 
@@ -294,4 +288,17 @@ defmodule Pleroma.Web.ActivityPub.UserView do
       map
     end
   end
+
+  defp maybe_make_image(func, key, user) do
+    if image = func.(user, no_default: true) do
+      %{
+        key => %{
+          "type" => "Image",
+          "url" => image
+        }
+      }
+    else
+      %{}
+    end
+  end
 end
index 6d9bf289502f617ea40adffc3a3278fa43e616cc..b3a09e49ee433f848f5b7fdca86e9dd36520dea9 100644 (file)
@@ -3,17 +3,18 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.AdminAPI.AdminAPIController do
-  @users_page_size 50
-
   use Pleroma.Web, :controller
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.Relay
   alias Pleroma.Web.AdminAPI.AccountView
+  alias Pleroma.Web.AdminAPI.Search
 
   import Pleroma.Web.ControllerHelper, only: [json_response: 3]
 
   require Logger
 
+  @users_page_size 50
+
   action_fallback(:errors)
 
   def user_delete(conn, %{"nickname" => nickname}) do
@@ -44,6 +45,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
     |> json(user.nickname)
   end
 
+  def user_show(conn, %{"nickname" => nickname}) do
+    with %User{} = user <- User.get_by_nickname(nickname) do
+      conn
+      |> json(AccountView.render("show.json", %{user: user}))
+    else
+      _ -> {:error, :not_found}
+    end
+  end
+
   def user_toggle_activation(conn, %{"nickname" => nickname}) do
     user = User.get_by_nickname(nickname)
 
@@ -63,17 +73,17 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
          do: json_response(conn, :no_content, "")
   end
 
-  def list_users(%{assigns: %{user: admin}} = conn, params) do
+  def list_users(conn, params) do
     {page, page_size} = page_params(params)
+    filters = maybe_parse_filters(params["filters"])
 
-    with {:ok, users, count} <-
-           User.search_for_admin(%{
-             query: params["query"],
-             admin: admin,
-             local: params["local_only"] == "true",
-             page: page,
-             page_size: page_size
-           }),
+    search_params = %{
+      query: params["query"],
+      page: page,
+      page_size: page_size
+    }
+
+    with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
          do:
            conn
            |> json(
@@ -85,6 +95,19 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
            )
   end
 
+  @filters ~w(local external active deactivated)
+
+  defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
+
+  @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
+  defp maybe_parse_filters(filters) do
+    filters
+    |> String.split(",")
+    |> Enum.filter(&Enum.member?(@filters, &1))
+    |> Enum.map(&String.to_atom(&1))
+    |> Enum.into(%{}, &{&1, true})
+  end
+
   def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
       when permission_group in ["moderator", "admin"] do
     user = User.get_by_nickname(nickname)
@@ -217,6 +240,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
     |> json(token.token)
   end
 
+  def errors(conn, {:error, :not_found}) do
+    conn
+    |> put_status(404)
+    |> json("Not found")
+  end
+
   def errors(conn, {:param_cast, _}) do
     conn
     |> put_status(400)
diff --git a/lib/pleroma/web/admin_api/search.ex b/lib/pleroma/web/admin_api/search.ex
new file mode 100644 (file)
index 0000000..9a8e41c
--- /dev/null
@@ -0,0 +1,54 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.Search do
+  import Ecto.Query
+
+  alias Pleroma.Repo
+  alias Pleroma.User
+
+  @page_size 50
+
+  def user(%{query: term} = params) when is_nil(term) or term == "" do
+    query = maybe_filtered_query(params)
+
+    paginated_query =
+      maybe_filtered_query(params)
+      |> paginate(params[:page] || 1, params[:page_size] || @page_size)
+
+    count = query |> Repo.aggregate(:count, :id)
+
+    results = Repo.all(paginated_query)
+
+    {:ok, results, count}
+  end
+
+  def user(%{query: term} = params) when is_binary(term) do
+    search_query = from(u in maybe_filtered_query(params), where: ilike(u.nickname, ^"%#{term}%"))
+
+    count = search_query |> Repo.aggregate(:count, :id)
+
+    results =
+      search_query
+      |> paginate(params[:page] || 1, params[:page_size] || @page_size)
+      |> Repo.all()
+
+    {:ok, results, count}
+  end
+
+  defp maybe_filtered_query(params) do
+    from(u in User, order_by: u.nickname)
+    |> User.maybe_local_user_query(params[:local])
+    |> User.maybe_external_user_query(params[:external])
+    |> User.maybe_active_user_query(params[:active])
+    |> User.maybe_deactivated_user_query(params[:deactivated])
+  end
+
+  defp paginate(query, page, page_size) do
+    from(u in query,
+      limit: ^page_size,
+      offset: ^((page - 1) * page_size)
+    )
+  end
+end
index 3a700fa3bea0d2cd7643c58b505694882e4e75c0..6503979a170852fbfe6203d99cc9082492f3853a 100644 (file)
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.UserSocket do
   def connect(%{"token" => token}, socket) do
     with true <- Pleroma.Config.get([:chat, :enabled]),
          {:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84_600),
-         %User{} = user <- Pleroma.Repo.get(User, user_id) do
+         %User{} = user <- Pleroma.User.get_by_id(user_id) do
       {:ok, assign(socket, :user_name, user.nickname)}
     else
       _e -> :error
index f596f703b5f3bae9bc8de8894372760407da4d1b..40cea30901199732e994d44bec89f97dba601681 100644 (file)
@@ -31,7 +31,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
   def get_replied_to_activity(""), do: nil
 
   def get_replied_to_activity(id) when not is_nil(id) do
-    Repo.get(Activity, id)
+    Activity.get_by_id(id)
   end
 
   def get_replied_to_activity(_), do: nil
@@ -275,7 +275,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
   end
 
   def confirm_current_password(user, password) do
-    with %User{local: true} = db_user <- Repo.get(User, user.id),
+    with %User{local: true} = db_user <- User.get_by_id(user.id),
          true <- Pbkdf2.checkpw(password, db_user.password_hash) do
       {:ok, db_user}
     else
index 4d6192db03edb5f63eb8bbbc66078c0cb20d5792..181483664ff45443a15f15d0ec5cf6821d3a65ad 100644 (file)
@@ -5,6 +5,11 @@
 defmodule Pleroma.Web.ControllerHelper do
   use Pleroma.Web, :controller
 
+  # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
+  @falsy_param_values [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"]
+  def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
+  def truthy_param?(value), do: value not in @falsy_param_values
+
   def oauth_scopes(params, default) do
     # Note: `scopes` is used by Mastodon — supporting it but sticking to
     # OAuth's standard `scope` wherever we control it
index 5e690ddb84446e08bb64c99e95aa2660bbaf9740..c47328e13a4e096182ffc97ae1688f7c559eb099 100644 (file)
@@ -4,7 +4,6 @@
 
 defmodule Pleroma.Web.Federator do
   alias Pleroma.Activity
-  alias Pleroma.Jobs
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Relay
@@ -31,39 +30,39 @@ defmodule Pleroma.Web.Federator do
   # Client API
 
   def incoming_doc(doc) do
-    Jobs.enqueue(:federator_incoming, __MODULE__, [:incoming_doc, doc])
+    PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_doc, doc])
   end
 
   def incoming_ap_doc(params) do
-    Jobs.enqueue(:federator_incoming, __MODULE__, [:incoming_ap_doc, params])
+    PleromaJobQueue.enqueue(:federator_incoming, __MODULE__, [:incoming_ap_doc, params])
   end
 
   def publish(activity, priority \\ 1) do
-    Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority)
+    PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority)
   end
 
   def publish_single_ap(params) do
-    Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_ap, params])
+    PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_ap, params])
   end
 
   def publish_single_websub(websub) do
-    Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub])
+    PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub])
   end
 
   def verify_websub(websub) do
-    Jobs.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub])
+    PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub])
   end
 
   def request_subscription(sub) do
-    Jobs.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub])
+    PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:request_subscription, sub])
   end
 
   def refresh_subscriptions do
-    Jobs.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions])
+    PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions])
   end
 
   def publish_single_salmon(params) do
-    Jobs.enqueue(:federator_outgoing, __MODULE__, [:publish_single_salmon, params])
+    PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_salmon, params])
   end
 
   # Job Worker Callbacks
index 6be0f2bafdcd6b3d563a05e4effa48f6e17bc2b3..0de2cca4e8293bbcb18732762fec7a5e490cce6b 100644 (file)
@@ -18,6 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   alias Pleroma.Web.ActivityPub.Visibility
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.MastodonAPI.AccountView
+  alias Pleroma.Web.MastodonAPI.AppView
   alias Pleroma.Web.MastodonAPI.FilterView
   alias Pleroma.Web.MastodonAPI.ListView
   alias Pleroma.Web.MastodonAPI.MastodonAPI
@@ -51,16 +52,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     with cs <- App.register_changeset(%App{}, app_attrs),
          false <- cs.changes[:client_name] == @local_mastodon_name,
          {:ok, app} <- Repo.insert(cs) do
-      res = %{
-        id: app.id |> to_string,
-        name: app.client_name,
-        client_id: app.client_id,
-        client_secret: app.client_secret,
-        redirect_uri: app.redirect_uris,
-        website: app.website
-      }
-
-      json(conn, res)
+      conn
+      |> put_view(AppView)
+      |> render("show.json", %{app: app})
     end
   end
 
@@ -132,6 +126,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     json(conn, account)
   end
 
+  def verify_app_credentials(%{assigns: %{user: _user, token: token}} = conn, _) do
+    with %Token{app: %App{} = app} <- Repo.preload(token, :app) do
+      conn
+      |> put_view(AppView)
+      |> render("short.json", %{app: app})
+    end
+  end
+
   def user(%{assigns: %{user: for_user}} = conn, %{"id" => nickname_or_id}) do
     with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id),
          true <- User.auth_active?(user) || user.id == for_user.id || User.superuser?(for_user) do
@@ -161,6 +163,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
       },
       stats: Stats.get_stats(),
       thumbnail: Web.base_url() <> "/instance/thumbnail.jpeg",
+      languages: ["en"],
+      registrations: Pleroma.Config.get([:instance, :registrations_open]),
+      # Extra (not present in Mastodon):
       max_toot_chars: Keyword.get(instance, :limit)
     }
 
@@ -280,7 +285,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
-    with %User{} = user <- Repo.get(User, params["id"]) do
+    with %User{} = user <- User.get_by_id(params["id"]) do
       activities = ActivityPub.fetch_user_activities(user, reading_user, params)
 
       conn
@@ -314,7 +319,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    with %Activity{} = activity <- Repo.get(Activity, id),
+    with %Activity{} = activity <- Activity.get_by_id(id),
          true <- Visibility.visible_for_user?(activity, user) do
       conn
       |> put_view(StatusView)
@@ -323,7 +328,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    with %Activity{} = activity <- Repo.get(Activity, id),
+    with %Activity{} = activity <- Activity.get_by_id(id),
          activities <-
            ActivityPub.fetch_activities_for_context(activity.data["context"], %{
              "blocking_user" => user,
@@ -455,7 +460,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    with %Activity{} = activity <- Repo.get(Activity, id),
+    with %Activity{} = activity <- Activity.get_by_id(id),
          %User{} = user <- User.get_by_nickname(user.nickname),
          true <- Visibility.visible_for_user?(activity, user),
          {:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do
@@ -466,7 +471,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    with %Activity{} = activity <- Repo.get(Activity, id),
+    with %Activity{} = activity <- Activity.get_by_id(id),
          %User{} = user <- User.get_by_nickname(user.nickname),
          true <- Visibility.visible_for_user?(activity, user),
          {:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do
@@ -588,7 +593,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def favourited_by(conn, %{"id" => id}) do
-    with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do
+    with %Activity{data: %{"object" => %{"likes" => likes}}} <- Activity.get_by_id(id) do
       q = from(u in User, where: u.ap_id in ^likes)
       users = Repo.all(q)
 
@@ -601,7 +606,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def reblogged_by(conn, %{"id" => id}) do
-    with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do
+    with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Activity.get_by_id(id) do
       q = from(u in User, where: u.ap_id in ^announces)
       users = Repo.all(q)
 
@@ -652,7 +657,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def followers(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
-    with %User{} = user <- Repo.get(User, id),
+    with %User{} = user <- User.get_by_id(id),
          followers <- MastodonAPI.get_followers(user, params) do
       followers =
         cond do
@@ -669,7 +674,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def following(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params) do
-    with %User{} = user <- Repo.get(User, id),
+    with %User{} = user <- User.get_by_id(id),
          followers <- MastodonAPI.get_friends(user, params) do
       followers =
         cond do
@@ -694,7 +699,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def authorize_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
-    with %User{} = follower <- Repo.get(User, id),
+    with %User{} = follower <- User.get_by_id(id),
          {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
       conn
       |> put_view(AccountView)
@@ -708,7 +713,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def reject_follow_request(%{assigns: %{user: followed}} = conn, %{"id" => id}) do
-    with %User{} = follower <- Repo.get(User, id),
+    with %User{} = follower <- User.get_by_id(id),
          {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
       conn
       |> put_view(AccountView)
@@ -722,7 +727,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
-    with %User{} = followed <- Repo.get(User, id),
+    with %User{} = followed <- User.get_by_id(id),
          false <- User.following?(follower, followed),
          {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
       conn
@@ -750,7 +755,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def follow(%{assigns: %{user: follower}} = conn, %{"uri" => uri}) do
-    with %User{} = followed <- Repo.get_by(User, nickname: uri),
+    with %User{} = followed <- User.get_by_nickname(uri),
          {:ok, follower, followed, _} <- CommonAPI.follow(follower, followed) do
       conn
       |> put_view(AccountView)
@@ -764,7 +769,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def unfollow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do
-    with %User{} = followed <- Repo.get(User, id),
+    with %User{} = followed <- User.get_by_id(id),
          {:ok, follower} <- CommonAPI.unfollow(follower, followed) do
       conn
       |> put_view(AccountView)
@@ -773,7 +778,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def mute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
-    with %User{} = muted <- Repo.get(User, id),
+    with %User{} = muted <- User.get_by_id(id),
          {:ok, muter} <- User.mute(muter, muted) do
       conn
       |> put_view(AccountView)
@@ -787,7 +792,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def unmute(%{assigns: %{user: muter}} = conn, %{"id" => id}) do
-    with %User{} = muted <- Repo.get(User, id),
+    with %User{} = muted <- User.get_by_id(id),
          {:ok, muter} <- User.unmute(muter, muted) do
       conn
       |> put_view(AccountView)
@@ -808,7 +813,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def block(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
-    with %User{} = blocked <- Repo.get(User, id),
+    with %User{} = blocked <- User.get_by_id(id),
          {:ok, blocker} <- User.block(blocker, blocked),
          {:ok, _activity} <- ActivityPub.block(blocker, blocked) do
       conn
@@ -823,7 +828,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def unblock(%{assigns: %{user: blocker}} = conn, %{"id" => id}) do
-    with %User{} = blocked <- Repo.get(User, id),
+    with %User{} = blocked <- User.get_by_id(id),
          {:ok, blocker} <- User.unblock(blocker, blocked),
          {:ok, _activity} <- ActivityPub.unblock(blocker, blocked) do
       conn
@@ -961,7 +966,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def bookmarks(%{assigns: %{user: user}} = conn, _) do
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
 
     activities =
       user.bookmarks
@@ -1018,7 +1023,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     accounts
     |> Enum.each(fn account_id ->
       with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
-           %User{} = followed <- Repo.get(User, account_id) do
+           %User{} = followed <- User.get_by_id(account_id) do
         Pleroma.List.follow(list, followed)
       end
     end)
@@ -1030,7 +1035,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     accounts
     |> Enum.each(fn account_id ->
       with %Pleroma.List{} = list <- Pleroma.List.get(id, user),
-           %User{} = followed <- Repo.get(Pleroma.User, account_id) do
+           %User{} = followed <- Pleroma.User.get_by_id(account_id) do
         Pleroma.List.unfollow(list, followed)
       end
     end)
@@ -1244,16 +1249,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     "glitch"
   end
 
-  def login(conn, %{"code" => code}) do
+  def login(%{assigns: %{user: %User{}}} = conn, _params) do
+    redirect(conn, to: local_mastodon_root_path(conn))
+  end
+
+  @doc "Local Mastodon FE login init action"
+  def login(conn, %{"code" => auth_token}) do
     with {:ok, app} <- get_or_make_app(),
-         %Authorization{} = auth <- Repo.get_by(Authorization, token: code, app_id: app.id),
+         %Authorization{} = auth <- Repo.get_by(Authorization, token: auth_token, app_id: app.id),
          {:ok, token} <- Token.exchange_token(app, auth) do
       conn
       |> put_session(:oauth_token, token.token)
-      |> redirect(to: "/web/getting-started")
+      |> redirect(to: local_mastodon_root_path(conn))
     end
   end
 
+  @doc "Local Mastodon FE callback action"
   def login(conn, _) do
     with {:ok, app} <- get_or_make_app() do
       path =
@@ -1271,6 +1282,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
+  defp local_mastodon_root_path(conn), do: mastodon_api_path(conn, :index, ["getting-started"])
+
   defp get_or_make_app do
     find_attrs = %{client_name: @local_mastodon_name, redirect_uris: "."}
     scopes = ["read", "write", "follow", "push"]
@@ -1307,7 +1320,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   def relationship_noop(%{assigns: %{user: user}} = conn, %{"id" => id}) do
     Logger.debug("Unimplemented, returning unmodified relationship")
 
-    with %User{} = target <- Repo.get(User, id) do
+    with %User{} = target <- User.get_by_id(id) do
       conn
       |> put_view(AccountView)
       |> render("relationship.json", %{user: user, target: target})
@@ -1449,7 +1462,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   end
 
   def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
-    with %Activity{} = activity <- Repo.get(Activity, status_id),
+    with %Activity{} = activity <- Activity.get_by_id(status_id),
          true <- Visibility.visible_for_user?(activity, user) do
       data =
         StatusView.render(
diff --git a/lib/pleroma/web/mastodon_api/views/app_view.ex b/lib/pleroma/web/mastodon_api/views/app_view.ex
new file mode 100644 (file)
index 0000000..f52b693
--- /dev/null
@@ -0,0 +1,41 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.AppView do
+  use Pleroma.Web, :view
+
+  alias Pleroma.Web.OAuth.App
+
+  @vapid_key :web_push_encryption
+             |> Application.get_env(:vapid_details, [])
+             |> Keyword.get(:public_key)
+
+  def render("show.json", %{app: %App{} = app}) do
+    %{
+      id: app.id |> to_string,
+      name: app.client_name,
+      client_id: app.client_id,
+      client_secret: app.client_secret,
+      redirect_uri: app.redirect_uris,
+      website: app.website
+    }
+    |> with_vapid_key()
+  end
+
+  def render("short.json", %{app: %App{website: webiste, client_name: name}}) do
+    %{
+      name: name,
+      website: webiste
+    }
+    |> with_vapid_key()
+  end
+
+  defp with_vapid_key(data) do
+    if @vapid_key do
+      Map.put(data, "vapid_key", @vapid_key)
+    else
+      data
+    end
+  end
+end
index 9b262f4616992709805bf1d4689c257f7cf95101..1b3721e2b62b200a7878c6830650ee6771c37cd9 100644 (file)
@@ -90,7 +90,7 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
   # Authenticated streams.
   defp allow_request(stream, {"access_token", access_token}) when stream in @streams do
     with %Token{user_id: user_id} <- Repo.get_by(Token, token: access_token),
-         user = %User{} <- Repo.get(User, user_id) do
+         user = %User{} <- User.get_by_id(user_id) do
       {:ok, user}
     else
       _ -> {:error, 403}
index ebb3dd253e69ad9f618f373f88b1004d639125c0..26d53df1a5da02302da62060a2639758da713405 100644 (file)
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
   alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.Auth.Authenticator
+  alias Pleroma.Web.ControllerHelper
   alias Pleroma.Web.OAuth.App
   alias Pleroma.Web.OAuth.Authorization
   alias Pleroma.Web.OAuth.Token
@@ -19,7 +20,28 @@ defmodule Pleroma.Web.OAuth.OAuthController do
 
   action_fallback(Pleroma.Web.OAuth.FallbackController)
 
-  def authorize(conn, params) do
+  def authorize(%{assigns: %{token: %Token{} = token}} = conn, params) do
+    if ControllerHelper.truthy_param?(params["force_login"]) do
+      do_authorize(conn, params)
+    else
+      redirect_uri =
+        if is_binary(params["redirect_uri"]) do
+          params["redirect_uri"]
+        else
+          app = Repo.preload(token, :app).app
+
+          app.redirect_uris
+          |> String.split()
+          |> Enum.at(0)
+        end
+
+      redirect(conn, external: redirect_uri(conn, redirect_uri))
+    end
+  end
+
+  def authorize(conn, params), do: do_authorize(conn, params)
+
+  defp do_authorize(conn, params) do
     app = Repo.get_by(App, client_id: params["client_id"])
     available_scopes = (app && app.scopes) || []
     scopes = oauth_scopes(params, nil) || available_scopes
@@ -51,13 +73,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
          {:missing_scopes, false} <- {:missing_scopes, scopes == []},
          {:auth_active, true} <- {:auth_active, User.auth_active?(user)},
          {:ok, auth} <- Authorization.create_authorization(app, user, scopes) do
-      redirect_uri =
-        if redirect_uri == "." do
-          # Special case: Local MastodonFE
-          mastodon_api_url(conn, :login)
-        else
-          redirect_uri
-        end
+      redirect_uri = redirect_uri(conn, redirect_uri)
 
       cond do
         redirect_uri == "urn:ietf:wg:oauth:2.0:oob" ->
@@ -108,7 +124,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
          fixed_token = fix_padding(params["code"]),
          %Authorization{} = auth <-
            Repo.get_by(Authorization, token: fixed_token, app_id: app.id),
-         %User{} = user <- Repo.get(User, auth.user_id),
+         %User{} = user <- User.get_by_id(auth.user_id),
          {:ok, token} <- Token.exchange_token(app, auth),
          {:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do
       response = %{
@@ -221,4 +237,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do
       nil
     end
   end
+
+  # Special case: Local MastodonFE
+  defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login)
+
+  defp redirect_uri(_conn, redirect_uri), do: redirect_uri
 end
index a8b06db36d90fb83ddb1b5f0e554218d9c01b24d..2b5ad9b9448bdfae6579878e6bfa53e2f518c067 100644 (file)
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.OAuth.Token do
   def exchange_token(app, auth) do
     with {:ok, auth} <- Authorization.use_token(auth),
          true <- auth.app_id == app.id do
-      create_token(app, Repo.get(User, auth.user_id), auth.scopes)
+      create_token(app, User.get_by_id(auth.user_id), auth.scopes)
     end
   end
 
index befd382bac5b4e139d9ba02ab0b2e84742f81401..605a327fc382960dee697305a1648244b4a1f66d 100644 (file)
@@ -5,6 +5,11 @@
 defmodule Pleroma.Web.Router do
   use Pleroma.Web, :router
 
+  pipeline :oauth do
+    plug(:fetch_session)
+    plug(Pleroma.Plugs.OAuthPlug)
+  end
+
   pipeline :api do
     plug(:accepts, ["json"])
     plug(:fetch_session)
@@ -105,10 +110,6 @@ defmodule Pleroma.Web.Router do
     plug(:accepts, ["json", "xml"])
   end
 
-  pipeline :oauth do
-    plug(:accepts, ["html", "json"])
-  end
-
   pipeline :pleroma_api do
     plug(:accepts, ["html", "json"])
   end
@@ -140,6 +141,7 @@ defmodule Pleroma.Web.Router do
     pipe_through([:admin_api, :oauth_write])
 
     get("/users", AdminAPIController, :list_users)
+    get("/users/:nickname", AdminAPIController, :user_show)
     delete("/user", AdminAPIController, :user_delete)
     patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation)
     post("/user", AdminAPIController, :user_create)
@@ -199,7 +201,11 @@ defmodule Pleroma.Web.Router do
   end
 
   scope "/oauth", Pleroma.Web.OAuth do
-    get("/authorize", OAuthController, :authorize)
+    scope [] do
+      pipe_through(:oauth)
+      get("/authorize", OAuthController, :authorize)
+    end
+
     post("/authorize", OAuthController, :create_authorization)
     post("/token", OAuthController, :token_exchange)
     post("/revoke", OAuthController, :token_revoke)
@@ -217,6 +223,7 @@ defmodule Pleroma.Web.Router do
       get("/accounts/search", MastodonAPIController, :account_search)
 
       get("/accounts/:id/lists", MastodonAPIController, :account_lists)
+      get("/accounts/:id/identity_proofs", MastodonAPIController, :empty_array)
 
       get("/follow_requests", MastodonAPIController, :follow_requests)
       get("/blocks", MastodonAPIController, :blocks)
@@ -328,6 +335,7 @@ defmodule Pleroma.Web.Router do
     get("/instance", MastodonAPIController, :masto_instance)
     get("/instance/peers", MastodonAPIController, :peers)
     post("/apps", MastodonAPIController, :create_app)
+    get("/apps/verify_credentials", MastodonAPIController, :verify_app_credentials)
     get("/custom_emojis", MastodonAPIController, :custom_emojis)
 
     get("/statuses/:id/card", MastodonAPIController, :status_card)
index 592749b42eb3df465a14b0271dbc916dff110fd1..a82109f92078947a8c2fc459634dbd1d05deeeda 100644 (file)
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.Streamer do
   alias Pleroma.Activity
   alias Pleroma.Notification
   alias Pleroma.Object
-  alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Visibility
@@ -82,7 +81,7 @@ defmodule Pleroma.Web.Streamer do
         _ ->
           Pleroma.List.get_lists_from_activity(item)
           |> Enum.filter(fn list ->
-            owner = Repo.get(User, list.user_id)
+            owner = User.get_by_id(list.user_id)
 
             Visibility.visible_for_user?(item, owner)
           end)
index b661c4363a668392ea57e3cad6c923fb08b52cd7..3cdd7a2f254693af44db3da09864b43cf292a831 100644 (file)
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
 
   def show_password_reset(conn, %{"token" => token}) do
     with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
-         %User{} = user <- Repo.get(User, token.user_id) do
+         %User{} = user <- User.get_by_id(token.user_id) do
       render(conn, "password_reset.html", %{
         token: token,
         user: user
@@ -113,13 +113,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   def do_remote_follow(conn, %{
         "authorization" => %{"name" => username, "password" => password, "id" => id}
       }) do
-    followee = Repo.get(User, id)
+    followee = User.get_by_id(id)
     avatar = User.avatar_url(followee)
     name = followee.nickname
 
     with %User{} = user <- User.get_cached_by_nickname(username),
          true <- Pbkdf2.checkpw(password, user.password_hash),
-         %User{} = _followed <- Repo.get(User, id),
+         %User{} = _followed <- User.get_by_id(id),
          {:ok, follower} <- User.follow(user, followee),
          {:ok, _activity} <- ActivityPub.follow(follower, followee) do
       conn
@@ -141,7 +141,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   end
 
   def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
-    with %User{} = followee <- Repo.get(User, id),
+    with %User{} = followee <- User.get_by_id(id),
          {:ok, follower} <- User.follow(user, followee),
          {:ok, _activity} <- ActivityPub.follow(follower, followee) do
       conn
index 9978c7f6440dac0d15fa14e478d93a40954dfb5e..9b081a3167141ce4d2fcdc780df88aa55df21c46 100644 (file)
@@ -20,7 +20,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
   end
 
   def delete(%User{} = user, id) do
-    with %Activity{data: %{"type" => _type}} <- Repo.get(Activity, id),
+    with %Activity{data: %{"type" => _type}} <- Activity.get_by_id(id),
          {:ok, activity} <- CommonAPI.delete(id, user) do
       {:ok, activity}
     end
@@ -227,12 +227,9 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
         end
 
       %{"screen_name" => nickname} ->
-        case target = Repo.get_by(User, nickname: nickname) do
-          nil ->
-            {:error, "No user with such screen_name"}
-
-          _ ->
-            {:ok, target}
+        case User.get_by_nickname(nickname) do
+          nil -> {:error, "No user with such screen_name"}
+          target -> {:ok, target}
         end
 
       _ ->
index 62cce18dc2bd78a7da18aef9816920ef6c20483c..a7ec9949cb43de42d4313cf8d15b3dd59fb7c4b4 100644 (file)
@@ -270,7 +270,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
   end
 
   def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    with %Activity{} = activity <- Repo.get(Activity, id),
+    with %Activity{} = activity <- Activity.get_by_id(id),
          true <- Visibility.visible_for_user?(activity, user) do
       conn
       |> put_view(ActivityView)
@@ -342,7 +342,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
   end
 
   def get_by_id_or_ap_id(id) do
-    activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
+    activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id)
 
     if activity.data["type"] == "Create" do
       activity
@@ -434,7 +434,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
   end
 
   def confirm_email(conn, %{"user_id" => uid, "token" => token}) do
-    with %User{} = user <- Repo.get(User, uid),
+    with %User{} = user <- User.get_by_id(uid),
          true <- user.local,
          true <- user.info.confirmation_pending,
          true <- user.info.confirmation_token == token,
@@ -587,7 +587,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
 
   def approve_friend_request(conn, %{"user_id" => uid} = _params) do
     with followed <- conn.assigns[:user],
-         %User{} = follower <- Repo.get(User, uid),
+         %User{} = follower <- User.get_by_id(uid),
          {:ok, follower} <- CommonAPI.accept_follow_request(follower, followed) do
       conn
       |> put_view(UserView)
@@ -599,7 +599,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
 
   def deny_friend_request(conn, %{"user_id" => uid} = _params) do
     with followed <- conn.assigns[:user],
-         %User{} = follower <- Repo.get(User, uid),
+         %User{} = follower <- User.get_by_id(uid),
          {:ok, follower} <- CommonAPI.reject_follow_request(follower, followed) do
       conn
       |> put_view(UserView)
diff --git a/mix.exs b/mix.exs
index 99a262089bbc35286051fccabb33bb56e60a160c..333f21a914d71e24c5c30687aeb258e1324323ab 100644 (file)
--- a/mix.exs
+++ b/mix.exs
@@ -22,16 +22,12 @@ defmodule Pleroma.Mixfile do
       homepage_url: "https://pleroma.social/",
       docs: [
         logo: "priv/static/static/logo.png",
-        extras: [
-          "README.md",
-          "docs/Admin-API.md",
-          "docs/Clients.md",
-          "docs/config.md",
-          "docs/Custom-Emoji.md",
-          "docs/Differences-in-MastodonAPI-Responses.md",
-          "docs/Message-Rewrite-Facility-configuration.md",
-          "docs/Pleroma-API.md",
-          "docs/static_dir.md"
+        extras: ["README.md" | Path.wildcard("docs/**/*.md")],
+        groups_for_extras: [
+          "Installation manuals": Path.wildcard("docs/installation/*.md"),
+          Configuration: Path.wildcard("docs/config/*.md"),
+          Administration: Path.wildcard("docs/admin/*.md"),
+          "Pleroma's APIs and Mastodon API extensions": Path.wildcard("docs/api/*.md")
         ],
         main: "readme",
         output: "priv/static/doc"
@@ -97,7 +93,8 @@ defmodule Pleroma.Mixfile do
       {:timex, "~> 3.5"},
       {:auto_linker,
        git: "https://git.pleroma.social/pleroma/auto_linker.git",
-       ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"}
+       ref: "94193ca5f97c1f9fdf3d1469653e2d46fac34bcd"},
+      {:pleroma_job_queue, "~> 0.2.0"}
     ]
   end
 
index 05eaa1d69eb42b93faa9df54260b558de22a32d4..f401258e9de7bd253b154e76e1fd6d25115ec5c6 100644 (file)
--- a/mix.lock
+++ b/mix.lock
@@ -50,6 +50,7 @@
   "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
   "phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
   "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"},
+  "pleroma_job_queue": {:hex, :pleroma_job_queue, "0.2.0", "879e660aa1cebe8dc6f0aaaa6aa48b4875e89cd961d4a585fd128e0773b31a18", [:mix], [], "hexpm"},
   "plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"},
   "plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
   "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
diff --git a/priv/repo/migrations/20190325215156_update_status_reply_count.exs b/priv/repo/migrations/20190325215156_update_status_reply_count.exs
deleted file mode 100644 (file)
index 50f1fe1..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-defmodule Pleroma.Repo.Migrations.UpdateStatusReplyCount do
-  use Ecto.Migration
-
-  @public "https://www.w3.org/ns/activitystreams#Public"
-
-  def up do
-    execute("""
-      WITH reply_count AS (
-        SELECT count(*) AS count, data->>'inReplyTo' AS ap_id
-        FROM objects
-        WHERE
-          data->>'inReplyTo' IS NOT NULL AND
-          data->>'type' = 'Note' AND (
-            data->'cc' ? '#{@public}' OR
-            data->'to' ? '#{@public}')
-        GROUP BY data->>'inReplyTo'
-      )
-      UPDATE objects AS o
-      SET "data" = jsonb_set(o.data, '{repliesCount}', reply_count.count::varchar::jsonb, true)
-      FROM reply_count
-      WHERE reply_count.ap_id = o.data->>'id';
-    """)
-
-    execute("""
-      WITH reply_count AS (SELECT
-          count(*) as count,
-          data->'object'->>'inReplyTo' AS ap_id
-        FROM
-          activities
-        WHERE
-          data->'object'->>'inReplyTo' IS NOT NULL AND
-          data->'object'->>'type' = 'Note' AND (
-            data->'object'->'cc' ? '#{@public}' OR
-            data->'object'->'to' ? '#{@public}')
-        GROUP BY
-          data->'object'->>'inReplyTo'
-      )
-      UPDATE activities AS a
-      SET "data" = jsonb_set(a.data, '{object, repliesCount}', reply_count.count::varchar::jsonb, true)
-      FROM reply_count
-      WHERE reply_count.ap_id = a.data->'object'->>'id';
-    """)
-  end
-
-  def down do
-    :noop
-  end
-end
diff --git a/priv/static/images/pleroma-fox-tan-smol.png b/priv/static/images/pleroma-fox-tan-smol.png
new file mode 100644 (file)
index 0000000..e944d0e
Binary files /dev/null and b/priv/static/images/pleroma-fox-tan-smol.png differ
diff --git a/priv/static/images/pleroma-fox-tan.png b/priv/static/images/pleroma-fox-tan.png
new file mode 100644 (file)
index 0000000..da0022f
Binary files /dev/null and b/priv/static/images/pleroma-fox-tan.png differ
diff --git a/priv/static/images/pleroma-tan.png b/priv/static/images/pleroma-tan.png
new file mode 100644 (file)
index 0000000..6c12c8e
Binary files /dev/null and b/priv/static/images/pleroma-tan.png differ
diff --git a/test/jobs_test.exs b/test/jobs_test.exs
deleted file mode 100644 (file)
index d55c86c..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.JobsTest do
-  use ExUnit.Case, async: true
-
-  alias Jobs.WorkerMock
-  alias Pleroma.Jobs
-
-  setup do
-    state = %{
-      queues: Enum.into([Jobs.create_queue(:testing)], %{}),
-      refs: %{}
-    }
-
-    [state: state]
-  end
-
-  test "creates queue" do
-    queue = Jobs.create_queue(:foobar)
-
-    assert {:foobar, set} = queue
-    assert :set == elem(set, 0) |> elem(0)
-  end
-
-  test "enqueues an element according to priority" do
-    queue = [%{item: 1, priority: 2}]
-
-    new_queue = Jobs.enqueue_sorted(queue, 2, 1)
-    assert new_queue == [%{item: 2, priority: 1}, %{item: 1, priority: 2}]
-
-    new_queue = Jobs.enqueue_sorted(queue, 2, 3)
-    assert new_queue == [%{item: 1, priority: 2}, %{item: 2, priority: 3}]
-  end
-
-  test "pop first item" do
-    queue = [%{item: 2, priority: 1}, %{item: 1, priority: 2}]
-
-    assert {2, [%{item: 1, priority: 2}]} = Jobs.queue_pop(queue)
-  end
-
-  test "enqueue a job", %{state: state} do
-    assert {:noreply, new_state} =
-             Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state)
-
-    assert %{queues: %{testing: {running_jobs, []}}, refs: _} = new_state
-    assert :sets.size(running_jobs) == 1
-    assert [ref] = :sets.to_list(running_jobs)
-    assert %{refs: %{^ref => :testing}} = new_state
-  end
-
-  test "max jobs setting", %{state: state} do
-    max_jobs = Pleroma.Config.get([Jobs, :testing, :max_jobs])
-
-    {:noreply, state} =
-      Enum.reduce(1..(max_jobs + 1), {:noreply, state}, fn _, {:noreply, state} ->
-        Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state)
-      end)
-
-    assert %{
-             queues: %{
-               testing:
-                 {running_jobs, [%{item: {WorkerMock, [:test_job, :foo, :bar]}, priority: 3}]}
-             }
-           } = state
-
-    assert :sets.size(running_jobs) == max_jobs
-  end
-
-  test "remove job after it finished", %{state: state} do
-    {:noreply, new_state} =
-      Jobs.handle_cast({:enqueue, :testing, WorkerMock, [:test_job, :foo, :bar], 3}, state)
-
-    %{queues: %{testing: {running_jobs, []}}} = new_state
-    [ref] = :sets.to_list(running_jobs)
-
-    assert {:noreply, %{queues: %{testing: {running_jobs, []}}, refs: %{}}} =
-             Jobs.handle_info({:DOWN, ref, :process, nil, nil}, new_state)
-
-    assert :sets.size(running_jobs) == 0
-  end
-end
index 18f77f01a836b644debda3df8dafea9fcb790d01..e1a08315a2f059f5464e6aa7b6e2c60edcc6f451 100644 (file)
@@ -216,7 +216,7 @@ defmodule Pleroma.Factory do
       redirect_uris: "https://example.com/callback",
       scopes: ["read", "write", "follow", "push"],
       website: "https://example.com",
-      client_id: "aaabbb==",
+      client_id: Ecto.UUID.generate(),
       client_secret: "aaa;/&bbb"
     }
   end
diff --git a/test/support/jobs_worker_mock.ex b/test/support/jobs_worker_mock.ex
deleted file mode 100644 (file)
index 0fb976d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Jobs.WorkerMock do
-  require Logger
-
-  def perform(:test_job, arg, arg2) do
-    Logger.debug({:perform, :test_job, arg, arg2})
-  end
-
-  def perform(:test_job, payload) do
-    Logger.debug({:perform, :test_job, payload})
-  end
-
-  def test_job(payload) do
-    Pleroma.Jobs.enqueue(:testing, __MODULE__, [:test_job, payload])
-  end
-end
index 7b814d171dad113cd0677d4f6547a34117f0d771..1030bd555ef2bd154914899c1ee6ec8ccb7aa300 100644 (file)
@@ -248,4 +248,14 @@ defmodule Mix.Tasks.Pleroma.UserTest do
       assert message =~ "Generated"
     end
   end
+
+  describe "running delete_activities" do
+    test "activities are deleted" do
+      %{nickname: nickname} = insert(:user)
+
+      assert :ok == Mix.Tasks.Pleroma.User.run(["delete_activities", nickname])
+      assert_received {:mix_shell, :info, [message]}
+      assert message == "User #{nickname} statuses deleted."
+    end
+  end
 end
index 442599910bff55b2bbc27ad7c33ed26f985e3741..38712cebb6aafb1edf7f4639806b4a52a5a87d97 100644 (file)
@@ -8,6 +8,7 @@ defmodule Pleroma.UserTest do
   alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.CommonAPI
+
   use Pleroma.DataCase
 
   import Pleroma.Factory
@@ -121,7 +122,7 @@ defmodule Pleroma.UserTest do
 
     {:ok, user} = User.follow(user, followed)
 
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
 
     followed = User.get_by_ap_id(followed.ap_id)
     assert followed.info.follower_count == 1
@@ -177,7 +178,7 @@ defmodule Pleroma.UserTest do
 
     {:ok, user, _activity} = User.unfollow(user, followed)
 
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
 
     assert user.following == []
   end
@@ -187,7 +188,7 @@ defmodule Pleroma.UserTest do
 
     {:error, _} = User.unfollow(user, user)
 
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
     assert user.following == [user.ap_id]
   end
 
@@ -199,6 +200,13 @@ defmodule Pleroma.UserTest do
     refute User.following?(followed, user)
   end
 
+  test "fetches correct profile for nickname beginning with number" do
+    # Use old-style integer ID to try to reproduce the problem
+    user = insert(:user, %{id: 1080})
+    userwithnumbers = insert(:user, %{nickname: "#{user.id}garbage"})
+    assert userwithnumbers == User.get_cached_by_nickname_or_id(userwithnumbers.nickname)
+  end
+
   describe "user registration" do
     @full_user_data %{
       bio: "A guy",
@@ -678,7 +686,7 @@ defmodule Pleroma.UserTest do
       assert User.following?(blocked, blocker)
 
       {:ok, blocker} = User.block(blocker, blocked)
-      blocked = Repo.get(User, blocked.id)
+      blocked = User.get_by_id(blocked.id)
 
       assert User.blocks?(blocker, blocked)
 
@@ -696,7 +704,7 @@ defmodule Pleroma.UserTest do
       refute User.following?(blocked, blocker)
 
       {:ok, blocker} = User.block(blocker, blocked)
-      blocked = Repo.get(User, blocked.id)
+      blocked = User.get_by_id(blocked.id)
 
       assert User.blocks?(blocker, blocked)
 
@@ -714,7 +722,7 @@ defmodule Pleroma.UserTest do
       assert User.following?(blocked, blocker)
 
       {:ok, blocker} = User.block(blocker, blocked)
-      blocked = Repo.get(User, blocked.id)
+      blocked = User.get_by_id(blocked.id)
 
       assert User.blocks?(blocker, blocked)
 
@@ -791,6 +799,16 @@ defmodule Pleroma.UserTest do
     assert false == user.info.deactivated
   end
 
+  test ".delete_user_activities deletes all create activities" do
+    user = insert(:user)
+
+    {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
+    {:ok, _} = User.delete_user_activities(user)
+
+    # TODO: Remove favorites, repeats, delete activities.
+    refute Activity.get_by_id(activity.id)
+  end
+
   test ".delete deactivates a user, all follow relationships and all create activities" do
     user = insert(:user)
     followed = insert(:user)
@@ -808,9 +826,9 @@ defmodule Pleroma.UserTest do
 
     {:ok, _} = User.delete(user)
 
-    followed = Repo.get(User, followed.id)
-    follower = Repo.get(User, follower.id)
-    user = Repo.get(User, user.id)
+    followed = User.get_by_id(followed.id)
+    follower = User.get_by_id(follower.id)
+    user = User.get_by_id(user.id)
 
     assert user.info.deactivated
 
@@ -819,7 +837,7 @@ defmodule Pleroma.UserTest do
 
     # TODO: Remove favorites, repeats, delete activities.
 
-    refute Repo.get(Activity, activity.id)
+    refute Activity.get_by_id(activity.id)
   end
 
   test "get_public_key_for_ap_id fetches a user that's not in the db" do
@@ -1107,21 +1125,4 @@ defmodule Pleroma.UserTest do
     assert {:ok, user_state3} = User.bookmark(user, id2)
     assert user_state3.bookmarks == [id2]
   end
-
-  describe "search for admin" do
-    test "it ignores case" do
-      insert(:user, nickname: "papercoach")
-      insert(:user, nickname: "CanadaPaperCoach")
-
-      {:ok, _results, count} =
-        User.search_for_admin(%{
-          query: "paper",
-          local: false,
-          page: 1,
-          page_size: 50
-        })
-
-      assert count == 2
-    end
-  end
 end
index a1e83b380ace08b7a6f9640c663f3d0abef006b5..8dd8e7e0ab0ca669e2225d0522d718e6072cdb11 100644 (file)
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
   alias Pleroma.Activity
   alias Pleroma.Instances
   alias Pleroma.Object
-  alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ObjectView
   alias Pleroma.Web.ActivityPub.UserView
@@ -51,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
         |> put_req_header("accept", "application/json")
         |> get("/users/#{user.nickname}")
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
 
       assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
     end
@@ -66,7 +65,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
         |> put_req_header("accept", "application/activity+json")
         |> get("/users/#{user.nickname}")
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
 
       assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
     end
@@ -84,7 +83,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
         )
         |> get("/users/#{user.nickname}")
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
 
       assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
     end
@@ -543,7 +542,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
       user = insert(:user)
 
       Enum.each(1..15, fn _ ->
-        user = Repo.get(User, user.id)
+        user = User.get_by_id(user.id)
         other_user = insert(:user)
         User.follow(user, other_user)
       end)
index 40bcced33dcfda65b3039cdcb8afb6f3ed18c87a..46b4cf7b6d18d232bbf73eb7a5591f452080ae0a 100644 (file)
@@ -218,18 +218,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       user = insert(:user)
 
       {:ok, _} =
-        CommonAPI.post(Repo.get(User, user.id), %{"status" => "1", "visibility" => "public"})
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "1", "visibility" => "public"})
 
       {:ok, _} =
-        CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "unlisted"})
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "unlisted"})
 
       {:ok, _} =
-        CommonAPI.post(Repo.get(User, user.id), %{"status" => "2", "visibility" => "private"})
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "2", "visibility" => "private"})
 
       {:ok, _} =
-        CommonAPI.post(Repo.get(User, user.id), %{"status" => "3", "visibility" => "direct"})
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "3", "visibility" => "direct"})
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
       assert user.info.note_count == 2
     end
 
@@ -322,7 +322,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     {:ok, user} = User.block(user, %{ap_id: activity_three.data["actor"]})
     {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
     %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
-    activity_three = Repo.get(Activity, activity_three.id)
+    activity_three = Activity.get_by_id(activity_three.id)
 
     activities =
       ActivityPub.fetch_activities([], %{"blocking_user" => user, "skip_preload" => true})
@@ -380,7 +380,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     {:ok, user} = User.mute(user, %User{ap_id: activity_three.data["actor"]})
     {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.repeat(activity_three.id, booster)
     %Activity{} = boost_activity = Activity.get_create_by_object_ap_id(id)
-    activity_three = Repo.get(Activity, activity_three.id)
+    activity_three = Activity.get_by_id(activity_three.id)
 
     activities =
       ActivityPub.fetch_activities([], %{"muting_user" => user, "skip_preload" => true})
@@ -494,7 +494,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
 
       activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
 
-      refute Enum.member?(activities, activity)
+      refute Enum.any?(activities, fn %{id: id} -> id == activity.id end)
+    end
+
+    test "returns reblogs for users for whom reblogs have not been muted" do
+      activity = insert(:note_activity)
+      user = insert(:user)
+      booster = insert(:user)
+      {:ok, user} = CommonAPI.hide_reblogs(user, booster)
+      {:ok, user} = CommonAPI.show_reblogs(user, booster)
+
+      {:ok, activity, _} = CommonAPI.repeat(activity.id, booster)
+
+      activities = ActivityPub.fetch_activities([], %{"muting_user" => user})
+
+      assert Enum.any?(activities, fn %{id: id} -> id == activity.id end)
     end
   end
 
@@ -545,7 +559,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       {:ok, _, _, object} = ActivityPub.unlike(user, object)
       assert object.data["like_count"] == 0
 
-      assert Repo.get(Activity, like_activity.id) == nil
+      assert Activity.get_by_id(like_activity.id) == nil
     end
   end
 
@@ -596,7 +610,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert unannounce_activity.data["actor"] == user.ap_id
       assert unannounce_activity.data["context"] == announce_activity.data["context"]
 
-      assert Repo.get(Activity, announce_activity.id) == nil
+      assert Activity.get_by_id(announce_activity.id) == nil
     end
   end
 
@@ -624,8 +638,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
   describe "fetch the latest Follow" do
     test "fetches the latest Follow activity" do
       %Activity{data: %{"type" => "Follow"}} = activity = insert(:follow_activity)
-      follower = Repo.get_by(User, ap_id: activity.data["actor"])
-      followed = Repo.get_by(User, ap_id: activity.data["object"])
+      follower = User.get_by_ap_id(activity.data["actor"])
+      followed = User.get_by_ap_id(activity.data["object"])
 
       assert activity == Utils.fetch_latest_follow(follower, followed)
     end
@@ -735,7 +749,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       assert delete.data["actor"] == note.data["actor"]
       assert delete.data["object"] == note.data["object"]["id"]
 
-      assert Repo.get(Activity, delete.id) != nil
+      assert Activity.get_by_id(delete.id) != nil
 
       assert Repo.get(Object, object.id).data["type"] == "Tombstone"
     end
@@ -744,23 +758,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       user = insert(:user, info: %{note_count: 10})
 
       {:ok, a1} =
-        CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "public"})
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "public"})
 
       {:ok, a2} =
-        CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "unlisted"})
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "unlisted"})
 
       {:ok, a3} =
-        CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "private"})
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "private"})
 
       {:ok, a4} =
-        CommonAPI.post(Repo.get(User, user.id), %{"status" => "yeah", "visibility" => "direct"})
+        CommonAPI.post(User.get_by_id(user.id), %{"status" => "yeah", "visibility" => "direct"})
 
       {:ok, _} = a1.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
       {:ok, _} = a2.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
       {:ok, _} = a3.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
       {:ok, _} = a4.data["object"]["id"] |> Object.get_by_ap_id() |> ActivityPub.delete()
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
       assert user.info.note_count == 10
     end
 
index 50e8e40bdd57a9e8f7210fba5b9482ba7c333862..62b973c4ff8df6b3b929b871a513a1a3c52d991d 100644 (file)
@@ -461,7 +461,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
 
-      refute Repo.get(Activity, activity.id)
+      refute Activity.get_by_id(activity.id)
     end
 
     test "it fails for incoming deletes with spoofed origin" do
@@ -481,7 +481,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       :error = Transmogrifier.handle_incoming(data)
 
-      assert Repo.get(Activity, activity.id)
+      assert Activity.get_by_id(activity.id)
     end
 
     test "it works for incoming unannounces with an existing notice" do
@@ -639,7 +639,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       assert activity.data["object"] == follow_activity.data["id"]
 
-      follower = Repo.get(User, follower.id)
+      follower = User.get_by_id(follower.id)
 
       assert User.following?(follower, followed) == true
     end
@@ -661,7 +661,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
       assert activity.data["object"] == follow_activity.data["id"]
 
-      follower = Repo.get(User, follower.id)
+      follower = User.get_by_id(follower.id)
 
       assert User.following?(follower, followed) == true
     end
@@ -681,7 +681,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       {:ok, activity} = Transmogrifier.handle_incoming(accept_data)
       assert activity.data["object"] == follow_activity.data["id"]
 
-      follower = Repo.get(User, follower.id)
+      follower = User.get_by_id(follower.id)
 
       assert User.following?(follower, followed) == true
     end
@@ -700,7 +700,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       :error = Transmogrifier.handle_incoming(accept_data)
 
-      follower = Repo.get(User, follower.id)
+      follower = User.get_by_id(follower.id)
 
       refute User.following?(follower, followed) == true
     end
@@ -719,7 +719,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       :error = Transmogrifier.handle_incoming(accept_data)
 
-      follower = Repo.get(User, follower.id)
+      follower = User.get_by_id(follower.id)
 
       refute User.following?(follower, followed) == true
     end
@@ -744,7 +744,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       {:ok, activity} = Transmogrifier.handle_incoming(reject_data)
       refute activity.local
 
-      follower = Repo.get(User, follower.id)
+      follower = User.get_by_id(follower.id)
 
       assert User.following?(follower, followed) == false
     end
@@ -766,7 +766,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       {:ok, %Activity{data: _}} = Transmogrifier.handle_incoming(reject_data)
 
-      follower = Repo.get(User, follower.id)
+      follower = User.get_by_id(follower.id)
 
       assert User.following?(follower, followed) == false
     end
@@ -1020,7 +1020,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       {:ok, unrelated_activity} = CommonAPI.post(user_two, %{"status" => "test"})
       assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
       assert user.info.note_count == 1
 
       {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
@@ -1031,10 +1031,10 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       # Wait for the background task
       :timer.sleep(1000)
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
       assert user.info.note_count == 1
 
-      activity = Repo.get(Activity, activity.id)
+      activity = Activity.get_by_id(activity.id)
       assert user.follower_address in activity.recipients
 
       assert %{
@@ -1057,10 +1057,10 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       refute "..." in activity.recipients
 
-      unrelated_activity = Repo.get(Activity, unrelated_activity.id)
+      unrelated_activity = Activity.get_by_id(unrelated_activity.id)
       refute user.follower_address in unrelated_activity.recipients
 
-      user_two = Repo.get(User, user_two.id)
+      user_two = User.get_by_id(user_two.id)
       assert user.follower_address in user_two.following
       refute "..." in user_two.following
     end
index 0bc1d4728f2296f29b5c52cae442beef1b139fa0..9fb9455d2c6693c95900d4c10ec869a3d4b6caa1 100644 (file)
@@ -16,6 +16,29 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
     assert String.contains?(result["publicKey"]["publicKeyPem"], "BEGIN PUBLIC KEY")
   end
 
+  test "Does not add an avatar image if the user hasn't set one" do
+    user = insert(:user)
+    {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+
+    result = UserView.render("user.json", %{user: user})
+    refute result["icon"]
+    refute result["image"]
+
+    user =
+      insert(:user,
+        avatar: %{"url" => [%{"href" => "https://someurl"}]},
+        info: %{
+          banner: %{"url" => [%{"href" => "https://somebanner"}]}
+        }
+      )
+
+    {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
+
+    result = UserView.render("user.json", %{user: user})
+    assert result["icon"]["url"] == "https://someurl"
+    assert result["image"]["url"] == "https://somebanner"
+  end
+
   describe "endpoints" do
     test "local users have a usable endpoints structure" do
       user = insert(:user)
index 0aab7f26257490fd612317491323587458c77a26..acae643614dcf1ea265ca5ed3ca5e3fe32867c4b 100644 (file)
@@ -5,7 +5,6 @@
 defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
   use Pleroma.Web.ConnCase
 
-  alias Pleroma.Repo
   alias Pleroma.User
   import Pleroma.Factory
 
@@ -40,6 +39,41 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
     end
   end
 
+  describe "/api/pleroma/admin/users/:nickname" do
+    test "Show", %{conn: conn} do
+      admin = insert(:user, info: %{is_admin: true})
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, admin)
+        |> get("/api/pleroma/admin/users/#{user.nickname}")
+
+      expected = %{
+        "deactivated" => false,
+        "id" => to_string(user.id),
+        "local" => true,
+        "nickname" => user.nickname,
+        "roles" => %{"admin" => false, "moderator" => false},
+        "tags" => []
+      }
+
+      assert expected == json_response(conn, 200)
+    end
+
+    test "when the user doesn't exist", %{conn: conn} do
+      admin = insert(:user, info: %{is_admin: true})
+      user = build(:user)
+
+      conn =
+        conn
+        |> assign(:user, admin)
+        |> get("/api/pleroma/admin/users/#{user.nickname}")
+
+      assert "Not found" == json_response(conn, 404)
+    end
+  end
+
   describe "PUT /api/pleroma/admin/users/tag" do
     setup do
       admin = insert(:user, info: %{is_admin: true})
@@ -66,13 +100,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       user2: user2
     } do
       assert json_response(conn, :no_content)
-      assert Repo.get(User, user1.id).tags == ["x", "foo", "bar"]
-      assert Repo.get(User, user2.id).tags == ["y", "foo", "bar"]
+      assert User.get_by_id(user1.id).tags == ["x", "foo", "bar"]
+      assert User.get_by_id(user2.id).tags == ["y", "foo", "bar"]
     end
 
     test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
       assert json_response(conn, :no_content)
-      assert Repo.get(User, user3.id).tags == ["unchanged"]
+      assert User.get_by_id(user3.id).tags == ["unchanged"]
     end
   end
 
@@ -102,13 +136,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       user2: user2
     } do
       assert json_response(conn, :no_content)
-      assert Repo.get(User, user1.id).tags == []
-      assert Repo.get(User, user2.id).tags == ["y"]
+      assert User.get_by_id(user1.id).tags == []
+      assert User.get_by_id(user2.id).tags == ["y"]
     end
 
     test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
       assert json_response(conn, :no_content)
-      assert Repo.get(User, user3.id).tags == ["unchanged"]
+      assert User.get_by_id(user3.id).tags == ["unchanged"]
     end
   end
 
@@ -178,7 +212,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
         conn
         |> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: false})
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
       assert user.info.deactivated == true
       assert json_response(conn, :no_content)
     end
@@ -190,7 +224,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
         conn
         |> put("/api/pleroma/admin/activation_status/#{user.nickname}", %{status: true})
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
       assert user.info.deactivated == false
       assert json_response(conn, :no_content)
     end
@@ -408,13 +442,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
 
     test "regular search with page size" do
       admin = insert(:user, info: %{is_admin: true})
-      user = insert(:user, nickname: "bob")
-      user2 = insert(:user, nickname: "bo")
+      user = insert(:user, nickname: "aalice")
+      user2 = insert(:user, nickname: "alice")
 
       conn =
         build_conn()
         |> assign(:user, admin)
-        |> get("/api/pleroma/admin/users?query=bo&page_size=1&page=1")
+        |> get("/api/pleroma/admin/users?query=a&page_size=1&page=1")
 
       assert json_response(conn, 200) == %{
                "count" => 2,
@@ -434,7 +468,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       conn =
         build_conn()
         |> assign(:user, admin)
-        |> get("/api/pleroma/admin/users?query=bo&page_size=1&page=2")
+        |> get("/api/pleroma/admin/users?query=a&page_size=1&page=2")
 
       assert json_response(conn, 200) == %{
                "count" => 2,
@@ -461,7 +495,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       conn =
         build_conn()
         |> assign(:user, admin)
-        |> get("/api/pleroma/admin/users?query=bo&local_only=true")
+        |> get("/api/pleroma/admin/users?query=bo&filters=local")
 
       assert json_response(conn, 200) == %{
                "count" => 1,
@@ -488,7 +522,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
       conn =
         build_conn()
         |> assign(:user, admin)
-        |> get("/api/pleroma/admin/users?local_only=true")
+        |> get("/api/pleroma/admin/users?filters=local")
 
       assert json_response(conn, 200) == %{
                "count" => 2,
@@ -513,6 +547,34 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
                ]
              }
     end
+
+    test "it works with multiple filters" do
+      admin = insert(:user, nickname: "john", info: %{is_admin: true})
+      user = insert(:user, nickname: "bob", local: false, info: %{deactivated: true})
+
+      insert(:user, nickname: "ken", local: true, info: %{deactivated: true})
+      insert(:user, nickname: "bobb", local: false, info: %{deactivated: false})
+
+      conn =
+        build_conn()
+        |> assign(:user, admin)
+        |> get("/api/pleroma/admin/users?filters=deactivated,external")
+
+      assert json_response(conn, 200) == %{
+               "count" => 1,
+               "page_size" => 50,
+               "users" => [
+                 %{
+                   "deactivated" => user.info.deactivated,
+                   "id" => user.id,
+                   "nickname" => user.nickname,
+                   "roles" => %{"admin" => false, "moderator" => false},
+                   "local" => user.local,
+                   "tags" => []
+                 }
+               ]
+             }
+    end
   end
 
   test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
diff --git a/test/web/admin_api/search_test.exs b/test/web/admin_api/search_test.exs
new file mode 100644 (file)
index 0000000..3950996
--- /dev/null
@@ -0,0 +1,88 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.SearchTest do
+  use Pleroma.Web.ConnCase
+
+  alias Pleroma.Web.AdminAPI.Search
+
+  import Pleroma.Factory
+
+  describe "search for admin" do
+    test "it ignores case" do
+      insert(:user, nickname: "papercoach")
+      insert(:user, nickname: "CanadaPaperCoach")
+
+      {:ok, _results, count} =
+        Search.user(%{
+          query: "paper",
+          local: false,
+          page: 1,
+          page_size: 50
+        })
+
+      assert count == 2
+    end
+
+    test "it returns local/external users" do
+      insert(:user, local: true)
+      insert(:user, local: false)
+      insert(:user, local: false)
+
+      {:ok, _results, local_count} =
+        Search.user(%{
+          query: "",
+          local: true
+        })
+
+      {:ok, _results, external_count} =
+        Search.user(%{
+          query: "",
+          external: true
+        })
+
+      assert local_count == 1
+      assert external_count == 2
+    end
+
+    test "it returns active/deactivated users" do
+      insert(:user, info: %{deactivated: true})
+      insert(:user, info: %{deactivated: true})
+      insert(:user, info: %{deactivated: false})
+
+      {:ok, _results, active_count} =
+        Search.user(%{
+          query: "",
+          active: true
+        })
+
+      {:ok, _results, deactivated_count} =
+        Search.user(%{
+          query: "",
+          deactivated: true
+        })
+
+      assert active_count == 1
+      assert deactivated_count == 2
+    end
+
+    test "it returns specific user" do
+      insert(:user)
+      insert(:user)
+      insert(:user, nickname: "bob", local: true, info: %{deactivated: false})
+
+      {:ok, _results, total_count} = Search.user(%{query: ""})
+
+      {:ok, _results, count} =
+        Search.user(%{
+          query: "Bo",
+          active: true,
+          local: true
+        })
+
+      assert total_count == 3
+      assert count == 1
+    end
+  end
+end
index b2302422b6aac7792f9872b0354e282237375d5b..1f3b268800fe843fcd6860c311a22788f0c36249 100644 (file)
@@ -14,7 +14,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.MastodonAPI.FilterView
+  alias Pleroma.Web.OAuth.App
   alias Pleroma.Web.OStatus
+  alias Pleroma.Web.Push
   alias Pleroma.Web.TwitterAPI.TwitterAPI
   import Pleroma.Factory
   import ExUnit.CaptureLog
@@ -99,7 +101,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
              json_response(conn_one, 200)
 
-    assert Repo.get(Activity, id)
+    assert Activity.get_by_id(id)
 
     conn_two =
       conn
@@ -138,7 +140,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
 
     assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
-    assert Repo.get(Activity, id)
+    assert Activity.get_by_id(id)
   end
 
   test "posting a status with OGP link preview", %{conn: conn} do
@@ -153,7 +155,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       })
 
     assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
-    assert Repo.get(Activity, id)
+    assert Activity.get_by_id(id)
     Pleroma.Config.put([:rich_media, :enabled], false)
   end
 
@@ -168,7 +170,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
 
     assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
-    assert activity = Repo.get(Activity, id)
+    assert activity = Activity.get_by_id(id)
     assert activity.recipients == [user2.ap_id, user1.ap_id]
     assert activity.data["to"] == [user2.ap_id]
     assert activity.data["cc"] == []
@@ -287,7 +289,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
 
-    activity = Repo.get(Activity, id)
+    activity = Activity.get_by_id(id)
 
     assert activity.data["context"] == replied_to.data["context"]
     assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
@@ -303,7 +305,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
 
-    activity = Repo.get(Activity, id)
+    activity = Activity.get_by_id(id)
 
     assert activity
   end
@@ -332,6 +334,53 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     assert id == to_string(user.id)
   end
 
+  test "apps/verify_credentials", %{conn: conn} do
+    token = insert(:oauth_token)
+
+    conn =
+      conn
+      |> assign(:user, token.user)
+      |> assign(:token, token)
+      |> get("/api/v1/apps/verify_credentials")
+
+    app = Repo.preload(token, :app).app
+
+    expected = %{
+      "name" => app.client_name,
+      "website" => app.website,
+      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
+    }
+
+    assert expected == json_response(conn, 200)
+  end
+
+  test "creates an oauth app", %{conn: conn} do
+    user = insert(:user)
+    app_attrs = build(:oauth_app)
+
+    conn =
+      conn
+      |> assign(:user, user)
+      |> post("/api/v1/apps", %{
+        client_name: app_attrs.client_name,
+        redirect_uris: app_attrs.redirect_uris
+      })
+
+    [app] = Repo.all(App)
+
+    expected = %{
+      "name" => app.client_name,
+      "website" => app.website,
+      "client_id" => app.client_id,
+      "client_secret" => app.client_secret,
+      "id" => app.id |> to_string(),
+      "redirect_uri" => app.redirect_uris,
+      "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
+    }
+
+    assert expected == json_response(conn, 200)
+  end
+
   test "get a status", %{conn: conn} do
     activity = insert(:note_activity)
 
@@ -355,7 +404,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       assert %{} = json_response(conn, 200)
 
-      refute Repo.get(Activity, activity.id)
+      refute Activity.get_by_id(activity.id)
     end
 
     test "when you didn't create it", %{conn: conn} do
@@ -369,7 +418,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       assert %{"error" => _} = json_response(conn, 403)
 
-      assert Repo.get(Activity, activity.id) == activity
+      assert Activity.get_by_id(activity.id) == activity
     end
 
     test "when you're an admin or moderator", %{conn: conn} do
@@ -392,8 +441,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       assert %{} = json_response(res_conn, 200)
 
-      refute Repo.get(Activity, activity1.id)
-      refute Repo.get(Activity, activity2.id)
+      refute Activity.get_by_id(activity1.id)
+      refute Activity.get_by_id(activity2.id)
     end
   end
 
@@ -1063,8 +1112,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       {:ok, _activity} = ActivityPub.follow(other_user, user)
 
-      user = Repo.get(User, user.id)
-      other_user = Repo.get(User, other_user.id)
+      user = User.get_by_id(user.id)
+      other_user = User.get_by_id(other_user.id)
 
       assert User.following?(other_user, user) == false
 
@@ -1083,8 +1132,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       {:ok, _activity} = ActivityPub.follow(other_user, user)
 
-      user = Repo.get(User, user.id)
-      other_user = Repo.get(User, other_user.id)
+      user = User.get_by_id(user.id)
+      other_user = User.get_by_id(other_user.id)
 
       assert User.following?(other_user, user) == false
 
@@ -1096,8 +1145,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       assert relationship = json_response(conn, 200)
       assert to_string(other_user.id) == relationship["id"]
 
-      user = Repo.get(User, user.id)
-      other_user = Repo.get(User, other_user.id)
+      user = User.get_by_id(user.id)
+      other_user = User.get_by_id(other_user.id)
 
       assert User.following?(other_user, user) == true
     end
@@ -1120,7 +1169,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
       {:ok, _activity} = ActivityPub.follow(other_user, user)
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
 
       conn =
         build_conn()
@@ -1130,8 +1179,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       assert relationship = json_response(conn, 200)
       assert to_string(other_user.id) == relationship["id"]
 
-      user = Repo.get(User, user.id)
-      other_user = Repo.get(User, other_user.id)
+      user = User.get_by_id(user.id)
+      other_user = User.get_by_id(other_user.id)
 
       assert User.following?(other_user, user) == false
     end
@@ -1416,7 +1465,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     assert %{"id" => _id, "following" => true} = json_response(conn, 200)
 
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
 
     conn =
       build_conn()
@@ -1425,7 +1474,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     assert %{"id" => _id, "following" => false} = json_response(conn, 200)
 
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
 
     conn =
       build_conn()
@@ -1447,7 +1496,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
 
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
 
     conn =
       build_conn()
@@ -1483,7 +1532,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
 
     assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
 
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
 
     conn =
       build_conn()
@@ -1808,6 +1857,27 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
   end
 
   test "get instance information", %{conn: conn} do
+    conn = get(conn, "/api/v1/instance")
+    assert result = json_response(conn, 200)
+
+    # Note: not checking for "max_toot_chars" since it's optional
+    assert %{
+             "uri" => _,
+             "title" => _,
+             "description" => _,
+             "version" => _,
+             "email" => _,
+             "urls" => %{
+               "streaming_api" => _
+             },
+             "stats" => _,
+             "thumbnail" => _,
+             "languages" => _,
+             "registrations" => _
+           } = result
+  end
+
+  test "get instance stats", %{conn: conn} do
     user = insert(:user, %{local: true})
 
     user2 = insert(:user, %{local: true})
@@ -1819,7 +1889,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
 
     # Stats should count users with missing or nil `info.deactivated` value
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
     info_change = Changeset.change(user.info, %{deactivated: nil})
 
     {:ok, _user} =
@@ -2195,4 +2265,30 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
       assert link_header =~ ~r/max_id=#{notification1.id}/
     end
   end
+
+  test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
+    # Need to set an old-style integer ID to reproduce the problem
+    # (these are no longer assigned to new accounts but were preserved
+    # for existing accounts during the migration to flakeIDs)
+    user_one = insert(:user, %{id: 1212})
+    user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
+
+    resp_one =
+      conn
+      |> get("/api/v1/accounts/#{user_one.id}")
+
+    resp_two =
+      conn
+      |> get("/api/v1/accounts/#{user_two.nickname}")
+
+    resp_three =
+      conn
+      |> get("/api/v1/accounts/#{user_two.id}")
+
+    acc_one = json_response(resp_one, 200)
+    acc_two = json_response(resp_two, 200)
+    acc_three = json_response(resp_three, 200)
+    refute acc_one == acc_two
+    assert acc_two == acc_three
+  end
 end
index b826a7e612423fbe304abb96d6d4e1516ef6a2a0..f2c1eb76c487d993cc408f000fbfc8180b5ef6a2 100644 (file)
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
     mentioned_user = insert(:user)
     {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{mentioned_user.nickname}"})
     {:ok, [notification]} = Notification.create_notifications(activity)
-    user = Repo.get(User, user.id)
+    user = User.get_by_id(user.id)
 
     expected = %{
       id: to_string(notification.id),
@@ -44,7 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
     {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
     {:ok, favorite_activity, _object} = CommonAPI.favorite(create_activity.id, another_user)
     {:ok, [notification]} = Notification.create_notifications(favorite_activity)
-    create_activity = Repo.get(Activity, create_activity.id)
+    create_activity = Activity.get_by_id(create_activity.id)
 
     expected = %{
       id: to_string(notification.id),
@@ -66,7 +66,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
     {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
     {:ok, reblog_activity, _object} = CommonAPI.repeat(create_activity.id, another_user)
     {:ok, [notification]} = Notification.create_notifications(reblog_activity)
-    reblog_activity = Repo.get(Activity, create_activity.id)
+    reblog_activity = Activity.get_by_id(create_activity.id)
 
     expected = %{
       id: to_string(notification.id),
index e1c9b2c8f61a03897673143f77800204d8b346ae..8db92ac160fd43efe0d8cf138d3115eb81eb7db4 100644 (file)
@@ -175,7 +175,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
 
     status = StatusView.render("status.json", %{activity: activity})
 
-    actor = Repo.get_by(User, ap_id: activity.actor)
+    actor = User.get_by_ap_id(activity.actor)
 
     assert status.mentions ==
              Enum.map([user, actor], fn u -> AccountView.render("mention.json", %{user: u}) end)
index 84ec7b4eef7354d15c53065f2800a0283eff9a9a..a9a0b9ed4c6b8eb8fd19b8da6eff0210824afef7 100644 (file)
@@ -10,261 +10,339 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
   alias Pleroma.Web.OAuth.Authorization
   alias Pleroma.Web.OAuth.Token
 
-  test "redirects with oauth authorization" do
-    user = insert(:user)
-    app = insert(:oauth_app, scopes: ["read", "write", "follow"])
-
-    conn =
-      build_conn()
-      |> post("/oauth/authorize", %{
-        "authorization" => %{
-          "name" => user.nickname,
-          "password" => "test",
-          "client_id" => app.client_id,
-          "redirect_uri" => app.redirect_uris,
-          "scope" => "read write",
-          "state" => "statepassed"
-        }
-      })
+  describe "GET /oauth/authorize" do
+    setup do
+      session_opts = [
+        store: :cookie,
+        key: "_test",
+        signing_salt: "cooldude"
+      ]
+
+      [
+        app: insert(:oauth_app, redirect_uris: "https://redirect.url"),
+        conn:
+          build_conn()
+          |> Plug.Session.call(Plug.Session.init(session_opts))
+          |> fetch_session()
+      ]
+    end
 
-    target = redirected_to(conn)
-    assert target =~ app.redirect_uris
+    test "renders authentication page", %{app: app, conn: conn} do
+      conn =
+        get(
+          conn,
+          "/oauth/authorize",
+          %{
+            "response_type" => "code",
+            "client_id" => app.client_id,
+            "redirect_uri" => app.redirect_uris,
+            "scope" => "read"
+          }
+        )
+
+      assert html_response(conn, 200) =~ ~s(type="submit")
+    end
 
-    query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
+    test "renders authentication page if user is already authenticated but `force_login` is tru-ish",
+         %{app: app, conn: conn} do
+      token = insert(:oauth_token, app_id: app.id)
+
+      conn =
+        conn
+        |> put_session(:oauth_token, token.token)
+        |> get(
+          "/oauth/authorize",
+          %{
+            "response_type" => "code",
+            "client_id" => app.client_id,
+            "redirect_uri" => app.redirect_uris,
+            "scope" => "read",
+            "force_login" => "true"
+          }
+        )
+
+      assert html_response(conn, 200) =~ ~s(type="submit")
+    end
 
-    assert %{"state" => "statepassed", "code" => code} = query
-    auth = Repo.get_by(Authorization, token: code)
-    assert auth
-    assert auth.scopes == ["read", "write"]
+    test "redirects to app if user is already authenticated", %{app: app, conn: conn} do
+      token = insert(:oauth_token, app_id: app.id)
+
+      conn =
+        conn
+        |> put_session(:oauth_token, token.token)
+        |> get(
+          "/oauth/authorize",
+          %{
+            "response_type" => "code",
+            "client_id" => app.client_id,
+            "redirect_uri" => app.redirect_uris,
+            "scope" => "read"
+          }
+        )
+
+      assert redirected_to(conn) == "https://redirect.url"
+    end
   end
 
-  test "returns 401 for wrong credentials", %{conn: conn} do
-    user = insert(:user)
-    app = insert(:oauth_app)
+  describe "POST /oauth/authorize" do
+    test "redirects with oauth authorization" do
+      user = insert(:user)
+      app = insert(:oauth_app, scopes: ["read", "write", "follow"])
+
+      conn =
+        build_conn()
+        |> post("/oauth/authorize", %{
+          "authorization" => %{
+            "name" => user.nickname,
+            "password" => "test",
+            "client_id" => app.client_id,
+            "redirect_uri" => app.redirect_uris,
+            "scope" => "read write",
+            "state" => "statepassed"
+          }
+        })
+
+      target = redirected_to(conn)
+      assert target =~ app.redirect_uris
+
+      query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
+
+      assert %{"state" => "statepassed", "code" => code} = query
+      auth = Repo.get_by(Authorization, token: code)
+      assert auth
+      assert auth.scopes == ["read", "write"]
+    end
 
-    result =
-      conn
-      |> post("/oauth/authorize", %{
-        "authorization" => %{
-          "name" => user.nickname,
-          "password" => "wrong",
-          "client_id" => app.client_id,
-          "redirect_uri" => app.redirect_uris,
-          "state" => "statepassed",
-          "scope" => Enum.join(app.scopes, " ")
-        }
-      })
-      |> html_response(:unauthorized)
-
-    # Keep the details
-    assert result =~ app.client_id
-    assert result =~ app.redirect_uris
-
-    # Error message
-    assert result =~ "Invalid Username/Password"
-  end
+    test "returns 401 for wrong credentials", %{conn: conn} do
+      user = insert(:user)
+      app = insert(:oauth_app)
+
+      result =
+        conn
+        |> post("/oauth/authorize", %{
+          "authorization" => %{
+            "name" => user.nickname,
+            "password" => "wrong",
+            "client_id" => app.client_id,
+            "redirect_uri" => app.redirect_uris,
+            "state" => "statepassed",
+            "scope" => Enum.join(app.scopes, " ")
+          }
+        })
+        |> html_response(:unauthorized)
+
+      # Keep the details
+      assert result =~ app.client_id
+      assert result =~ app.redirect_uris
+
+      # Error message
+      assert result =~ "Invalid Username/Password"
+    end
 
-  test "returns 401 for missing scopes", %{conn: conn} do
-    user = insert(:user)
-    app = insert(:oauth_app)
+    test "returns 401 for missing scopes", %{conn: conn} do
+      user = insert(:user)
+      app = insert(:oauth_app)
+
+      result =
+        conn
+        |> post("/oauth/authorize", %{
+          "authorization" => %{
+            "name" => user.nickname,
+            "password" => "test",
+            "client_id" => app.client_id,
+            "redirect_uri" => app.redirect_uris,
+            "state" => "statepassed",
+            "scope" => ""
+          }
+        })
+        |> html_response(:unauthorized)
+
+      # Keep the details
+      assert result =~ app.client_id
+      assert result =~ app.redirect_uris
+
+      # Error message
+      assert result =~ "This action is outside the authorized scopes"
+    end
 
-    result =
-      conn
-      |> post("/oauth/authorize", %{
-        "authorization" => %{
-          "name" => user.nickname,
-          "password" => "test",
-          "client_id" => app.client_id,
-          "redirect_uri" => app.redirect_uris,
-          "state" => "statepassed",
-          "scope" => ""
-        }
-      })
-      |> html_response(:unauthorized)
-
-    # Keep the details
-    assert result =~ app.client_id
-    assert result =~ app.redirect_uris
-
-    # Error message
-    assert result =~ "This action is outside the authorized scopes"
+    test "returns 401 for scopes beyond app scopes", %{conn: conn} do
+      user = insert(:user)
+      app = insert(:oauth_app, scopes: ["read", "write"])
+
+      result =
+        conn
+        |> post("/oauth/authorize", %{
+          "authorization" => %{
+            "name" => user.nickname,
+            "password" => "test",
+            "client_id" => app.client_id,
+            "redirect_uri" => app.redirect_uris,
+            "state" => "statepassed",
+            "scope" => "read write follow"
+          }
+        })
+        |> html_response(:unauthorized)
+
+      # Keep the details
+      assert result =~ app.client_id
+      assert result =~ app.redirect_uris
+
+      # Error message
+      assert result =~ "This action is outside the authorized scopes"
+    end
   end
 
-  test "returns 401 for scopes beyond app scopes", %{conn: conn} do
-    user = insert(:user)
-    app = insert(:oauth_app, scopes: ["read", "write"])
+  describe "POST /oauth/token" do
+    test "issues a token for an all-body request" do
+      user = insert(:user)
+      app = insert(:oauth_app, scopes: ["read", "write"])
 
-    result =
-      conn
-      |> post("/oauth/authorize", %{
-        "authorization" => %{
-          "name" => user.nickname,
-          "password" => "test",
-          "client_id" => app.client_id,
+      {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
+
+      conn =
+        build_conn()
+        |> post("/oauth/token", %{
+          "grant_type" => "authorization_code",
+          "code" => auth.token,
           "redirect_uri" => app.redirect_uris,
-          "state" => "statepassed",
-          "scope" => "read write follow"
-        }
-      })
-      |> html_response(:unauthorized)
-
-    # Keep the details
-    assert result =~ app.client_id
-    assert result =~ app.redirect_uris
-
-    # Error message
-    assert result =~ "This action is outside the authorized scopes"
-  end
+          "client_id" => app.client_id,
+          "client_secret" => app.client_secret
+        })
 
-  test "issues a token for an all-body request" do
-    user = insert(:user)
-    app = insert(:oauth_app, scopes: ["read", "write"])
+      assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200)
 
-    {:ok, auth} = Authorization.create_authorization(app, user, ["write"])
+      token = Repo.get_by(Token, token: token)
+      assert token
+      assert token.scopes == auth.scopes
+      assert user.ap_id == ap_id
+    end
 
-    conn =
-      build_conn()
-      |> post("/oauth/token", %{
-        "grant_type" => "authorization_code",
-        "code" => auth.token,
-        "redirect_uri" => app.redirect_uris,
-        "client_id" => app.client_id,
-        "client_secret" => app.client_secret
-      })
+    test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
+      password = "testpassword"
+      user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
 
-    assert %{"access_token" => token, "me" => ap_id} = json_response(conn, 200)
+      app = insert(:oauth_app, scopes: ["read", "write"])
 
-    token = Repo.get_by(Token, token: token)
-    assert token
-    assert token.scopes == auth.scopes
-    assert user.ap_id == ap_id
-  end
+      # Note: "scope" param is intentionally omitted
+      conn =
+        build_conn()
+        |> post("/oauth/token", %{
+          "grant_type" => "password",
+          "username" => user.nickname,
+          "password" => password,
+          "client_id" => app.client_id,
+          "client_secret" => app.client_secret
+        })
 
-  test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
-    password = "testpassword"
-    user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
+      assert %{"access_token" => token} = json_response(conn, 200)
 
-    app = insert(:oauth_app, scopes: ["read", "write"])
+      token = Repo.get_by(Token, token: token)
+      assert token
+      assert token.scopes == app.scopes
+    end
 
-    # Note: "scope" param is intentionally omitted
-    conn =
-      build_conn()
-      |> post("/oauth/token", %{
-        "grant_type" => "password",
-        "username" => user.nickname,
-        "password" => password,
-        "client_id" => app.client_id,
-        "client_secret" => app.client_secret
-      })
+    test "issues a token for request with HTTP basic auth client credentials" do
+      user = insert(:user)
+      app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])
 
-    assert %{"access_token" => token} = json_response(conn, 200)
+      {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"])
+      assert auth.scopes == ["scope1", "scope2"]
 
-    token = Repo.get_by(Token, token: token)
-    assert token
-    assert token.scopes == app.scopes
-  end
+      app_encoded =
+        (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret))
+        |> Base.encode64()
 
-  test "issues a token for request with HTTP basic auth client credentials" do
-    user = insert(:user)
-    app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])
+      conn =
+        build_conn()
+        |> put_req_header("authorization", "Basic " <> app_encoded)
+        |> post("/oauth/token", %{
+          "grant_type" => "authorization_code",
+          "code" => auth.token,
+          "redirect_uri" => app.redirect_uris
+        })
 
-    {:ok, auth} = Authorization.create_authorization(app, user, ["scope1", "scope2"])
-    assert auth.scopes == ["scope1", "scope2"]
+      assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
 
-    app_encoded =
-      (URI.encode_www_form(app.client_id) <> ":" <> URI.encode_www_form(app.client_secret))
-      |> Base.encode64()
+      assert scope == "scope1 scope2"
 
-    conn =
-      build_conn()
-      |> put_req_header("authorization", "Basic " <> app_encoded)
-      |> post("/oauth/token", %{
-        "grant_type" => "authorization_code",
-        "code" => auth.token,
-        "redirect_uri" => app.redirect_uris
-      })
+      token = Repo.get_by(Token, token: token)
+      assert token
+      assert token.scopes == ["scope1", "scope2"]
+    end
 
-    assert %{"access_token" => token, "scope" => scope} = json_response(conn, 200)
+    test "rejects token exchange with invalid client credentials" do
+      user = insert(:user)
+      app = insert(:oauth_app)
 
-    assert scope == "scope1 scope2"
+      {:ok, auth} = Authorization.create_authorization(app, user)
 
-    token = Repo.get_by(Token, token: token)
-    assert token
-    assert token.scopes == ["scope1", "scope2"]
-  end
+      conn =
+        build_conn()
+        |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=")
+        |> post("/oauth/token", %{
+          "grant_type" => "authorization_code",
+          "code" => auth.token,
+          "redirect_uri" => app.redirect_uris
+        })
 
-  test "rejects token exchange with invalid client credentials" do
-    user = insert(:user)
-    app = insert(:oauth_app)
+      assert resp = json_response(conn, 400)
+      assert %{"error" => _} = resp
+      refute Map.has_key?(resp, "access_token")
+    end
 
-    {:ok, auth} = Authorization.create_authorization(app, user)
+    test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
+      setting = Pleroma.Config.get([:instance, :account_activation_required])
 
-    conn =
-      build_conn()
-      |> put_req_header("authorization", "Basic JTIxOiVGMCU5RiVBNCVCNwo=")
-      |> post("/oauth/token", %{
-        "grant_type" => "authorization_code",
-        "code" => auth.token,
-        "redirect_uri" => app.redirect_uris
-      })
+      unless setting do
+        Pleroma.Config.put([:instance, :account_activation_required], true)
+        on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
+      end
 
-    assert resp = json_response(conn, 400)
-    assert %{"error" => _} = resp
-    refute Map.has_key?(resp, "access_token")
-  end
+      password = "testpassword"
+      user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
+      info_change = Pleroma.User.Info.confirmation_changeset(user.info, :unconfirmed)
 
-  test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
-    setting = Pleroma.Config.get([:instance, :account_activation_required])
+      {:ok, user} =
+        user
+        |> Ecto.Changeset.change()
+        |> Ecto.Changeset.put_embed(:info, info_change)
+        |> Repo.update()
 
-    unless setting do
-      Pleroma.Config.put([:instance, :account_activation_required], true)
-      on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
+      refute Pleroma.User.auth_active?(user)
+
+      app = insert(:oauth_app)
+
+      conn =
+        build_conn()
+        |> post("/oauth/token", %{
+          "grant_type" => "password",
+          "username" => user.nickname,
+          "password" => password,
+          "client_id" => app.client_id,
+          "client_secret" => app.client_secret
+        })
+
+      assert resp = json_response(conn, 403)
+      assert %{"error" => _} = resp
+      refute Map.has_key?(resp, "access_token")
     end
 
-    password = "testpassword"
-    user = insert(:user, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
-    info_change = Pleroma.User.Info.confirmation_changeset(user.info, :unconfirmed)
-
-    {:ok, user} =
-      user
-      |> Ecto.Changeset.change()
-      |> Ecto.Changeset.put_embed(:info, info_change)
-      |> Repo.update()
-
-    refute Pleroma.User.auth_active?(user)
-
-    app = insert(:oauth_app)
-
-    conn =
-      build_conn()
-      |> post("/oauth/token", %{
-        "grant_type" => "password",
-        "username" => user.nickname,
-        "password" => password,
-        "client_id" => app.client_id,
-        "client_secret" => app.client_secret
-      })
-
-    assert resp = json_response(conn, 403)
-    assert %{"error" => _} = resp
-    refute Map.has_key?(resp, "access_token")
-  end
+    test "rejects an invalid authorization code" do
+      app = insert(:oauth_app)
 
-  test "rejects an invalid authorization code" do
-    app = insert(:oauth_app)
-
-    conn =
-      build_conn()
-      |> post("/oauth/token", %{
-        "grant_type" => "authorization_code",
-        "code" => "Imobviouslyinvalid",
-        "redirect_uri" => app.redirect_uris,
-        "client_id" => app.client_id,
-        "client_secret" => app.client_secret
-      })
-
-    assert resp = json_response(conn, 400)
-    assert %{"error" => _} = json_response(conn, 400)
-    refute Map.has_key?(resp, "access_token")
+      conn =
+        build_conn()
+        |> post("/oauth/token", %{
+          "grant_type" => "authorization_code",
+          "code" => "Imobviouslyinvalid",
+          "redirect_uri" => app.redirect_uris,
+          "client_id" => app.client_id,
+          "client_secret" => app.client_secret
+        })
+
+      assert resp = json_response(conn, 400)
+      assert %{"error" => _} = json_response(conn, 400)
+      refute Map.has_key?(resp, "access_token")
+    end
   end
 end
index 5cb135b4c065f35390e02f55e2f09e8c678f9f4d..a4bb68c4d9722aa82428b4770227160a34e33b56 100644 (file)
@@ -116,10 +116,10 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do
 
     {:ok, announce, _object} = ActivityPub.announce(user, object)
 
-    announce = Repo.get(Activity, announce.id)
+    announce = Activity.get_by_id(announce.id)
 
     note_user = User.get_cached_by_ap_id(note.data["actor"])
-    note = Repo.get(Activity, note.id)
+    note = Activity.get_by_id(note.id)
 
     note_xml =
       ActivityRepresenter.to_simple_form(note, note_user, true)
index 412d894fd83b1f31c1c1b472e2e32273e1759cca..ca6e6133952b36d1ba0c3f366d05487733087bf2 100644 (file)
@@ -6,7 +6,6 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
 
   alias Pleroma.Activity
   alias Pleroma.Object
-  alias Pleroma.Repo
   alias Pleroma.Web.OStatus
 
   setup do
@@ -32,10 +31,10 @@ defmodule Pleroma.Web.OStatus.DeleteHandlingTest do
 
       {:ok, [delete]} = OStatus.handle_incoming(incoming)
 
-      refute Repo.get(Activity, note.id)
-      refute Repo.get(Activity, like.id)
+      refute Activity.get_by_id(note.id)
+      refute Activity.get_by_id(like.id)
       assert Object.get_by_ap_id(note.data["object"]["id"]).data["type"] == "Tombstone"
-      assert Repo.get(Activity, second_note.id)
+      assert Activity.get_by_id(second_note.id)
       assert Object.get_by_ap_id(second_note.data["object"]["id"])
 
       assert delete.data["type"] == "Delete"
index 76b90e186e6de31603607f3b019733951bdb3ca2..9fd100f63bc0131f992d8a5db64423d590cfcb7a 100644 (file)
@@ -154,7 +154,7 @@ defmodule Pleroma.Web.OStatusTest do
     assert "https://pleroma.soykaf.com/users/lain" in activity.data["to"]
     refute activity.local
 
-    retweeted_activity = Repo.get(Activity, retweeted_activity.id)
+    retweeted_activity = Activity.get_by_id(retweeted_activity.id)
     assert retweeted_activity.data["type"] == "Create"
     assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain"
     refute retweeted_activity.local
@@ -181,7 +181,7 @@ defmodule Pleroma.Web.OStatusTest do
     assert user.ap_id in activity.data["to"]
     refute activity.local
 
-    retweeted_activity = Repo.get(Activity, retweeted_activity.id)
+    retweeted_activity = Activity.get_by_id(retweeted_activity.id)
     assert note_activity.id == retweeted_activity.id
     assert retweeted_activity.data["type"] == "Create"
     assert retweeted_activity.data["actor"] == user.ap_id
@@ -344,7 +344,7 @@ defmodule Pleroma.Web.OStatusTest do
 
       {:ok, user} = OStatus.find_or_make_user(uri)
 
-      user = Repo.get(Pleroma.User, user.id)
+      user = Pleroma.User.get_by_id(user.id)
       assert user.name == "Constance Variable"
       assert user.nickname == "lambadalambda@social.heldscal.la"
       assert user.local == false
index 265e1abbd44588dac1674851f3ece4b0c54ce7de..35503259b933cd2cfe0ba39a5553e4a836cdcffe 100644 (file)
@@ -99,7 +99,7 @@ defmodule Pleroma.Web.Salmon.SalmonTest do
     }
 
     {:ok, activity} = Repo.insert(%Activity{data: activity_data, recipients: activity_data["to"]})
-    user = Repo.get_by(User, ap_id: activity.data["actor"])
+    user = User.get_by_ap_id(activity.data["actor"])
     {:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)
 
     poster = fn url, _data, _headers ->
index 0835400175b057eb7a26fb03225d94741a6fbf79..72b7ea85eba8e001cde0a212aa8a73ca9f09d464 100644 (file)
@@ -719,7 +719,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> with_credentials(current_user.nickname, "test")
         |> post("/api/friendships/create.json", %{user_id: followed.id})
 
-      current_user = Repo.get(User, current_user.id)
+      current_user = User.get_by_id(current_user.id)
       assert User.ap_followers(followed) in current_user.following
 
       assert json_response(conn, 200) ==
@@ -734,8 +734,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> with_credentials(current_user.nickname, "test")
         |> post("/api/friendships/create.json", %{user_id: followed.id})
 
-      current_user = Repo.get(User, current_user.id)
-      followed = Repo.get(User, followed.id)
+      current_user = User.get_by_id(current_user.id)
+      followed = User.get_by_id(followed.id)
 
       refute User.ap_followers(followed) in current_user.following
 
@@ -764,7 +764,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> with_credentials(current_user.nickname, "test")
         |> post("/api/friendships/destroy.json", %{user_id: followed.id})
 
-      current_user = Repo.get(User, current_user.id)
+      current_user = User.get_by_id(current_user.id)
       assert current_user.following == [current_user.ap_id]
 
       assert json_response(conn, 200) ==
@@ -788,7 +788,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> with_credentials(current_user.nickname, "test")
         |> post("/api/blocks/create.json", %{user_id: blocked.id})
 
-      current_user = Repo.get(User, current_user.id)
+      current_user = User.get_by_id(current_user.id)
       assert User.blocks?(current_user, blocked)
 
       assert json_response(conn, 200) ==
@@ -815,7 +815,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> with_credentials(current_user.nickname, "test")
         |> post("/api/blocks/destroy.json", %{user_id: blocked.id})
 
-      current_user = Repo.get(User, current_user.id)
+      current_user = User.get_by_id(current_user.id)
       assert current_user.info.blocks == []
 
       assert json_response(conn, 200) ==
@@ -846,7 +846,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> with_credentials(current_user.nickname, "test")
         |> post("/api/qvitter/update_avatar.json", %{img: avatar_image})
 
-      current_user = Repo.get(User, current_user.id)
+      current_user = User.get_by_id(current_user.id)
       assert is_map(current_user.avatar)
 
       assert json_response(conn, 200) ==
@@ -954,8 +954,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> with_credentials(current_user.nickname, "test")
         |> post(request_path)
 
-      activity = Repo.get(Activity, note_activity.id)
-      activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"])
+      activity = Activity.get_by_id(note_activity.id)
+      activity_user = User.get_by_ap_id(note_activity.data["actor"])
 
       assert json_response(response, 200) ==
                ActivityView.render("activity.json", %{
@@ -992,8 +992,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         |> with_credentials(current_user.nickname, "test")
         |> post(request_path)
 
-      activity = Repo.get(Activity, note_activity.id)
-      activity_user = Repo.get_by(User, ap_id: note_activity.data["actor"])
+      activity = Activity.get_by_id(note_activity.id)
+      activity_user = User.get_by_ap_id(note_activity.data["actor"])
 
       assert json_response(response, 200) ==
                ActivityView.render("activity.json", %{
@@ -1021,7 +1021,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
 
       user = json_response(conn, 200)
 
-      fetched_user = Repo.get_by(User, nickname: "lain")
+      fetched_user = User.get_by_nickname("lain")
       assert user == UserView.render("show.json", %{user: fetched_user})
     end
 
@@ -1109,7 +1109,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
     test "it confirms the user account", %{conn: conn, user: user} do
       get(conn, "/api/account/confirm_email/#{user.id}/#{user.info.confirmation_token}")
 
-      user = Repo.get(User, user.id)
+      user = User.get_by_id(user.id)
 
       refute user.info.confirmation_pending
       refute user.info.confirmation_token
@@ -1727,7 +1727,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
         })
 
       assert json_response(conn, 200) == %{"status" => "success"}
-      fetched_user = Repo.get(User, current_user.id)
+      fetched_user = User.get_by_id(current_user.id)
       assert Pbkdf2.checkpw("newpass", fetched_user.password_hash) == true
     end
   end
@@ -1768,8 +1768,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
 
       {:ok, _activity} = ActivityPub.follow(other_user, user)
 
-      user = Repo.get(User, user.id)
-      other_user = Repo.get(User, other_user.id)
+      user = User.get_by_id(user.id)
+      other_user = User.get_by_id(other_user.id)
 
       assert User.following?(other_user, user) == false
 
@@ -1808,8 +1808,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
 
       {:ok, _activity} = ActivityPub.follow(other_user, user)
 
-      user = Repo.get(User, user.id)
-      other_user = Repo.get(User, other_user.id)
+      user = User.get_by_id(user.id)
+      other_user = User.get_by_id(other_user.id)
 
       assert User.following?(other_user, user) == false
 
@@ -1831,8 +1831,8 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
 
       {:ok, _activity} = ActivityPub.follow(other_user, user)
 
-      user = Repo.get(User, user.id)
-      other_user = Repo.get(User, other_user.id)
+      user = User.get_by_id(user.id)
+      other_user = User.get_by_id(other_user.id)
 
       assert User.following?(other_user, user) == false
 
index b823bfd68f6e00a4c0486aa20816d09df6776f39..6c00244deb70ff1a8ffa866c4a76c9ddee2e30a1 100644 (file)
@@ -275,7 +275,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
 
     {:ok, user} = TwitterAPI.register_user(data)
 
-    fetched_user = Repo.get_by(User, nickname: "lain")
+    fetched_user = User.get_by_nickname("lain")
 
     assert UserView.render("show.json", %{user: user}) ==
              UserView.render("show.json", %{user: fetched_user})
@@ -293,7 +293,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
 
     {:ok, user} = TwitterAPI.register_user(data)
 
-    fetched_user = Repo.get_by(User, nickname: "lain")
+    fetched_user = User.get_by_nickname("lain")
 
     assert UserView.render("show.json", %{user: user}) ==
              UserView.render("show.json", %{user: fetched_user})
@@ -369,7 +369,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
 
     {:ok, user} = TwitterAPI.register_user(data)
 
-    fetched_user = Repo.get_by(User, nickname: "vinny")
+    fetched_user = User.get_by_nickname("vinny")
     token = Repo.get_by(UserInviteToken, token: token.token)
 
     assert token.used == true
@@ -393,7 +393,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
     {:error, msg} = TwitterAPI.register_user(data)
 
     assert msg == "Invalid token"
-    refute Repo.get_by(User, nickname: "GrimReaper")
+    refute User.get_by_nickname("GrimReaper")
   end
 
   @moduletag skip: "needs 'registrations_open: false' in config"
@@ -414,7 +414,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
     {:error, msg} = TwitterAPI.register_user(data)
 
     assert msg == "Expired token"
-    refute Repo.get_by(User, nickname: "GrimReaper")
+    refute User.get_by_nickname("GrimReaper")
   end
 
   test "it returns the error on registration problems" do
@@ -429,7 +429,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
     {:error, error_object} = TwitterAPI.register_user(data)
 
     assert is_binary(error_object[:error])
-    refute Repo.get_by(User, nickname: "lain")
+    refute User.get_by_nickname("lain")
   end
 
   test "it assigns an integer conversation_id" do
index a1776b3e6ccc084cbec8c54404c82200fd2aa2c2..ee9a0c834ed6eef0f5105d488a289b1203edd3cb 100644 (file)
@@ -281,7 +281,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityViewTest do
 
     convo_id = Utils.context_to_conversation_id(activity.data["object"]["context"])
 
-    activity = Repo.get(Activity, activity.id)
+    activity = Activity.get_by_id(activity.id)
 
     result = ActivityView.render("activity.json", activity: announce)
 
index 4e7f94795375cfd0ef79277d7002db52ca046c94..0feaf4b64837ab032214cf33c08fbf383c72f1d6 100644 (file)
@@ -292,7 +292,7 @@ defmodule Pleroma.Web.TwitterAPI.UserViewTest do
       }
     }
 
-    blocker = Repo.get(User, blocker.id)
+    blocker = User.get_by_id(blocker.id)
     assert represented == UserView.render("show.json", %{user: user, for: blocker})
   end