feat(fediverse): implement activitypub protocols + update user interface
- add "ActivityPub" library to handle server to server federation and basic client to server protocols using activitypub: - add webfinger endpoint to look for actor - add actor definition with inbox / outbox / followers - remote follow an actor - create notes with possible preview cards - interract with favourites, reblogs and replies - block incoming actors and/or domains - broadcast/schedule activities to fediverse followers using a cron task - For castopod, the podcast is the actor: - overwrite the activitypub library for castopod's specific needs - perform basic interactions administrating a podcast to interact with fediverse users: - create notes with episode attachment - favourite and share a note + reply - add specific castopod_namespaces for podcasts and episodes definitions - overwrite CodeIgniter's Route service to include alternate-content option for activitystream requests - update episode publication logic: - remove publication inputs in create / edit episode form - publish / schedule or unpublish an episode after creation - the podcaster publishes a note when publishing an episode - Javascript / Typescript modules: - fix Dropdown.ts to keep dropdown menu in foreground - add Modal.ts for funding links modal - add Toggler.ts to toggle various css states in ui - User Interface: - update tailwindcss to v2 - use castopod's pine and rose colors - update public layout to a 3 column layout - add pages in public for podcast activity, episode list and notes - update episode page to include linked notes - remove previous and next episodes from episode pages - show different public views depending on whether user is authenticated or not - use Kumbh Sans and Montserrat fonts - update CodeIgniter's config files - with CodeIgniter's new requirements, update docker environments are now based on php v7.3 image - move Image entity to Libraries - update composer and npm packages to latest versions closes #69 #65 #85, fixes #51 #91 #92 #88
This commit is contained in:
parent
dd3ac9b4ab
commit
2f525c0f6e
|
@ -1,8 +1,8 @@
|
||||||
FROM php:7.2-fpm
|
FROM php:7.3-fpm
|
||||||
|
|
||||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
|
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y nodejs
|
apt-get install -y nodejs
|
||||||
|
|
|
@ -138,7 +138,6 @@ node_modules
|
||||||
# public folder
|
# public folder
|
||||||
public/*
|
public/*
|
||||||
!public/media
|
!public/media
|
||||||
!public/media/~person
|
|
||||||
!public/.htaccess
|
!public/.htaccess
|
||||||
!public/favicon.ico
|
!public/favicon.ico
|
||||||
!public/index.php
|
!public/index.php
|
||||||
|
@ -147,10 +146,14 @@ public/*
|
||||||
# public media folder
|
# public media folder
|
||||||
public/media/*
|
public/media/*
|
||||||
!public/media/index.html
|
!public/media/index.html
|
||||||
|
!public/media/podcasts
|
||||||
|
!public/media/persons
|
||||||
|
|
||||||
# public person folder
|
public/media/podcasts/*
|
||||||
public/media/~person/*
|
!public/media/podcasts/index.html
|
||||||
!public/media/~person/index.html
|
|
||||||
|
public/media/persons/*
|
||||||
|
!public/media/persons/index.html
|
||||||
|
|
||||||
# Generated files
|
# Generated files
|
||||||
app/Language/en/PersonsTaxonomy.php
|
app/Language/en/PersonsTaxonomy.php
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{
|
{
|
||||||
"files": "*.php",
|
"files": "*.php",
|
||||||
"options": {
|
"options": {
|
||||||
"phpVersion": "7.2",
|
"phpVersion": "7.3",
|
||||||
"singleQuote": true
|
"singleQuote": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
+ writable/***
|
+ writable/***
|
||||||
+ .env.example
|
+ .env.example
|
||||||
+ DEPENDENCIES.md
|
+ DEPENDENCIES.md
|
||||||
+ LICENSE
|
+ LICENSE.md
|
||||||
+ README.md
|
+ README.md
|
||||||
+ INSTALL.md
|
+ INSTALL.md
|
||||||
- **
|
- **
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
"apply",
|
"apply",
|
||||||
"responsive",
|
"responsive",
|
||||||
"variants",
|
"variants",
|
||||||
"screen"
|
"screen",
|
||||||
|
"layer"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
"removeXMLNS",
|
||||||
|
"removeDimensions",
|
||||||
|
"sortAttrs",
|
||||||
|
{
|
||||||
|
name: "addAttributesToSVGElement",
|
||||||
|
params: {
|
||||||
|
attributes: [
|
||||||
|
{ fill: "currentColor" },
|
||||||
|
{ width: "1em" },
|
||||||
|
{ height: "1em" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
|
@ -1,9 +0,0 @@
|
||||||
plugins:
|
|
||||||
- removeXMLNS: true
|
|
||||||
- removeDimensions: true
|
|
||||||
- addAttributesToSVGElement:
|
|
||||||
attributes:
|
|
||||||
- fill: currentColor
|
|
||||||
- width: "1em"
|
|
||||||
- height: "1em"
|
|
||||||
- sortAttrs: true
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
name: "removeViewBox",
|
||||||
|
active: false,
|
||||||
|
},
|
||||||
|
"removeXMLNS",
|
||||||
|
"removeDimensions",
|
||||||
|
"sortAttrs",
|
||||||
|
"prefixIds",
|
||||||
|
],
|
||||||
|
};
|
|
@ -1,5 +0,0 @@
|
||||||
plugins:
|
|
||||||
- removeXMLNS: true
|
|
||||||
- removeDimensions: true
|
|
||||||
- sortAttrs: true
|
|
||||||
- prefixIds: true
|
|
|
@ -4,7 +4,7 @@ Castopod uses the following components:
|
||||||
|
|
||||||
PHP Dependencies:
|
PHP Dependencies:
|
||||||
|
|
||||||
- [Code Igniter 4](https://codeigniter.com)
|
- [CodeIgniter 4](https://codeigniter.com)
|
||||||
([MIT License](https://codeigniter.com/user_guide/license.html))
|
([MIT License](https://codeigniter.com/user_guide/license.html))
|
||||||
- [WhichBrowser/Parser-PHP](https://github.com/WhichBrowser/Parser-PHP)
|
- [WhichBrowser/Parser-PHP](https://github.com/WhichBrowser/Parser-PHP)
|
||||||
([MIT License](https://github.com/WhichBrowser/Parser-PHP/blob/master/LICENSE))
|
([MIT License](https://github.com/WhichBrowser/Parser-PHP/blob/master/LICENSE))
|
||||||
|
@ -24,6 +24,14 @@ PHP Dependencies:
|
||||||
([MIT License](https://github.com/podlibre/user-agents-php/blob/main/LICENSE))
|
([MIT License](https://github.com/podlibre/user-agents-php/blob/main/LICENSE))
|
||||||
- [podlibre/ipcat](https://github.com/podlibre/ipcat)
|
- [podlibre/ipcat](https://github.com/podlibre/ipcat)
|
||||||
([GNU General Public License v3.0](https://github.com/podlibre/ipcat/blob/master/LICENSE))
|
([GNU General Public License v3.0](https://github.com/podlibre/ipcat/blob/master/LICENSE))
|
||||||
|
- [podlibre/podcast-namespace](https://code.podlibre.org/podlibre/podcastnamespace)
|
||||||
|
([MIT License](https://code.podlibre.org/podlibre/podcastnamespace/-/blob/master/LICENSE))
|
||||||
|
- [phpseclib](https://phpseclib.com/)
|
||||||
|
([MIT License](https://github.com/phpseclib/phpseclib/blob/master/LICENSE))
|
||||||
|
- [codeigniter4-uuid](https://github.com/michalsn/codeigniter4-uuid)
|
||||||
|
([MIT License](https://github.com/michalsn/codeigniter4-uuid/blob/develop/LICENSE))
|
||||||
|
- [essence](https://github.com/essence/essence)
|
||||||
|
([The FreeBSD License](https://github.com/essence/essence/blob/master/LICENSE.txt))
|
||||||
|
|
||||||
Javascript dependencies:
|
Javascript dependencies:
|
||||||
|
|
||||||
|
@ -39,9 +47,15 @@ Javascript dependencies:
|
||||||
([MIT License](https://github.com/jshjohnson/Choices/blob/master/LICENSE))
|
([MIT License](https://github.com/jshjohnson/Choices/blob/master/LICENSE))
|
||||||
- [flatpickr](https://flatpickr.js.org/)
|
- [flatpickr](https://flatpickr.js.org/)
|
||||||
([MIT License](https://github.com/flatpickr/flatpickr/blob/master/LICENSE.md))
|
([MIT License](https://github.com/flatpickr/flatpickr/blob/master/LICENSE.md))
|
||||||
|
- [popperjs](https://popper.js.org/)
|
||||||
|
([MIT License](https://github.com/popperjs/popper-core/blob/master/LICENSE.md))
|
||||||
|
|
||||||
Other:
|
Other:
|
||||||
|
|
||||||
|
- [Kumbh Sans](https://fonts.google.com/specimen/Kumbh+Sans)
|
||||||
|
([Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL))
|
||||||
|
- [Montserrat](https://fonts.google.com/specimen/Montserrat)
|
||||||
|
([Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL))
|
||||||
- [RemixIcon](https://remixicon.com/)
|
- [RemixIcon](https://remixicon.com/)
|
||||||
([Apache License 2.0](https://github.com/Remix-Design/RemixIcon/blob/master/License))
|
([Apache License 2.0](https://github.com/Remix-Design/RemixIcon/blob/master/License))
|
||||||
- [OPAWG/User agent list](https://github.com/opawg/user-agents)
|
- [OPAWG/User agent list](https://github.com/opawg/user-agents)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM php:7.2-fpm
|
FROM php:7.3-fpm
|
||||||
|
|
||||||
COPY . /castopod
|
COPY . /castopod
|
||||||
WORKDIR /castopod
|
WORKDIR /castopod
|
||||||
|
@ -25,3 +25,9 @@ RUN echo "file_uploads = On\n" \
|
||||||
"post_max_size = 120M\n" \
|
"post_max_size = 120M\n" \
|
||||||
"max_execution_time = 300\n" \
|
"max_execution_time = 300\n" \
|
||||||
> /usr/local/etc/php/conf.d/uploads.ini
|
> /usr/local/etc/php/conf.d/uploads.ini
|
||||||
|
|
||||||
|
# install cron
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y cron
|
||||||
|
|
||||||
|
RUN crontab /castopod/crontab
|
||||||
|
|
25
INSTALL.md
25
INSTALL.md
|
@ -1,13 +1,16 @@
|
||||||
# How to install Castopod
|
# How to install Castopod <!-- omit in toc -->
|
||||||
|
|
||||||
Castopod was thought to be easy to install. Whether using dedicated or shared
|
Castopod was thought to be easy to install. Whether using dedicated or shared
|
||||||
hosting, you can install it on most PHP-MySQL compatible web servers.
|
hosting, you can install it on most PHP-MySQL compatible web servers.
|
||||||
|
|
||||||
|
## Table of contents <!-- omit in toc -->
|
||||||
|
|
||||||
- [Install instructions](#install-instructions)
|
- [Install instructions](#install-instructions)
|
||||||
- [(optional) Manual configuration](#optional-manual-configuration)
|
- [(optional) Manual configuration](#optional-manual-configuration)
|
||||||
- [Web Server Requirements](#web-server-requirements)
|
- [Web Server Requirements](#web-server-requirements)
|
||||||
- [PHP v7.2 or higher](#php-v72-or-higher)
|
- [PHP v7.3 or higher](#php-v73-or-higher)
|
||||||
- [MySQL compatible database](#mysql-compatible-database)
|
- [MySQL compatible database](#mysql-compatible-database)
|
||||||
|
- [Privileges](#privileges)
|
||||||
- [(Optional) Other recommendations](#optional-other-recommendations)
|
- [(Optional) Other recommendations](#optional-other-recommendations)
|
||||||
- [Security concerns](#security-concerns)
|
- [Security concerns](#security-concerns)
|
||||||
|
|
||||||
|
@ -19,9 +22,16 @@ hosting, you can install it on most PHP-MySQL compatible web servers.
|
||||||
1. Download and unzip the Castopod package onto the web server if you haven’t
|
1. Download and unzip the Castopod package onto the web server if you haven’t
|
||||||
already.
|
already.
|
||||||
- ⚠️ Set the web server document root to the `public/` sub-folder.
|
- ⚠️ Set the web server document root to the `public/` sub-folder.
|
||||||
2. Run the Castopod install script by going to the install wizard page
|
2. ⚠️ For broadcasting social activities to the fediverse, add a cron task on
|
||||||
|
your web server to run every minute (replace the paths accordingly):
|
||||||
|
|
||||||
|
```php
|
||||||
|
* * * * * /path/to/php /path/to/castopod/public/index.php scheduled-activities
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run the Castopod install script by going to the install wizard page
|
||||||
(`https://your_domain_name.com/cp-install`) in your favorite web browser.
|
(`https://your_domain_name.com/cp-install`) in your favorite web browser.
|
||||||
3. Follow the instructions on your screen.
|
4. Follow the instructions on your screen.
|
||||||
|
|
||||||
All done, start podcasting!
|
All done, start podcasting!
|
||||||
|
|
||||||
|
@ -36,13 +46,12 @@ Before uploading Castopod files to your web server:
|
||||||
|
|
||||||
## Web Server Requirements
|
## Web Server Requirements
|
||||||
|
|
||||||
### PHP v7.2 or higher
|
### PHP v7.3 or higher
|
||||||
|
|
||||||
PHP version 7.2 or higher is required, with the following extensions installed:
|
PHP version 7.3 or higher is required, with the following extensions installed:
|
||||||
|
|
||||||
- [intl](http://php.net/manual/en/intl.requirements.php)
|
- [intl](http://php.net/manual/en/intl.requirements.php)
|
||||||
- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use
|
- [libcurl](http://php.net/manual/en/curl.requirements.php)
|
||||||
the HTTP\CURLRequest library
|
|
||||||
- [mbstring](http://php.net/manual/en/mbstring.installation.php)
|
- [mbstring](http://php.net/manual/en/mbstring.installation.php)
|
||||||
|
|
||||||
Additionally, make sure that the following extensions are enabled in your PHP:
|
Additionally, make sure that the following extensions are enabled in your PHP:
|
||||||
|
|
661
LICENSE
661
LICENSE
|
@ -1,661 +0,0 @@
|
||||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 19 November 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU Affero General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works, specifically designed to ensure
|
|
||||||
cooperation with the community in the case of network server software.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
|
||||||
to take away your freedom to share and change the works. By contrast,
|
|
||||||
our General Public Licenses are intended to guarantee your freedom to
|
|
||||||
share and change all versions of a program--to make sure it remains free
|
|
||||||
software for all its users.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
them if you wish), that you receive source code or can get it if you
|
|
||||||
want it, that you can change the software or use pieces of it in new
|
|
||||||
free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
Developers that use our General Public Licenses protect your rights
|
|
||||||
with two steps: (1) assert copyright on the software, and (2) offer
|
|
||||||
you this License which gives you legal permission to copy, distribute
|
|
||||||
and/or modify the software.
|
|
||||||
|
|
||||||
A secondary benefit of defending all users' freedom is that
|
|
||||||
improvements made in alternate versions of the program, if they
|
|
||||||
receive widespread use, become available for other developers to
|
|
||||||
incorporate. Many developers of free software are heartened and
|
|
||||||
encouraged by the resulting cooperation. However, in the case of
|
|
||||||
software used on network servers, this result may fail to come about.
|
|
||||||
The GNU General Public License permits making a modified version and
|
|
||||||
letting the public access it on a server without ever releasing its
|
|
||||||
source code to the public.
|
|
||||||
|
|
||||||
The GNU Affero General Public License is designed specifically to
|
|
||||||
ensure that, in such cases, the modified source code becomes available
|
|
||||||
to the community. It requires the operator of a network server to
|
|
||||||
provide the source code of the modified version running there to the
|
|
||||||
users of that server. Therefore, public use of a modified version, on
|
|
||||||
a publicly accessible server, gives the public access to the source
|
|
||||||
code of the modified version.
|
|
||||||
|
|
||||||
An older license, called the Affero General Public License and
|
|
||||||
published by Affero, was designed to accomplish similar goals. This is
|
|
||||||
a different license, not a version of the Affero GPL, but Affero has
|
|
||||||
released a new version of the Affero GPL which permits relicensing under
|
|
||||||
this license.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
|
||||||
works, such as semiconductor masks.
|
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this
|
|
||||||
License. Each licensee is addressed as "you". "Licensees" and
|
|
||||||
"recipients" may be individuals or organizations.
|
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work
|
|
||||||
in a fashion requiring copyright permission, other than the making of an
|
|
||||||
exact copy. The resulting work is called a "modified version" of the
|
|
||||||
earlier work or a work "based on" the earlier work.
|
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based
|
|
||||||
on the Program.
|
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without
|
|
||||||
permission, would make you directly or secondarily liable for
|
|
||||||
infringement under applicable copyright law, except executing it on a
|
|
||||||
computer or modifying a private copy. Propagation includes copying,
|
|
||||||
distribution (with or without modification), making available to the
|
|
||||||
public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other
|
|
||||||
parties to make or receive copies. Mere interaction with a user through
|
|
||||||
a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
|
||||||
to the extent that it includes a convenient and prominently visible
|
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
|
||||||
tells the user that there is no warranty for the work (except to the
|
|
||||||
extent that warranties are provided), that licensees may convey the
|
|
||||||
work under this License, and how to view a copy of this License. If
|
|
||||||
the interface presents a list of user commands or options, such as a
|
|
||||||
menu, a prominent item in the list meets this criterion.
|
|
||||||
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work
|
|
||||||
for making modifications to it. "Object code" means any non-source
|
|
||||||
form of a work.
|
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official
|
|
||||||
standard defined by a recognized standards body, or, in the case of
|
|
||||||
interfaces specified for a particular programming language, one that
|
|
||||||
is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other
|
|
||||||
than the work as a whole, that (a) is included in the normal form of
|
|
||||||
packaging a Major Component, but which is not part of that Major
|
|
||||||
Component, and (b) serves only to enable use of the work with that
|
|
||||||
Major Component, or to implement a Standard Interface for which an
|
|
||||||
implementation is available to the public in source code form. A
|
|
||||||
"Major Component", in this context, means a major essential component
|
|
||||||
(kernel, window system, and so on) of the specific operating system
|
|
||||||
(if any) on which the executable work runs, or a compiler used to
|
|
||||||
produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all
|
|
||||||
the source code needed to generate, install, and (for an executable
|
|
||||||
work) run the object code and to modify the work, including scripts to
|
|
||||||
control those activities. However, it does not include the work's
|
|
||||||
System Libraries, or general-purpose tools or generally available free
|
|
||||||
programs which are used unmodified in performing those activities but
|
|
||||||
which are not part of the work. For example, Corresponding Source
|
|
||||||
includes interface definition files associated with source files for
|
|
||||||
the work, and the source code for shared libraries and dynamically
|
|
||||||
linked subprograms that the work is specifically designed to require,
|
|
||||||
such as by intimate data communication or control flow between those
|
|
||||||
subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users
|
|
||||||
can regenerate automatically from other parts of the Corresponding
|
|
||||||
Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that
|
|
||||||
same work.
|
|
||||||
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of
|
|
||||||
copyright on the Program, and are irrevocable provided the stated
|
|
||||||
conditions are met. This License explicitly affirms your unlimited
|
|
||||||
permission to run the unmodified Program. The output from running a
|
|
||||||
covered work is covered by this License only if the output, given its
|
|
||||||
content, constitutes a covered work. This License acknowledges your
|
|
||||||
rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not
|
|
||||||
convey, without conditions so long as your license otherwise remains
|
|
||||||
in force. You may convey covered works to others for the sole purpose
|
|
||||||
of having them make modifications exclusively for you, or provide you
|
|
||||||
with facilities for running those works, provided that you comply with
|
|
||||||
the terms of this License in conveying all material for which you do
|
|
||||||
not control copyright. Those thus making or running the covered works
|
|
||||||
for you must do so exclusively on your behalf, under your direction
|
|
||||||
and control, on terms that prohibit them from making any copies of
|
|
||||||
your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under
|
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10
|
|
||||||
makes it unnecessary.
|
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological
|
|
||||||
measure under any applicable law fulfilling obligations under article
|
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
|
||||||
similar laws prohibiting or restricting circumvention of such
|
|
||||||
measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid
|
|
||||||
circumvention of technological measures to the extent such circumvention
|
|
||||||
is effected by exercising rights under this License with respect to
|
|
||||||
the covered work, and you disclaim any intention to limit operation or
|
|
||||||
modification of the work as a means of enforcing, against the work's
|
|
||||||
users, your or third parties' legal rights to forbid circumvention of
|
|
||||||
technological measures.
|
|
||||||
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you
|
|
||||||
receive it, in any medium, provided that you conspicuously and
|
|
||||||
appropriately publish on each copy an appropriate copyright notice;
|
|
||||||
keep intact all notices stating that this License and any
|
|
||||||
non-permissive terms added in accord with section 7 apply to the code;
|
|
||||||
keep intact all notices of the absence of any warranty; and give all
|
|
||||||
recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey,
|
|
||||||
and you may offer support or warranty protection for a fee.
|
|
||||||
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to
|
|
||||||
produce it from the Program, in the form of source code under the
|
|
||||||
terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified
|
|
||||||
it, and giving a relevant date.
|
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is
|
|
||||||
released under this License and any conditions added under section
|
|
||||||
7. This requirement modifies the requirement in section 4 to
|
|
||||||
"keep intact all notices".
|
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this
|
|
||||||
License to anyone who comes into possession of a copy. This
|
|
||||||
License will therefore apply, along with any applicable section 7
|
|
||||||
additional terms, to the whole of the work, and all its parts,
|
|
||||||
regardless of how they are packaged. This License gives no
|
|
||||||
permission to license the work in any other way, but it does not
|
|
||||||
invalidate such permission if you have separately received it.
|
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display
|
|
||||||
Appropriate Legal Notices; however, if the Program has interactive
|
|
||||||
interfaces that do not display Appropriate Legal Notices, your
|
|
||||||
work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent
|
|
||||||
works, which are not by their nature extensions of the covered work,
|
|
||||||
and which are not combined with it such as to form a larger program,
|
|
||||||
in or on a volume of a storage or distribution medium, is called an
|
|
||||||
"aggregate" if the compilation and its resulting copyright are not
|
|
||||||
used to limit the access or legal rights of the compilation's users
|
|
||||||
beyond what the individual works permit. Inclusion of a covered work
|
|
||||||
in an aggregate does not cause this License to apply to the other
|
|
||||||
parts of the aggregate.
|
|
||||||
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms
|
|
||||||
of sections 4 and 5, provided that you also convey the
|
|
||||||
machine-readable Corresponding Source under the terms of this License,
|
|
||||||
in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by the
|
|
||||||
Corresponding Source fixed on a durable physical medium
|
|
||||||
customarily used for software interchange.
|
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by a
|
|
||||||
written offer, valid for at least three years and valid for as
|
|
||||||
long as you offer spare parts or customer support for that product
|
|
||||||
model, to give anyone who possesses the object code either (1) a
|
|
||||||
copy of the Corresponding Source for all the software in the
|
|
||||||
product that is covered by this License, on a durable physical
|
|
||||||
medium customarily used for software interchange, for a price no
|
|
||||||
more than your reasonable cost of physically performing this
|
|
||||||
conveying of source, or (2) access to copy the
|
|
||||||
Corresponding Source from a network server at no charge.
|
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the
|
|
||||||
written offer to provide the Corresponding Source. This
|
|
||||||
alternative is allowed only occasionally and noncommercially, and
|
|
||||||
only if you received the object code with such an offer, in accord
|
|
||||||
with subsection 6b.
|
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated
|
|
||||||
place (gratis or for a charge), and offer equivalent access to the
|
|
||||||
Corresponding Source in the same way through the same place at no
|
|
||||||
further charge. You need not require recipients to copy the
|
|
||||||
Corresponding Source along with the object code. If the place to
|
|
||||||
copy the object code is a network server, the Corresponding Source
|
|
||||||
may be on a different server (operated by you or a third party)
|
|
||||||
that supports equivalent copying facilities, provided you maintain
|
|
||||||
clear directions next to the object code saying where to find the
|
|
||||||
Corresponding Source. Regardless of what server hosts the
|
|
||||||
Corresponding Source, you remain obligated to ensure that it is
|
|
||||||
available for as long as needed to satisfy these requirements.
|
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided
|
|
||||||
you inform other peers where the object code and Corresponding
|
|
||||||
Source of the work are being offered to the general public at no
|
|
||||||
charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded
|
|
||||||
from the Corresponding Source as a System Library, need not be
|
|
||||||
included in conveying the object code work.
|
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any
|
|
||||||
tangible personal property which is normally used for personal, family,
|
|
||||||
or household purposes, or (2) anything designed or sold for incorporation
|
|
||||||
into a dwelling. In determining whether a product is a consumer product,
|
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
|
||||||
product received by a particular user, "normally used" refers to a
|
|
||||||
typical or common use of that class of product, regardless of the status
|
|
||||||
of the particular user or of the way in which the particular user
|
|
||||||
actually uses, or expects or is expected to use, the product. A product
|
|
||||||
is a consumer product regardless of whether the product has substantial
|
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent
|
|
||||||
the only significant mode of use of the product.
|
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods,
|
|
||||||
procedures, authorization keys, or other information required to install
|
|
||||||
and execute modified versions of a covered work in that User Product from
|
|
||||||
a modified version of its Corresponding Source. The information must
|
|
||||||
suffice to ensure that the continued functioning of the modified object
|
|
||||||
code is in no case prevented or interfered with solely because
|
|
||||||
modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or
|
|
||||||
specifically for use in, a User Product, and the conveying occurs as
|
|
||||||
part of a transaction in which the right of possession and use of the
|
|
||||||
User Product is transferred to the recipient in perpetuity or for a
|
|
||||||
fixed term (regardless of how the transaction is characterized), the
|
|
||||||
Corresponding Source conveyed under this section must be accompanied
|
|
||||||
by the Installation Information. But this requirement does not apply
|
|
||||||
if neither you nor any third party retains the ability to install
|
|
||||||
modified object code on the User Product (for example, the work has
|
|
||||||
been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a
|
|
||||||
requirement to continue to provide support service, warranty, or updates
|
|
||||||
for a work that has been modified or installed by the recipient, or for
|
|
||||||
the User Product in which it has been modified or installed. Access to a
|
|
||||||
network may be denied when the modification itself materially and
|
|
||||||
adversely affects the operation of the network or violates the rules and
|
|
||||||
protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided,
|
|
||||||
in accord with this section must be in a format that is publicly
|
|
||||||
documented (and with an implementation available to the public in
|
|
||||||
source code form), and must require no special password or key for
|
|
||||||
unpacking, reading or copying.
|
|
||||||
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this
|
|
||||||
License by making exceptions from one or more of its conditions.
|
|
||||||
Additional permissions that are applicable to the entire Program shall
|
|
||||||
be treated as though they were included in this License, to the extent
|
|
||||||
that they are valid under applicable law. If additional permissions
|
|
||||||
apply only to part of the Program, that part may be used separately
|
|
||||||
under those permissions, but the entire Program remains governed by
|
|
||||||
this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option
|
|
||||||
remove any additional permissions from that copy, or from any part of
|
|
||||||
it. (Additional permissions may be written to require their own
|
|
||||||
removal in certain cases when you modify the work.) You may place
|
|
||||||
additional permissions on material, added by you to a covered work,
|
|
||||||
for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you
|
|
||||||
add to a covered work, you may (if authorized by the copyright holders of
|
|
||||||
that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the
|
|
||||||
terms of sections 15 and 16 of this License; or
|
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or
|
|
||||||
author attributions in that material or in the Appropriate Legal
|
|
||||||
Notices displayed by works containing it; or
|
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or
|
|
||||||
requiring that modified versions of such material be marked in
|
|
||||||
reasonable ways as different from the original version; or
|
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or
|
|
||||||
authors of the material; or
|
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some
|
|
||||||
trade names, trademarks, or service marks; or
|
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that
|
|
||||||
material by anyone who conveys the material (or modified versions of
|
|
||||||
it) with contractual assumptions of liability to the recipient, for
|
|
||||||
any liability that these contractual assumptions directly impose on
|
|
||||||
those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further
|
|
||||||
restrictions" within the meaning of section 10. If the Program as you
|
|
||||||
received it, or any part of it, contains a notice stating that it is
|
|
||||||
governed by this License along with a term that is a further
|
|
||||||
restriction, you may remove that term. If a license document contains
|
|
||||||
a further restriction but permits relicensing or conveying under this
|
|
||||||
License, you may add to a covered work material governed by the terms
|
|
||||||
of that license document, provided that the further restriction does
|
|
||||||
not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you
|
|
||||||
must place, in the relevant source files, a statement of the
|
|
||||||
additional terms that apply to those files, or a notice indicating
|
|
||||||
where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the
|
|
||||||
form of a separately written license, or stated as exceptions;
|
|
||||||
the above requirements apply either way.
|
|
||||||
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly
|
|
||||||
provided under this License. Any attempt otherwise to propagate or
|
|
||||||
modify it is void, and will automatically terminate your rights under
|
|
||||||
this License (including any patent licenses granted under the third
|
|
||||||
paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your
|
|
||||||
license from a particular copyright holder is reinstated (a)
|
|
||||||
provisionally, unless and until the copyright holder explicitly and
|
|
||||||
finally terminates your license, and (b) permanently, if the copyright
|
|
||||||
holder fails to notify you of the violation by some reasonable means
|
|
||||||
prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is
|
|
||||||
reinstated permanently if the copyright holder notifies you of the
|
|
||||||
violation by some reasonable means, this is the first time you have
|
|
||||||
received notice of violation of this License (for any work) from that
|
|
||||||
copyright holder, and you cure the violation prior to 30 days after
|
|
||||||
your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the
|
|
||||||
licenses of parties who have received copies or rights from you under
|
|
||||||
this License. If your rights have been terminated and not permanently
|
|
||||||
reinstated, you do not qualify to receive new licenses for the same
|
|
||||||
material under section 10.
|
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or
|
|
||||||
run a copy of the Program. Ancillary propagation of a covered work
|
|
||||||
occurring solely as a consequence of using peer-to-peer transmission
|
|
||||||
to receive a copy likewise does not require acceptance. However,
|
|
||||||
nothing other than this License grants you permission to propagate or
|
|
||||||
modify any covered work. These actions infringe copyright if you do
|
|
||||||
not accept this License. Therefore, by modifying or propagating a
|
|
||||||
covered work, you indicate your acceptance of this License to do so.
|
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically
|
|
||||||
receives a license from the original licensors, to run, modify and
|
|
||||||
propagate that work, subject to this License. You are not responsible
|
|
||||||
for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an
|
|
||||||
organization, or substantially all assets of one, or subdividing an
|
|
||||||
organization, or merging organizations. If propagation of a covered
|
|
||||||
work results from an entity transaction, each party to that
|
|
||||||
transaction who receives a copy of the work also receives whatever
|
|
||||||
licenses to the work the party's predecessor in interest had or could
|
|
||||||
give under the previous paragraph, plus a right to possession of the
|
|
||||||
Corresponding Source of the work from the predecessor in interest, if
|
|
||||||
the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the
|
|
||||||
rights granted or affirmed under this License. For example, you may
|
|
||||||
not impose a license fee, royalty, or other charge for exercise of
|
|
||||||
rights granted under this License, and you may not initiate litigation
|
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
|
||||||
any patent claim is infringed by making, using, selling, offering for
|
|
||||||
sale, or importing the Program or any portion of it.
|
|
||||||
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this
|
|
||||||
License of the Program or a work on which the Program is based. The
|
|
||||||
work thus licensed is called the contributor's "contributor version".
|
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims
|
|
||||||
owned or controlled by the contributor, whether already acquired or
|
|
||||||
hereafter acquired, that would be infringed by some manner, permitted
|
|
||||||
by this License, of making, using, or selling its contributor version,
|
|
||||||
but do not include claims that would be infringed only as a
|
|
||||||
consequence of further modification of the contributor version. For
|
|
||||||
purposes of this definition, "control" includes the right to grant
|
|
||||||
patent sublicenses in a manner consistent with the requirements of
|
|
||||||
this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
|
||||||
patent license under the contributor's essential patent claims, to
|
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
|
||||||
propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express
|
|
||||||
agreement or commitment, however denominated, not to enforce a patent
|
|
||||||
(such as an express permission to practice a patent or covenant not to
|
|
||||||
sue for patent infringement). To "grant" such a patent license to a
|
|
||||||
party means to make such an agreement or commitment not to enforce a
|
|
||||||
patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license,
|
|
||||||
and the Corresponding Source of the work is not available for anyone
|
|
||||||
to copy, free of charge and under the terms of this License, through a
|
|
||||||
publicly available network server or other readily accessible means,
|
|
||||||
then you must either (1) cause the Corresponding Source to be so
|
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the
|
|
||||||
patent license for this particular work, or (3) arrange, in a manner
|
|
||||||
consistent with the requirements of this License, to extend the patent
|
|
||||||
license to downstream recipients. "Knowingly relying" means you have
|
|
||||||
actual knowledge that, but for the patent license, your conveying the
|
|
||||||
covered work in a country, or your recipient's use of the covered work
|
|
||||||
in a country, would infringe one or more identifiable patents in that
|
|
||||||
country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or
|
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
|
||||||
covered work, and grant a patent license to some of the parties
|
|
||||||
receiving the covered work authorizing them to use, propagate, modify
|
|
||||||
or convey a specific copy of the covered work, then the patent license
|
|
||||||
you grant is automatically extended to all recipients of the covered
|
|
||||||
work and works based on it.
|
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within
|
|
||||||
the scope of its coverage, prohibits the exercise of, or is
|
|
||||||
conditioned on the non-exercise of one or more of the rights that are
|
|
||||||
specifically granted under this License. You may not convey a covered
|
|
||||||
work if you are a party to an arrangement with a third party that is
|
|
||||||
in the business of distributing software, under which you make payment
|
|
||||||
to the third party based on the extent of your activity of conveying
|
|
||||||
the work, and under which the third party grants, to any of the
|
|
||||||
parties who would receive the covered work from you, a discriminatory
|
|
||||||
patent license (a) in connection with copies of the covered work
|
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily
|
|
||||||
for and in connection with specific products or compilations that
|
|
||||||
contain the covered work, unless you entered into that arrangement,
|
|
||||||
or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting
|
|
||||||
any implied license or other defenses to infringement that may
|
|
||||||
otherwise be available to you under applicable patent law.
|
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot convey a
|
|
||||||
covered work so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you may
|
|
||||||
not convey it at all. For example, if you agree to terms that obligate you
|
|
||||||
to collect a royalty for further conveying from those to whom you convey
|
|
||||||
the Program, the only way you could satisfy both those terms and this
|
|
||||||
License would be to refrain entirely from conveying the Program.
|
|
||||||
|
|
||||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, if you modify the
|
|
||||||
Program, your modified version must prominently offer all users
|
|
||||||
interacting with it remotely through a computer network (if your version
|
|
||||||
supports such interaction) an opportunity to receive the Corresponding
|
|
||||||
Source of your version by providing access to the Corresponding Source
|
|
||||||
from a network server at no charge, through some standard or customary
|
|
||||||
means of facilitating copying of software. This Corresponding Source
|
|
||||||
shall include the Corresponding Source for any work covered by version 3
|
|
||||||
of the GNU General Public License that is incorporated pursuant to the
|
|
||||||
following paragraph.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
|
||||||
permission to link or combine any covered work with a work licensed
|
|
||||||
under version 3 of the GNU General Public License into a single
|
|
||||||
combined work, and to convey the resulting work. The terms of this
|
|
||||||
License will continue to apply to the part which is the covered work,
|
|
||||||
but the work with which it is combined will remain governed by version
|
|
||||||
3 of the GNU General Public License.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
|
||||||
the GNU Affero General Public License from time to time. Such new versions
|
|
||||||
will be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Program specifies that a certain numbered version of the GNU Affero General
|
|
||||||
Public License "or any later version" applies to it, you have the
|
|
||||||
option of following the terms and conditions either of that numbered
|
|
||||||
version or of any later version published by the Free Software
|
|
||||||
Foundation. If the Program does not specify a version number of the
|
|
||||||
GNU Affero General Public License, you may choose any version ever published
|
|
||||||
by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
|
||||||
versions of the GNU Affero General Public License can be used, that proxy's
|
|
||||||
public statement of acceptance of a version permanently authorizes you
|
|
||||||
to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different
|
|
||||||
permissions. However, no additional obligations are imposed on any
|
|
||||||
author or copyright holder as a result of your choosing to follow a
|
|
||||||
later version.
|
|
||||||
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
|
||||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
|
||||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
|
||||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
|
||||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
|
||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
|
||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
|
||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
|
||||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
|
||||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
|
||||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
|
||||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGES.
|
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided
|
|
||||||
above cannot be given local legal effect according to their terms,
|
|
||||||
reviewing courts shall apply local law that most closely approximates
|
|
||||||
an absolute waiver of all civil liability in connection with the
|
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
|
||||||
copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
Castopod
|
|
||||||
Copyright (C) 2020 Podlibre
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published
|
|
||||||
by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If your software can interact with users remotely through a computer
|
|
||||||
network, you should also make sure that it provides a way for users to
|
|
||||||
get its source. For example, if your program is a web application, its
|
|
||||||
interface could display a "Source" link that leads users to an archive
|
|
||||||
of the code. There are many ways you could offer source, and different
|
|
||||||
solutions will be better for different programs; see section 13 for the
|
|
||||||
specific requirements.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
|
@ -0,0 +1,598 @@
|
||||||
|
# GNU Affero General Public License
|
||||||
|
|
||||||
|
_Version 3, 19 November 2007_ _Copyright © 2007 Free Software Foundation, Inc.
|
||||||
|
<<http://fsf.org/>>_
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this license
|
||||||
|
document, but changing it is not allowed.
|
||||||
|
|
||||||
|
## Preamble
|
||||||
|
|
||||||
|
The GNU Affero General Public License is a free, copyleft license for software
|
||||||
|
and other kinds of works, specifically designed to ensure cooperation with the
|
||||||
|
community in the case of network server software.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed to take
|
||||||
|
away your freedom to share and change the works. By contrast, our General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change all versions
|
||||||
|
of a program--to make sure it remains free software for all its users.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not price. Our
|
||||||
|
General Public Licenses are designed to make sure that you have the freedom to
|
||||||
|
distribute copies of free software (and charge for them if you wish), that you
|
||||||
|
receive source code or can get it if you want it, that you can change the
|
||||||
|
software or use pieces of it in new free programs, and that you know you can do
|
||||||
|
these things.
|
||||||
|
|
||||||
|
Developers that use our General Public Licenses protect your rights with two
|
||||||
|
steps: **(1)** assert copyright on the software, and **(2)** offer you this
|
||||||
|
License which gives you legal permission to copy, distribute and/or modify the
|
||||||
|
software.
|
||||||
|
|
||||||
|
A secondary benefit of defending all users' freedom is that improvements made in
|
||||||
|
alternate versions of the program, if they receive widespread use, become
|
||||||
|
available for other developers to incorporate. Many developers of free software
|
||||||
|
are heartened and encouraged by the resulting cooperation. However, in the case
|
||||||
|
of software used on network servers, this result may fail to come about. The GNU
|
||||||
|
General Public License permits making a modified version and letting the public
|
||||||
|
access it on a server without ever releasing its source code to the public.
|
||||||
|
|
||||||
|
The GNU Affero General Public License is designed specifically to ensure that,
|
||||||
|
in such cases, the modified source code becomes available to the community. It
|
||||||
|
requires the operator of a network server to provide the source code of the
|
||||||
|
modified version running there to the users of that server. Therefore, public
|
||||||
|
use of a modified version, on a publicly accessible server, gives the public
|
||||||
|
access to the source code of the modified version.
|
||||||
|
|
||||||
|
An older license, called the Affero General Public License and published by
|
||||||
|
Affero, was designed to accomplish similar goals. This is a different license,
|
||||||
|
not a version of the Affero GPL, but Affero has released a new version of the
|
||||||
|
Affero GPL which permits relicensing under this license.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and modification
|
||||||
|
follow.
|
||||||
|
|
||||||
|
## TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
### 0. Definitions
|
||||||
|
|
||||||
|
“This License” refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
|
“Copyright” also means copyright-like laws that apply to other kinds of works,
|
||||||
|
such as semiconductor masks.
|
||||||
|
|
||||||
|
“The Program” refers to any copyrightable work licensed under this License. Each
|
||||||
|
licensee is addressed as “you”. “Licensees” and “recipients” may be individuals
|
||||||
|
or organizations.
|
||||||
|
|
||||||
|
To “modify” a work means to copy from or adapt all or part of the work in a
|
||||||
|
fashion requiring copyright permission, other than the making of an exact copy.
|
||||||
|
The resulting work is called a “modified version” of the earlier work or a work
|
||||||
|
“based on” the earlier work.
|
||||||
|
|
||||||
|
A “covered work” means either the unmodified Program or a work based on the
|
||||||
|
Program.
|
||||||
|
|
||||||
|
To “propagate” a work means to do anything with it that, without permission,
|
||||||
|
would make you directly or secondarily liable for infringement under applicable
|
||||||
|
copyright law, except executing it on a computer or modifying a private copy.
|
||||||
|
Propagation includes copying, distribution (with or without modification),
|
||||||
|
making available to the public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To “convey” a work means any kind of propagation that enables other parties to
|
||||||
|
make or receive copies. Mere interaction with a user through a computer network,
|
||||||
|
with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays “Appropriate Legal Notices” to the extent
|
||||||
|
that it includes a convenient and prominently visible feature that **(1)**
|
||||||
|
displays an appropriate copyright notice, and **(2)** tells the user that there
|
||||||
|
is no warranty for the work (except to the extent that warranties are provided),
|
||||||
|
that licensees may convey the work under this License, and how to view a copy of
|
||||||
|
this License. If the interface presents a list of user commands or options, such
|
||||||
|
as a menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
### 1. Source Code
|
||||||
|
|
||||||
|
The “source code” for a work means the preferred form of the work for making
|
||||||
|
modifications to it. “Object code” means any non-source form of a work.
|
||||||
|
|
||||||
|
A “Standard Interface” means an interface that either is an official standard
|
||||||
|
defined by a recognized standards body, or, in the case of interfaces specified
|
||||||
|
for a particular programming language, one that is widely used among developers
|
||||||
|
working in that language.
|
||||||
|
|
||||||
|
The “System Libraries” of an executable work include anything, other than the
|
||||||
|
work as a whole, that **(a)** is included in the normal form of packaging a
|
||||||
|
Major Component, but which is not part of that Major Component, and **(b)**
|
||||||
|
serves only to enable use of the work with that Major Component, or to implement
|
||||||
|
a Standard Interface for which an implementation is available to the public in
|
||||||
|
source code form. A “Major Component”, in this context, means a major essential
|
||||||
|
component (kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to produce the
|
||||||
|
work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The “Corresponding Source” for a work in object code form means all the source
|
||||||
|
code needed to generate, install, and (for an executable work) run the object
|
||||||
|
code and to modify the work, including scripts to control those activities.
|
||||||
|
However, it does not include the work's System Libraries, or general-purpose
|
||||||
|
tools or generally available free programs which are used unmodified in
|
||||||
|
performing those activities but which are not part of the work. For example,
|
||||||
|
Corresponding Source includes interface definition files associated with source
|
||||||
|
files for the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require, such as by
|
||||||
|
intimate data communication or control flow between those subprograms and other
|
||||||
|
parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users can regenerate
|
||||||
|
automatically from other parts of the Corresponding Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that same work.
|
||||||
|
|
||||||
|
### 2. Basic Permissions
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of copyright on
|
||||||
|
the Program, and are irrevocable provided the stated conditions are met. This
|
||||||
|
License explicitly affirms your unlimited permission to run the unmodified
|
||||||
|
Program. The output from running a covered work is covered by this License only
|
||||||
|
if the output, given its content, constitutes a covered work. This License
|
||||||
|
acknowledges your rights of fair use or other equivalent, as provided by
|
||||||
|
copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not convey, without
|
||||||
|
conditions so long as your license otherwise remains in force. You may convey
|
||||||
|
covered works to others for the sole purpose of having them make modifications
|
||||||
|
exclusively for you, or provide you with facilities for running those works,
|
||||||
|
provided that you comply with the terms of this License in conveying all
|
||||||
|
material for which you do not control copyright. Those thus making or running
|
||||||
|
the covered works for you must do so exclusively on your behalf, under your
|
||||||
|
direction and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under the conditions
|
||||||
|
stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
|
||||||
|
|
||||||
|
### 3. Protecting Users' Legal Rights From Anti-Circumvention Law
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological measure under
|
||||||
|
any applicable law fulfilling obligations under article 11 of the WIPO copyright
|
||||||
|
treaty adopted on 20 December 1996, or similar laws prohibiting or restricting
|
||||||
|
circumvention of such measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention is
|
||||||
|
effected by exercising rights under this License with respect to the covered
|
||||||
|
work, and you disclaim any intention to limit operation or modification of the
|
||||||
|
work as a means of enforcing, against the work's users, your or third parties'
|
||||||
|
legal rights to forbid circumvention of technological measures.
|
||||||
|
|
||||||
|
### 4. Conveying Verbatim Copies
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you receive it,
|
||||||
|
in any medium, provided that you conspicuously and appropriately publish on each
|
||||||
|
copy an appropriate copyright notice; keep intact all notices stating that this
|
||||||
|
License and any non-permissive terms added in accord with section 7 apply to the
|
||||||
|
code; keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey, and you may
|
||||||
|
offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
### 5. Conveying Modified Source Versions
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to produce it
|
||||||
|
from the Program, in the form of source code under the terms of section 4,
|
||||||
|
provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
- **a)** The work must carry prominent notices stating that you modified it, and
|
||||||
|
giving a relevant date.
|
||||||
|
- **b)** The work must carry prominent notices stating that it is released under
|
||||||
|
this License and any conditions added under section 7. This requirement
|
||||||
|
modifies the requirement in section 4 to “keep intact all notices”.
|
||||||
|
- **c)** You must license the entire work, as a whole, under this License to
|
||||||
|
anyone who comes into possession of a copy. This License will therefore apply,
|
||||||
|
along with any applicable section 7 additional terms, to the whole of the
|
||||||
|
work, and all its parts, regardless of how they are packaged. This License
|
||||||
|
gives no permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
- **d)** If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive interfaces
|
||||||
|
that do not display Appropriate Legal Notices, your work need not make them do
|
||||||
|
so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent works, which
|
||||||
|
are not by their nature extensions of the covered work, and which are not
|
||||||
|
combined with it such as to form a larger program, in or on a volume of a
|
||||||
|
storage or distribution medium, is called an “aggregate” if the compilation and
|
||||||
|
its resulting copyright are not used to limit the access or legal rights of the
|
||||||
|
compilation's users beyond what the individual works permit. Inclusion of a
|
||||||
|
covered work in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
### 6. Conveying Non-Source Forms
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms of sections 4
|
||||||
|
and 5, provided that you also convey the machine-readable Corresponding Source
|
||||||
|
under the terms of this License, in one of these ways:
|
||||||
|
|
||||||
|
- **a)** Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the Corresponding
|
||||||
|
Source fixed on a durable physical medium customarily used for software
|
||||||
|
interchange.
|
||||||
|
- **b)** Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a written offer,
|
||||||
|
valid for at least three years and valid for as long as you offer spare parts
|
||||||
|
or customer support for that product model, to give anyone who possesses the
|
||||||
|
object code either **(1)** a copy of the Corresponding Source for all the
|
||||||
|
software in the product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no more than
|
||||||
|
your reasonable cost of physically performing this conveying of source, or
|
||||||
|
**(2)** access to copy the Corresponding Source from a network server at no
|
||||||
|
charge.
|
||||||
|
- **c)** Convey individual copies of the object code with a copy of the written
|
||||||
|
offer to provide the Corresponding Source. This alternative is allowed only
|
||||||
|
occasionally and noncommercially, and only if you received the object code
|
||||||
|
with such an offer, in accord with subsection 6b.
|
||||||
|
- **d)** Convey the object code by offering access from a designated place
|
||||||
|
(gratis or for a charge), and offer equivalent access to the Corresponding
|
||||||
|
Source in the same way through the same place at no further charge. You need
|
||||||
|
not require recipients to copy the Corresponding Source along with the object
|
||||||
|
code. If the place to copy the object code is a network server, the
|
||||||
|
Corresponding Source may be on a different server (operated by you or a third
|
||||||
|
party) that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the Corresponding
|
||||||
|
Source, you remain obligated to ensure that it is available for as long as
|
||||||
|
needed to satisfy these requirements.
|
||||||
|
- **e)** Convey the object code using peer-to-peer transmission, provided you
|
||||||
|
inform other peers where the object code and Corresponding Source of the work
|
||||||
|
are being offered to the general public at no charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded from the
|
||||||
|
Corresponding Source as a System Library, need not be included in conveying the
|
||||||
|
object code work.
|
||||||
|
|
||||||
|
A “User Product” is either **(1)** a “consumer product”, which means any
|
||||||
|
tangible personal property which is normally used for personal, family, or
|
||||||
|
household purposes, or **(2)** anything designed or sold for incorporation into
|
||||||
|
a dwelling. In determining whether a product is a consumer product, doubtful
|
||||||
|
cases shall be resolved in favor of coverage. For a particular product received
|
||||||
|
by a particular user, “normally used” refers to a typical or common use of that
|
||||||
|
class of product, regardless of the status of the particular user or of the way
|
||||||
|
in which the particular user actually uses, or expects or is expected to use,
|
||||||
|
the product. A product is a consumer product regardless of whether the product
|
||||||
|
has substantial commercial, industrial or non-consumer uses, unless such uses
|
||||||
|
represent the only significant mode of use of the product.
|
||||||
|
|
||||||
|
“Installation Information” for a User Product means any methods, procedures,
|
||||||
|
authorization keys, or other information required to install and execute
|
||||||
|
modified versions of a covered work in that User Product from a modified version
|
||||||
|
of its Corresponding Source. The information must suffice to ensure that the
|
||||||
|
continued functioning of the modified object code is in no case prevented or
|
||||||
|
interfered with solely because modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as part of a
|
||||||
|
transaction in which the right of possession and use of the User Product is
|
||||||
|
transferred to the recipient in perpetuity or for a fixed term (regardless of
|
||||||
|
how the transaction is characterized), the Corresponding Source conveyed under
|
||||||
|
this section must be accompanied by the Installation Information. But this
|
||||||
|
requirement does not apply if neither you nor any third party retains the
|
||||||
|
ability to install modified object code on the User Product (for example, the
|
||||||
|
work has been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates for a
|
||||||
|
work that has been modified or installed by the recipient, or for the User
|
||||||
|
Product in which it has been modified or installed. Access to a network may be
|
||||||
|
denied when the modification itself materially and adversely affects the
|
||||||
|
operation of the network or violates the rules and protocols for communication
|
||||||
|
across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided, in accord
|
||||||
|
with this section must be in a format that is publicly documented (and with an
|
||||||
|
implementation available to the public in source code form), and must require no
|
||||||
|
special password or key for unpacking, reading or copying.
|
||||||
|
|
||||||
|
### 7. Additional Terms
|
||||||
|
|
||||||
|
“Additional permissions” are terms that supplement the terms of this License by
|
||||||
|
making exceptions from one or more of its conditions. Additional permissions
|
||||||
|
that are applicable to the entire Program shall be treated as though they were
|
||||||
|
included in this License, to the extent that they are valid under applicable
|
||||||
|
law. If additional permissions apply only to part of the Program, that part may
|
||||||
|
be used separately under those permissions, but the entire Program remains
|
||||||
|
governed by this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option remove any
|
||||||
|
additional permissions from that copy, or from any part of it. (Additional
|
||||||
|
permissions may be written to require their own removal in certain cases when
|
||||||
|
you modify the work.) You may place additional permissions on material, added by
|
||||||
|
you to a covered work, for which you have or can give appropriate copyright
|
||||||
|
permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you add to a
|
||||||
|
covered work, you may (if authorized by the copyright holders of that material)
|
||||||
|
supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
- **a)** Disclaiming warranty or limiting liability differently from the terms
|
||||||
|
of sections 15 and 16 of this License; or
|
||||||
|
- **b)** Requiring preservation of specified reasonable legal notices or author
|
||||||
|
attributions in that material or in the Appropriate Legal Notices displayed by
|
||||||
|
works containing it; or
|
||||||
|
- **c)** Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in reasonable ways
|
||||||
|
as different from the original version; or
|
||||||
|
- **d)** Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
- **e)** Declining to grant rights under trademark law for use of some trade
|
||||||
|
names, trademarks, or service marks; or
|
||||||
|
- **f)** Requiring indemnification of licensors and authors of that material by
|
||||||
|
anyone who conveys the material (or modified versions of it) with contractual
|
||||||
|
assumptions of liability to the recipient, for any liability that these
|
||||||
|
contractual assumptions directly impose on those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered “further restrictions”
|
||||||
|
within the meaning of section 10. If the Program as you received it, or any part
|
||||||
|
of it, contains a notice stating that it is governed by this License along with
|
||||||
|
a term that is a further restriction, you may remove that term. If a license
|
||||||
|
document contains a further restriction but permits relicensing or conveying
|
||||||
|
under this License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does not survive
|
||||||
|
such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you must place,
|
||||||
|
in the relevant source files, a statement of the additional terms that apply to
|
||||||
|
those files, or a notice indicating where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the form of a
|
||||||
|
separately written license, or stated as exceptions; the above requirements
|
||||||
|
apply either way.
|
||||||
|
|
||||||
|
### 8. Termination
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly provided
|
||||||
|
under this License. Any attempt otherwise to propagate or modify it is void, and
|
||||||
|
will automatically terminate your rights under this License (including any
|
||||||
|
patent licenses granted under the third paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your license from a
|
||||||
|
particular copyright holder is reinstated **(a)** provisionally, unless and
|
||||||
|
until the copyright holder explicitly and finally terminates your license, and
|
||||||
|
**(b)** permanently, if the copyright holder fails to notify you of the
|
||||||
|
violation by some reasonable means prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is reinstated
|
||||||
|
permanently if the copyright holder notifies you of the violation by some
|
||||||
|
reasonable means, this is the first time you have received notice of violation
|
||||||
|
of this License (for any work) from that copyright holder, and you cure the
|
||||||
|
violation prior to 30 days after your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the licenses of
|
||||||
|
parties who have received copies or rights from you under this License. If your
|
||||||
|
rights have been terminated and not permanently reinstated, you do not qualify
|
||||||
|
to receive new licenses for the same material under section 10.
|
||||||
|
|
||||||
|
### 9. Acceptance Not Required for Having Copies
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or run a copy of
|
||||||
|
the Program. Ancillary propagation of a covered work occurring solely as a
|
||||||
|
consequence of using peer-to-peer transmission to receive a copy likewise does
|
||||||
|
not require acceptance. However, nothing other than this License grants you
|
||||||
|
permission to propagate or modify any covered work. These actions infringe
|
||||||
|
copyright if you do not accept this License. Therefore, by modifying or
|
||||||
|
propagating a covered work, you indicate your acceptance of this License to do
|
||||||
|
so.
|
||||||
|
|
||||||
|
### 10. Automatic Licensing of Downstream Recipients
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically receives a
|
||||||
|
license from the original licensors, to run, modify and propagate that work,
|
||||||
|
subject to this License. You are not responsible for enforcing compliance by
|
||||||
|
third parties with this License.
|
||||||
|
|
||||||
|
An “entity transaction” is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered work results
|
||||||
|
from an entity transaction, each party to that transaction who receives a copy
|
||||||
|
of the work also receives whatever licenses to the work the party's predecessor
|
||||||
|
in interest had or could give under the previous paragraph, plus a right to
|
||||||
|
possession of the Corresponding Source of the work from the predecessor in
|
||||||
|
interest, if the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the rights
|
||||||
|
granted or affirmed under this License. For example, you may not impose a
|
||||||
|
license fee, royalty, or other charge for exercise of rights granted under this
|
||||||
|
License, and you may not initiate litigation (including a cross-claim or
|
||||||
|
counterclaim in a lawsuit) alleging that any patent claim is infringed by
|
||||||
|
making, using, selling, offering for sale, or importing the Program or any
|
||||||
|
portion of it.
|
||||||
|
|
||||||
|
### 11. Patents
|
||||||
|
|
||||||
|
A “contributor” is a copyright holder who authorizes use under this License of
|
||||||
|
the Program or a work on which the Program is based. The work thus licensed is
|
||||||
|
called the contributor's “contributor version”.
|
||||||
|
|
||||||
|
A contributor's “essential patent claims” are all patent claims owned or
|
||||||
|
controlled by the contributor, whether already acquired or hereafter acquired,
|
||||||
|
that would be infringed by some manner, permitted by this License, of making,
|
||||||
|
using, or selling its contributor version, but do not include claims that would
|
||||||
|
be infringed only as a consequence of further modification of the contributor
|
||||||
|
version. For purposes of this definition, “control” includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free patent
|
||||||
|
license under the contributor's essential patent claims, to make, use, sell,
|
||||||
|
offer for sale, import and otherwise run, modify and propagate the contents of
|
||||||
|
its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a “patent license” is any express agreement
|
||||||
|
or commitment, however denominated, not to enforce a patent (such as an express
|
||||||
|
permission to practice a patent or covenant not to sue for patent infringement).
|
||||||
|
To “grant” such a patent license to a party means to make such an agreement or
|
||||||
|
commitment not to enforce a patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license, and the
|
||||||
|
Corresponding Source of the work is not available for anyone to copy, free of
|
||||||
|
charge and under the terms of this License, through a publicly available network
|
||||||
|
server or other readily accessible means, then you must either **(1)** cause the
|
||||||
|
Corresponding Source to be so available, or **(2)** arrange to deprive yourself
|
||||||
|
of the benefit of the patent license for this particular work, or **(3)**
|
||||||
|
arrange, in a manner consistent with the requirements of this License, to extend
|
||||||
|
the patent license to downstream recipients. “Knowingly relying” means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the covered
|
||||||
|
work in a country, or your recipient's use of the covered work in a country,
|
||||||
|
would infringe one or more identifiable patents in that country that you have
|
||||||
|
reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or arrangement, you
|
||||||
|
convey, or propagate by procuring conveyance of, a covered work, and grant a
|
||||||
|
patent license to some of the parties receiving the covered work authorizing
|
||||||
|
them to use, propagate, modify or convey a specific copy of the covered work,
|
||||||
|
then the patent license you grant is automatically extended to all recipients of
|
||||||
|
the covered work and works based on it.
|
||||||
|
|
||||||
|
A patent license is “discriminatory” if it does not include within the scope of
|
||||||
|
its coverage, prohibits the exercise of, or is conditioned on the non-exercise
|
||||||
|
of one or more of the rights that are specifically granted under this License.
|
||||||
|
You may not convey a covered work if you are a party to an arrangement with a
|
||||||
|
third party that is in the business of distributing software, under which you
|
||||||
|
make payment to the third party based on the extent of your activity of
|
||||||
|
conveying the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory patent
|
||||||
|
license **(a)** in connection with copies of the covered work conveyed by you
|
||||||
|
(or copies made from those copies), or **(b)** primarily for and in connection
|
||||||
|
with specific products or compilations that contain the covered work, unless you
|
||||||
|
entered into that arrangement, or that patent license was granted, prior to 28
|
||||||
|
March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting any implied
|
||||||
|
license or other defenses to infringement that may otherwise be available to you
|
||||||
|
under applicable patent law.
|
||||||
|
|
||||||
|
### 12. No Surrender of Others' Freedom
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not excuse
|
||||||
|
you from the conditions of this License. If you cannot convey a covered work so
|
||||||
|
as to satisfy simultaneously your obligations under this License and any other
|
||||||
|
pertinent obligations, then as a consequence you may not convey it at all. For
|
||||||
|
example, if you agree to terms that obligate you to collect a royalty for
|
||||||
|
further conveying from those to whom you convey the Program, the only way you
|
||||||
|
could satisfy both those terms and this License would be to refrain entirely
|
||||||
|
from conveying the Program.
|
||||||
|
|
||||||
|
### 13. Remote Network Interaction; Use with the GNU General Public License
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the Program,
|
||||||
|
your modified version must prominently offer all users interacting with it
|
||||||
|
remotely through a computer network (if your version supports such interaction)
|
||||||
|
an opportunity to receive the Corresponding Source of your version by providing
|
||||||
|
access to the Corresponding Source from a network server at no charge, through
|
||||||
|
some standard or customary means of facilitating copying of software. This
|
||||||
|
Corresponding Source shall include the Corresponding Source for any work covered
|
||||||
|
by version 3 of the GNU General Public License that is incorporated pursuant to
|
||||||
|
the following paragraph.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have permission to link
|
||||||
|
or combine any covered work with a work licensed under version 3 of the GNU
|
||||||
|
General Public License into a single combined work, and to convey the resulting
|
||||||
|
work. The terms of this License will continue to apply to the part which is the
|
||||||
|
covered work, but the work with which it is combined will remain governed by
|
||||||
|
version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
### 14. Revised Versions of this License
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of the GNU
|
||||||
|
Affero General Public License from time to time. Such new versions will be
|
||||||
|
similar in spirit to the present version, but may differ in detail to address
|
||||||
|
new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program specifies
|
||||||
|
that a certain numbered version of the GNU Affero General Public License “or any
|
||||||
|
later version” applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that numbered version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Program does not specify a version number
|
||||||
|
of the GNU Affero General Public License, you may choose any version ever
|
||||||
|
published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future versions of the
|
||||||
|
GNU Affero General Public License can be used, that proxy's public statement of
|
||||||
|
acceptance of a version permanently authorizes you to choose that version for
|
||||||
|
the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different permissions.
|
||||||
|
However, no additional obligations are imposed on any author or copyright holder
|
||||||
|
as a result of your choosing to follow a later version.
|
||||||
|
|
||||||
|
### 15. Disclaimer of Warranty
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
|
||||||
|
PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||||
|
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
|
||||||
|
QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
|
||||||
|
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
### 16. Limitation of Liability
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
|
||||||
|
COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
|
||||||
|
PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
|
||||||
|
INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
|
||||||
|
THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
|
||||||
|
INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
|
||||||
|
PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY
|
||||||
|
HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
### 17. Interpretation of Sections 15 and 16
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided above cannot
|
||||||
|
be given local legal effect according to their terms, reviewing courts shall
|
||||||
|
apply local law that most closely approximates an absolute waiver of all civil
|
||||||
|
liability in connection with the Program, unless a warranty or assumption of
|
||||||
|
liability accompanies a copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
_END OF TERMS AND CONDITIONS_
|
||||||
|
|
||||||
|
## How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest possible use
|
||||||
|
to the public, the best way to achieve this is to make it free software which
|
||||||
|
everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest to attach
|
||||||
|
them to the start of each source file to most effectively state the exclusion of
|
||||||
|
warranty; and each file should have at least the “copyright” line and a pointer
|
||||||
|
to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If your software can interact with users remotely through a computer network,
|
||||||
|
you should also make sure that it provides a way for users to get its source.
|
||||||
|
For example, if your program is a web application, its interface could display a
|
||||||
|
“Source” link that leads users to an archive of the code. There are many ways
|
||||||
|
you could offer source, and different solutions will be better for different
|
||||||
|
programs; see section 13 for the specific requirements.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school, if
|
||||||
|
any, to sign a “copyright disclaimer” for the program, if necessary. For more
|
||||||
|
information on this, and how to apply and follow the GNU AGPL, see
|
||||||
|
<<http://www.gnu.org/licenses/>>.
|
12
README.md
12
README.md
|
@ -3,12 +3,12 @@
|
||||||
Castopod is an open-source podcast hosting solution for everyone.\
|
Castopod is an open-source podcast hosting solution for everyone.\
|
||||||
Whether you are a beginner, an amateur or a professional, you will get everything
|
Whether you are a beginner, an amateur or a professional, you will get everything
|
||||||
you need:\
|
you need:\
|
||||||
Create, upload, publish, and get comprehensive audience measurement that respects your
|
Create, upload, publish, and get comprehensive audience measurement that
|
||||||
listeners privacy.
|
respects your listeners privacy.
|
||||||
|
|
||||||
Castopod is a free and open-source solution (AGPL v3).\
|
Castopod is a free and open-source solution (AGPL v3).\
|
||||||
Whether you choose to install it on your own server or have it hosted by a
|
Whether you choose to install it on your own server or have it hosted by a professional,
|
||||||
professional, all your data and analytics belong to you and you only.
|
all your data and analytics belong to you and you only.
|
||||||
|
|
||||||
![Castopod Logo](https://podlibre.org/static/images/Castopod-Mascot-Server.svg)
|
![Castopod Logo](https://podlibre.org/static/images/Castopod-Mascot-Server.svg)
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ Castopod can be hosted on any PHP/MySQL server:\
|
||||||
Unzip it and you are ready to broadcast.
|
Unzip it and you are ready to broadcast.
|
||||||
|
|
||||||
To install Castopod on your server:
|
To install Castopod on your server:
|
||||||
- Download [Castopod latest Package (zip or tar.gz)](https://code.podlibre.org/podlibre/castopod/-/releases),
|
|
||||||
|
- Download
|
||||||
|
[Castopod latest Package (zip or tar.gz)](https://code.podlibre.org/podlibre/castopod/-/releases),
|
||||||
- Follow the procedure “[How to install Castopod](./INSTALL.md)”.
|
- Follow the procedure “[How to install Castopod](./INSTALL.md)”.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php namespace Config;
|
||||||
|
|
||||||
|
use ActivityPub\Config\ActivityPub as ActivityPubBase;
|
||||||
|
|
||||||
|
class ActivityPub extends ActivityPubBase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* ActivityPub Objects
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
public $actorObject = 'App\Libraries\PodcastActor';
|
||||||
|
public $noteObject = 'App\Libraries\NoteObject';
|
||||||
|
}
|
|
@ -6,309 +6,487 @@ use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
class App extends BaseConfig
|
class App extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Base Site URL
|
* Base Site URL
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| URL to your CodeIgniter root. Typically this will be your base URL,
|
* URL to your CodeIgniter root. Typically this will be your base URL,
|
||||||
| WITH a trailing slash:
|
* WITH a trailing slash:
|
||||||
|
|
*
|
||||||
| http://example.com/
|
* http://example.com/
|
||||||
|
|
*
|
||||||
| If this is not set then CodeIgniter will try guess the protocol, domain
|
* If this is not set then CodeIgniter will try guess the protocol, domain
|
||||||
| and path to your installation. However, you should always configure this
|
* and path to your installation. However, you should always configure this
|
||||||
| explicitly and never rely on auto-guessing, especially in production
|
* explicitly and never rely on auto-guessing, especially in production
|
||||||
| environments.
|
* environments.
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
public $baseURL = 'http://127.0.0.1:8080/';
|
*/
|
||||||
|
public $baseURL = 'http://localhost:8080/';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Media Base URL
|
* Media Base URL
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| URL to your media root. Typically this will be your base URL,
|
* URL to your media root. Typically this will be your base URL,
|
||||||
| WITH a trailing slash:
|
* WITH a trailing slash:
|
||||||
|
|
*
|
||||||
| http://cdn.example.com/
|
* http://cdn.example.com/
|
||||||
|
|
*/
|
||||||
*/
|
|
||||||
public $mediaBaseURL = 'http://127.0.0.2:8080/';
|
public $mediaBaseURL = 'http://127.0.0.2:8080/';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Index File
|
* Index File
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| Typically this will be your index.php file, unless you've renamed it to
|
* Typically this will be your index.php file, unless you've renamed it to
|
||||||
| something else. If you are using mod_rewrite to remove the page set this
|
* something else. If you are using mod_rewrite to remove the page set this
|
||||||
| variable so that it is blank.
|
* variable so that it is blank.
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $indexPage = '';
|
public $indexPage = '';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| URI PROTOCOL
|
* URI PROTOCOL
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| This item determines which getServer global should be used to retrieve the
|
* This item determines which getServer global should be used to retrieve the
|
||||||
| URI string. The default setting of 'REQUEST_URI' works for most servers.
|
* URI string. The default setting of 'REQUEST_URI' works for most servers.
|
||||||
| If your links do not seem to work, try one of the other delicious flavors:
|
* If your links do not seem to work, try one of the other delicious flavors:
|
||||||
|
|
*
|
||||||
| 'REQUEST_URI' Uses $_SERVER['REQUEST_URI']
|
* 'REQUEST_URI' Uses $_SERVER['REQUEST_URI']
|
||||||
| 'QUERY_STRING' Uses $_SERVER['QUERY_STRING']
|
* 'QUERY_STRING' Uses $_SERVER['QUERY_STRING']
|
||||||
| 'PATH_INFO' Uses $_SERVER['PATH_INFO']
|
* 'PATH_INFO' Uses $_SERVER['PATH_INFO']
|
||||||
|
|
*
|
||||||
| WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
|
* WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
|
||||||
*/
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $uriProtocol = 'REQUEST_URI';
|
public $uriProtocol = 'REQUEST_URI';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Default Locale
|
* Default Locale
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| The Locale roughly represents the language and location that your visitor
|
* The Locale roughly represents the language and location that your visitor
|
||||||
| is viewing the site from. It affects the language strings and other
|
* is viewing the site from. It affects the language strings and other
|
||||||
| strings (like currency markers, numbers, etc), that your program
|
* strings (like currency markers, numbers, etc), that your program
|
||||||
| should run under for this request.
|
* should run under for this request.
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $defaultLocale = 'en';
|
public $defaultLocale = 'en';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Negotiate Locale
|
* Negotiate Locale
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| If true, the current Request object will automatically determine the
|
* If true, the current Request object will automatically determine the
|
||||||
| language to use based on the value of the Accept-Language header.
|
* language to use based on the value of the Accept-Language header.
|
||||||
|
|
*
|
||||||
| If false, no automatic detection will be performed.
|
* If false, no automatic detection will be performed.
|
||||||
|
|
*
|
||||||
*/
|
* @var boolean
|
||||||
|
*/
|
||||||
public $negotiateLocale = true;
|
public $negotiateLocale = true;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Supported Locales
|
* Supported Locales
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| If $negotiateLocale is true, this array lists the locales supported
|
* If $negotiateLocale is true, this array lists the locales supported
|
||||||
| by the application in descending order of priority. If no match is
|
* by the application in descending order of priority. If no match is
|
||||||
| found, the first locale will be used.
|
* found, the first locale will be used.
|
||||||
|
|
*
|
||||||
*/
|
* @var string[]
|
||||||
|
*/
|
||||||
public $supportedLocales = ['en', 'fr'];
|
public $supportedLocales = ['en', 'fr'];
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Application Timezone
|
* Application Timezone
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| The default timezone that will be used in your application to display
|
* The default timezone that will be used in your application to display
|
||||||
| dates with the date helper, and can be retrieved through app_timezone()
|
* dates with the date helper, and can be retrieved through app_timezone()
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $appTimezone = 'UTC';
|
public $appTimezone = 'UTC';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Default Character Set
|
* Default Character Set
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| This determines which character set is used by default in various methods
|
* This determines which character set is used by default in various methods
|
||||||
| that require a character set to be provided.
|
* that require a character set to be provided.
|
||||||
|
|
*
|
||||||
| See http://php.net/htmlspecialchars for a list of supported charsets.
|
* @see http://php.net/htmlspecialchars for a list of supported charsets.
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $charset = 'UTF-8';
|
public $charset = 'UTF-8';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| URI PROTOCOL
|
* URI PROTOCOL
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| If true, this will force every request made to this application to be
|
* If true, this will force every request made to this application to be
|
||||||
| made via a secure connection (HTTPS). If the incoming request is not
|
* made via a secure connection (HTTPS). If the incoming request is not
|
||||||
| secure, the user will be redirected to a secure version of the page
|
* secure, the user will be redirected to a secure version of the page
|
||||||
| and the HTTP Strict Transport Security header will be set.
|
* and the HTTP Strict Transport Security header will be set.
|
||||||
*/
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
public $forceGlobalSecureRequests = false;
|
public $forceGlobalSecureRequests = false;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Session Variables
|
* Session Driver
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| 'sessionDriver'
|
* The session storage driver to use:
|
||||||
|
|
* - `CodeIgniter\Session\Handlers\FileHandler`
|
||||||
| The storage driver to use: files, database, redis, memcached
|
* - `CodeIgniter\Session\Handlers\DatabaseHandler`
|
||||||
| - CodeIgniter\Session\Handlers\FileHandler
|
* - `CodeIgniter\Session\Handlers\MemcachedHandler`
|
||||||
| - CodeIgniter\Session\Handlers\DatabaseHandler
|
* - `CodeIgniter\Session\Handlers\RedisHandler`
|
||||||
| - CodeIgniter\Session\Handlers\MemcachedHandler
|
*
|
||||||
| - CodeIgniter\Session\Handlers\RedisHandler
|
* @var string
|
||||||
|
|
*/
|
||||||
| 'sessionCookieName'
|
|
||||||
|
|
|
||||||
| The session cookie name, must contain only [0-9a-z_-] characters
|
|
||||||
|
|
|
||||||
| 'sessionExpiration'
|
|
||||||
|
|
|
||||||
| The number of SECONDS you want the session to last.
|
|
||||||
| Setting to 0 (zero) means expire when the browser is closed.
|
|
||||||
|
|
|
||||||
| 'sessionSavePath'
|
|
||||||
|
|
|
||||||
| The location to save sessions to, driver dependent.
|
|
||||||
|
|
|
||||||
| For the 'files' driver, it's a path to a writable directory.
|
|
||||||
| WARNING: Only absolute paths are supported!
|
|
||||||
|
|
|
||||||
| For the 'database' driver, it's a table name.
|
|
||||||
| Please read up the manual for the format with other session drivers.
|
|
||||||
|
|
|
||||||
| IMPORTANT: You are REQUIRED to set a valid save path!
|
|
||||||
|
|
|
||||||
| 'sessionMatchIP'
|
|
||||||
|
|
|
||||||
| Whether to match the user's IP address when reading the session data.
|
|
||||||
|
|
|
||||||
| WARNING: If you're using the database driver, don't forget to update
|
|
||||||
| your session table's PRIMARY KEY when changing this setting.
|
|
||||||
|
|
|
||||||
| 'sessionTimeToUpdate'
|
|
||||||
|
|
|
||||||
| How many seconds between CI regenerating the session ID.
|
|
||||||
|
|
|
||||||
| 'sessionRegenerateDestroy'
|
|
||||||
|
|
|
||||||
| Whether to destroy session data associated with the old session ID
|
|
||||||
| when auto-regenerating the session ID. When set to FALSE, the data
|
|
||||||
| will be later deleted by the garbage collector.
|
|
||||||
|
|
|
||||||
| Other session cookie settings are shared with the rest of the application,
|
|
||||||
| except for 'cookie_prefix' and 'cookie_httponly', which are ignored here.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
public $sessionDriver = 'CodeIgniter\Session\Handlers\FileHandler';
|
public $sessionDriver = 'CodeIgniter\Session\Handlers\FileHandler';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Session Cookie Name
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The session cookie name, must contain only [0-9a-z_-] characters
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $sessionCookieName = 'ci_session';
|
public $sessionCookieName = 'ci_session';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Session Expiration
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The number of SECONDS you want the session to last.
|
||||||
|
* Setting to 0 (zero) means expire when the browser is closed.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
public $sessionExpiration = 7200;
|
public $sessionExpiration = 7200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Session Save Path
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The location to save sessions to and is driver dependent.
|
||||||
|
*
|
||||||
|
* For the 'files' driver, it's a path to a writable directory.
|
||||||
|
* WARNING: Only absolute paths are supported!
|
||||||
|
*
|
||||||
|
* For the 'database' driver, it's a table name.
|
||||||
|
* Please read up the manual for the format with other session drivers.
|
||||||
|
*
|
||||||
|
* IMPORTANT: You are REQUIRED to set a valid save path!
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $sessionSavePath = WRITEPATH . 'session';
|
public $sessionSavePath = WRITEPATH . 'session';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Session Match IP
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Whether to match the user's IP address when reading the session data.
|
||||||
|
*
|
||||||
|
* WARNING: If you're using the database driver, don't forget to update
|
||||||
|
* your session table's PRIMARY KEY when changing this setting.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
public $sessionMatchIP = false;
|
public $sessionMatchIP = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Session Time to Update
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* How many seconds between CI regenerating the session ID.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
public $sessionTimeToUpdate = 300;
|
public $sessionTimeToUpdate = 300;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Session Regenerate Destroy
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Whether to destroy session data associated with the old session ID
|
||||||
|
* when auto-regenerating the session ID. When set to FALSE, the data
|
||||||
|
* will be later deleted by the garbage collector.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
public $sessionRegenerateDestroy = false;
|
public $sessionRegenerateDestroy = false;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Cookie Related Variables
|
* Cookie Prefix
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| 'cookiePrefix' = Set a cookie name prefix if you need to avoid collisions
|
* Set a cookie name prefix if you need to avoid collisions.
|
||||||
| 'cookieDomain' = Set to .your-domain.com for site-wide cookies
|
*
|
||||||
| 'cookiePath' = Typically will be a forward slash
|
* @var string
|
||||||
| 'cookieSecure' = Cookie will only be set if a secure HTTPS connection exists.
|
*/
|
||||||
| 'cookieHTTPOnly' = Cookie will only be accessible via HTTP(S) (no javascript)
|
|
||||||
|
|
|
||||||
| Note: These settings (with the exception of 'cookie_prefix' and
|
|
||||||
| 'cookie_httponly') will also affect sessions.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
public $cookiePrefix = '';
|
public $cookiePrefix = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Cookie Domain
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Set to `.your-domain.com` for site-wide cookies.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $cookieDomain = '';
|
public $cookieDomain = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Cookie Path
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Typically will be a forward slash.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $cookiePath = '/';
|
public $cookiePath = '/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Cookie Secure
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Cookie will only be set if a secure HTTPS connection exists.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
public $cookieSecure = false;
|
public $cookieSecure = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Cookie HTTP Only
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Cookie will only be accessible via HTTP(S) (no JavaScript).
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
public $cookieHTTPOnly = false;
|
public $cookieHTTPOnly = false;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Reverse Proxy IPs
|
* Cookie SameSite
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| If your server is behind a reverse proxy, you must whitelist the proxy
|
* Configure cookie SameSite setting. Allowed values are:
|
||||||
| IP addresses from which CodeIgniter should trust headers such as
|
* - None
|
||||||
| HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify
|
* - Lax
|
||||||
| the visitor's IP address.
|
* - Strict
|
||||||
|
|
* - ''
|
||||||
| You can use both an array or a comma-separated list of proxy addresses,
|
*
|
||||||
| as well as specifying whole subnets. Here are a few examples:
|
* Defaults to `Lax` for compatibility with modern browsers. Setting `''`
|
||||||
|
|
* (empty string) means no SameSite attribute will be set on cookies. If
|
||||||
| Comma-separated: '10.0.1.200,192.168.5.0/24'
|
* set to `None`, `$cookieSecure` must also be set.
|
||||||
| Array: array('10.0.1.200', '192.168.5.0/24')
|
*
|
||||||
*/
|
* @var string 'Lax'|'None'|'Strict'
|
||||||
|
*/
|
||||||
|
public $cookieSameSite = 'Lax';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Reverse Proxy IPs
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* If your server is behind a reverse proxy, you must whitelist the proxy
|
||||||
|
* IP addresses from which CodeIgniter should trust headers such as
|
||||||
|
* HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify
|
||||||
|
* the visitor's IP address.
|
||||||
|
*
|
||||||
|
* You can use both an array or a comma-separated list of proxy addresses,
|
||||||
|
* as well as specifying whole subnets. Here are a few examples:
|
||||||
|
*
|
||||||
|
* Comma-separated: '10.0.1.200,192.168.5.0/24'
|
||||||
|
* Array: ['10.0.1.200', '192.168.5.0/24']
|
||||||
|
*
|
||||||
|
* @var string|string[]
|
||||||
|
*/
|
||||||
public $proxyIPs = '';
|
public $proxyIPs = '';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Cross Site Request Forgery
|
* CSRF Token Name
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Enables a CSRF cookie token to be set. When set to TRUE, token will be
|
*
|
||||||
| checked on a submitted form. If you are accepting user data, it is strongly
|
* The token name.
|
||||||
| recommended CSRF protection be enabled.
|
*
|
||||||
|
|
* @deprecated Use `Config\Security` $tokenName property instead of using this property.
|
||||||
| CSRFTokenName = The token name
|
*
|
||||||
| CSRFHeaderName = The header name
|
* @var string
|
||||||
| CSRFCookieName = The cookie name
|
*/
|
||||||
| CSRFExpire = The number in seconds the token should expire.
|
|
||||||
| CSRFRegenerate = Regenerate token on every submission
|
|
||||||
| CSRFRedirect = Redirect to previous page with error on failure
|
|
||||||
*/
|
|
||||||
public $CSRFTokenName = 'csrf_test_name';
|
public $CSRFTokenName = 'csrf_test_name';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Header Name
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The header name.
|
||||||
|
*
|
||||||
|
* @deprecated Use `Config\Security` $headerName property instead of using this property.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $CSRFHeaderName = 'X-CSRF-TOKEN';
|
public $CSRFHeaderName = 'X-CSRF-TOKEN';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Cookie Name
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The cookie name.
|
||||||
|
*
|
||||||
|
* @deprecated Use `Config\Security` $cookieName property instead of using this property.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $CSRFCookieName = 'csrf_cookie_name';
|
public $CSRFCookieName = 'csrf_cookie_name';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Expire
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The number in seconds the token should expire.
|
||||||
|
*
|
||||||
|
* @deprecated Use `Config\Security` $expire property instead of using this property.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
public $CSRFExpire = 7200;
|
public $CSRFExpire = 7200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Regenerate
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Regenerate token on every submission?
|
||||||
|
*
|
||||||
|
* @deprecated Use `Config\Security` $regenerate property instead of using this property.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
public $CSRFRegenerate = true;
|
public $CSRFRegenerate = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Redirect
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Redirect to previous page with error on failure?
|
||||||
|
*
|
||||||
|
* @deprecated Use `Config\Security` $redirect property instead of using this property.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
public $CSRFRedirect = true;
|
public $CSRFRedirect = true;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Content Security Policy
|
* CSRF SameSite
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Enables the Response's Content Secure Policy to restrict the sources that
|
*
|
||||||
| can be used for images, scripts, CSS files, audio, video, etc. If enabled,
|
* Setting for CSRF SameSite cookie token. Allowed values are:
|
||||||
| the Response object will populate default values for the policy from the
|
* - None
|
||||||
| ContentSecurityPolicy.php file. Controllers can always add to those
|
* - Lax
|
||||||
| restrictions at run time.
|
* - Strict
|
||||||
|
|
* - ''
|
||||||
| For a better understanding of CSP, see these documents:
|
*
|
||||||
| - http://www.html5rocks.com/en/tutorials/security/content-security-policy/
|
* Defaults to `Lax` as recommended in this link:
|
||||||
| - http://www.w3.org/TR/CSP/
|
*
|
||||||
*/
|
* @see https://portswigger.net/web-security/csrf/samesite-cookies
|
||||||
|
*
|
||||||
|
* @deprecated Use `Config\Security` $samesite property instead of using this property.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $CSRFSameSite = 'Lax';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Content Security Policy
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Enables the Response's Content Secure Policy to restrict the sources that
|
||||||
|
* can be used for images, scripts, CSS files, audio, video, etc. If enabled,
|
||||||
|
* the Response object will populate default values for the policy from the
|
||||||
|
* `ContentSecurityPolicy.php` file. Controllers can always add to those
|
||||||
|
* restrictions at run time.
|
||||||
|
*
|
||||||
|
* For a better understanding of CSP, see these documents:
|
||||||
|
*
|
||||||
|
* @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/
|
||||||
|
* @see http://www.w3.org/TR/CSP/
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
public $CSPEnabled = false;
|
public $CSPEnabled = false;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Media root folder
|
* Media root folder
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Defines the root folder for media files storage
|
* Defines the root folder for media files storage
|
||||||
*/
|
*/
|
||||||
public $mediaRoot = 'media';
|
public $mediaRoot = 'media';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Admin gateway
|
* Admin gateway
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Defines a base route for all admin pages
|
* Defines a base route for all admin pages
|
||||||
*/
|
*/
|
||||||
public $adminGateway = 'cp-admin';
|
public $adminGateway = 'cp-admin';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Auth gateway
|
* Auth gateway
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Defines a base route for all authentication related pages
|
* Defines a base route for all authentication related pages
|
||||||
*/
|
*/
|
||||||
public $authGateway = 'cp-auth';
|
public $authGateway = 'cp-auth';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Install gateway
|
* Install gateway
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Defines a base route for instance installation
|
* Defines a base route for instance installation
|
||||||
*/
|
*/
|
||||||
public $installGateway = 'cp-install';
|
public $installGateway = 'cp-install';
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,90 +2,66 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
require_once SYSTEMPATH . 'Config/AutoloadConfig.php';
|
use CodeIgniter\Config\AutoloadConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* -------------------------------------------------------------------
|
* -------------------------------------------------------------------
|
||||||
* AUTO-LOADER
|
* AUTO-LOADER
|
||||||
* -------------------------------------------------------------------
|
* -------------------------------------------------------------------
|
||||||
|
*
|
||||||
* This file defines the namespaces and class maps so the Autoloader
|
* This file defines the namespaces and class maps so the Autoloader
|
||||||
* can find the files as needed.
|
* can find the files as needed.
|
||||||
|
*
|
||||||
|
* NOTE: If you use an identical key in $psr4 or $classmap, then
|
||||||
|
* the values in this file will overwrite the framework's values.
|
||||||
*/
|
*/
|
||||||
class Autoload extends \CodeIgniter\Config\AutoloadConfig
|
class Autoload extends AutoloadConfig
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
* Namespaces
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
* This maps the locations of any namespaces in your application to
|
||||||
|
* their location on the file system. These are used by the autoloader
|
||||||
|
* to locate files the first time they have been instantiated.
|
||||||
|
*
|
||||||
|
* The '/app' and '/system' directories are already mapped for you.
|
||||||
|
* you may change the name of the 'App' namespace if you wish,
|
||||||
|
* but this should be done prior to creating any namespaced classes,
|
||||||
|
* else you will need to modify all of those classes for this to work.
|
||||||
|
*
|
||||||
|
* Prototype:
|
||||||
|
*
|
||||||
|
* $psr4 = [
|
||||||
|
* 'CodeIgniter' => SYSTEMPATH,
|
||||||
|
* 'App' => APPPATH
|
||||||
|
* ];
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
public $psr4 = [
|
public $psr4 = [
|
||||||
'App' => APPPATH,
|
APP_NAMESPACE => APPPATH, // For custom app namespace
|
||||||
|
'Config' => APPPATH . 'Config',
|
||||||
|
'ActivityPub' => APPPATH . 'Libraries/ActivityPub',
|
||||||
];
|
];
|
||||||
|
|
||||||
public $classmap = [];
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collects the application-specific autoload settings and merges
|
* -------------------------------------------------------------------
|
||||||
* them with the framework's required settings.
|
* Class Map
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
* The class map provides a map of class names and their exact
|
||||||
|
* location on the drive. Classes loaded in this manner will have
|
||||||
|
* slightly faster performance because they will not have to be
|
||||||
|
* searched for within one or more directories as they would if they
|
||||||
|
* were being autoloaded through a namespace.
|
||||||
*
|
*
|
||||||
* NOTE: If you use an identical key in $psr4 or $classmap, then
|
* Prototype:
|
||||||
* the values in this file will overwrite the framework's values.
|
*
|
||||||
|
* $classmap = [
|
||||||
|
* 'MyClass' => '/path/to/class/file.php'
|
||||||
|
* ];
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
public function __construct()
|
public $classmap = [];
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* -------------------------------------------------------------------
|
|
||||||
* Namespaces
|
|
||||||
* -------------------------------------------------------------------
|
|
||||||
* This maps the locations of any namespaces in your application
|
|
||||||
* to their location on the file system. These are used by the
|
|
||||||
* Autoloader to locate files the first time they have been instantiated.
|
|
||||||
*
|
|
||||||
* The '/app' and '/system' directories are already mapped for
|
|
||||||
* you. You may change the name of the 'App' namespace if you wish,
|
|
||||||
* but this should be done prior to creating any namespaced classes,
|
|
||||||
* else you will need to modify all of those classes for this to work.
|
|
||||||
*
|
|
||||||
* DO NOT change the name of the CodeIgniter namespace or your application
|
|
||||||
* WILL break. *
|
|
||||||
* Prototype:
|
|
||||||
*
|
|
||||||
* $Config['psr4'] = [
|
|
||||||
* 'CodeIgniter' => SYSPATH
|
|
||||||
* `];
|
|
||||||
*/
|
|
||||||
$psr4 = [
|
|
||||||
'App' => APPPATH, // To ensure filters, etc still found,
|
|
||||||
APP_NAMESPACE => APPPATH, // For custom namespace
|
|
||||||
'Config' => APPPATH . 'Config',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* -------------------------------------------------------------------
|
|
||||||
* Class Map
|
|
||||||
* -------------------------------------------------------------------
|
|
||||||
* The class map provides a map of class names and their exact
|
|
||||||
* location on the drive. Classes loaded in this manner will have
|
|
||||||
* slightly faster performance because they will not have to be
|
|
||||||
* searched for within one or more directories as they would if they
|
|
||||||
* were being autoloaded through a namespace.
|
|
||||||
*
|
|
||||||
* Prototype:
|
|
||||||
*
|
|
||||||
* $Config['classmap'] = [
|
|
||||||
* 'MyClass' => '/path/to/class/file.php'
|
|
||||||
* ];
|
|
||||||
*/
|
|
||||||
$classmap = [];
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// Do Not Edit Below This Line
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
|
|
||||||
$this->psr4 = array_merge($this->psr4, $psr4);
|
|
||||||
$this->classmap = array_merge($this->classmap, $classmap);
|
|
||||||
|
|
||||||
unset($psr4, $classmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,32 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| ERROR DISPLAY
|
* ERROR DISPLAY
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| In development, we want to show as many errors as possible to help
|
* In development, we want to show as many errors as possible to help
|
||||||
| make sure they don't make it to production. And save us hours of
|
* make sure they don't make it to production. And save us hours of
|
||||||
| painful debugging.
|
* painful debugging.
|
||||||
*/
|
*/
|
||||||
error_reporting(-1);
|
error_reporting(-1);
|
||||||
ini_set('display_errors', '1');
|
ini_set('display_errors', '1');
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| DEBUG BACKTRACES
|
* DEBUG BACKTRACES
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| If true, this constant will tell the error screens to display debug
|
* If true, this constant will tell the error screens to display debug
|
||||||
| backtraces along with the other error information. If you would
|
* backtraces along with the other error information. If you would
|
||||||
| prefer to not see this, set this value to false.
|
* prefer to not see this, set this value to false.
|
||||||
*/
|
*/
|
||||||
defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
|
defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| DEBUG MODE
|
* DEBUG MODE
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Debug mode is an experimental flag that can allow changes throughout
|
* Debug mode is an experimental flag that can allow changes throughout
|
||||||
| the system. This will control whether Kint is loaded, and a few other
|
* the system. This will control whether Kint is loaded, and a few other
|
||||||
| items. It can always be used within your own application too.
|
* items. It can always be used within your own application too.
|
||||||
*/
|
*/
|
||||||
|
defined('CI_DEBUG') || define('CI_DEBUG', true);
|
||||||
defined('CI_DEBUG') || define('CI_DEBUG', 1);
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| ERROR DISPLAY
|
* ERROR DISPLAY
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Don't show ANY in production environments. Instead, let the system catch
|
* Don't show ANY in production environments. Instead, let the system catch
|
||||||
| it and display a generic error message.
|
* it and display a generic error message.
|
||||||
*/
|
*/
|
||||||
ini_set('display_errors', '0');
|
ini_set('display_errors', '0');
|
||||||
error_reporting(
|
error_reporting(
|
||||||
|
@ -14,16 +14,15 @@ error_reporting(
|
||||||
~E_DEPRECATED &
|
~E_DEPRECATED &
|
||||||
~E_STRICT &
|
~E_STRICT &
|
||||||
~E_USER_NOTICE &
|
~E_USER_NOTICE &
|
||||||
~E_USER_DEPRECATED
|
~E_USER_DEPRECATED,
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| DEBUG MODE
|
* DEBUG MODE
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Debug mode is an experimental flag that can allow changes throughout
|
* Debug mode is an experimental flag that can allow changes throughout
|
||||||
| the system. It's not widely used currently, and may not survive
|
* the system. It's not widely used currently, and may not survive
|
||||||
| release of the framework.
|
* release of the framework.
|
||||||
*/
|
*/
|
||||||
|
defined('CI_DEBUG') || define('CI_DEBUG', false);
|
||||||
defined('CI_DEBUG') || define('CI_DEBUG', 0);
|
|
||||||
|
|
|
@ -1,33 +1,32 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| ERROR DISPLAY
|
* ERROR DISPLAY
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| In development, we want to show as many errors as possible to help
|
* In development, we want to show as many errors as possible to help
|
||||||
| make sure they don't make it to production. And save us hours of
|
* make sure they don't make it to production. And save us hours of
|
||||||
| painful debugging.
|
* painful debugging.
|
||||||
*/
|
*/
|
||||||
error_reporting(-1);
|
error_reporting(-1);
|
||||||
ini_set('display_errors', '1');
|
ini_set('display_errors', '1');
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| DEBUG BACKTRACES
|
* DEBUG BACKTRACES
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| If true, this constant will tell the error screens to display debug
|
* If true, this constant will tell the error screens to display debug
|
||||||
| backtraces along with the other error information. If you would
|
* backtraces along with the other error information. If you would
|
||||||
| prefer to not see this, set this value to false.
|
* prefer to not see this, set this value to false.
|
||||||
*/
|
*/
|
||||||
defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
|
defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| DEBUG MODE
|
* DEBUG MODE
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Debug mode is an experimental flag that can allow changes throughout
|
* Debug mode is an experimental flag that can allow changes throughout
|
||||||
| the system. It's not widely used currently, and may not survive
|
* the system. It's not widely used currently, and may not survive
|
||||||
| release of the framework.
|
* release of the framework.
|
||||||
*/
|
*/
|
||||||
|
defined('CI_DEBUG') || define('CI_DEBUG', true);
|
||||||
defined('CI_DEBUG') || define('CI_DEBUG', 1);
|
|
||||||
|
|
|
@ -2,83 +2,111 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
|
use CodeIgniter\Cache\Handlers\DummyHandler;
|
||||||
|
use CodeIgniter\Cache\Handlers\FileHandler;
|
||||||
|
use CodeIgniter\Cache\Handlers\MemcachedHandler;
|
||||||
|
use CodeIgniter\Cache\Handlers\PredisHandler;
|
||||||
|
use CodeIgniter\Cache\Handlers\RedisHandler;
|
||||||
|
use CodeIgniter\Cache\Handlers\WincacheHandler;
|
||||||
use CodeIgniter\Config\BaseConfig;
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
class Cache extends BaseConfig
|
class Cache extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Primary Handler
|
* Primary Handler
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| The name of the preferred handler that should be used. If for some reason
|
* The name of the preferred handler that should be used. If for some reason
|
||||||
| it is not available, the $backupHandler will be used in its place.
|
* it is not available, the $backupHandler will be used in its place.
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $handler = 'file';
|
public $handler = 'file';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Backup Handler
|
* Backup Handler
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| The name of the handler that will be used in case the first one is
|
* The name of the handler that will be used in case the first one is
|
||||||
| unreachable. Often, 'file' is used here since the filesystem is
|
* unreachable. Often, 'file' is used here since the filesystem is
|
||||||
| always available, though that's not always practical for the app.
|
* always available, though that's not always practical for the app.
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $backupHandler = 'dummy';
|
public $backupHandler = 'dummy';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Cache Directory Path
|
* Cache Directory Path
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| The path to where cache files should be stored, if using a file-based
|
* The path to where cache files should be stored, if using a file-based
|
||||||
| system.
|
* system.
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*
|
||||||
|
* @deprecated Use the driver-specific variant under $file
|
||||||
|
*/
|
||||||
public $storePath = WRITEPATH . 'cache/';
|
public $storePath = WRITEPATH . 'cache/';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Cache Include Query String
|
* Cache Include Query String
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| Whether to take the URL query string into consideration when generating
|
* Whether to take the URL query string into consideration when generating
|
||||||
| output cache files. Valid options are:
|
* output cache files. Valid options are:
|
||||||
|
|
*
|
||||||
| false = Disabled
|
* false = Disabled
|
||||||
| true = Enabled, take all query parameters into account.
|
* true = Enabled, take all query parameters into account.
|
||||||
| Please be aware that this may result in numerous cache
|
* Please be aware that this may result in numerous cache
|
||||||
| files generated for the same page over and over again.
|
* files generated for the same page over and over again.
|
||||||
| array('q') = Enabled, but only take into account the specified list
|
* array('q') = Enabled, but only take into account the specified list
|
||||||
| of query parameters.
|
* of query parameters.
|
||||||
|
|
*
|
||||||
*/
|
* @var boolean|string[]
|
||||||
|
*/
|
||||||
public $cacheQueryString = false;
|
public $cacheQueryString = false;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Key Prefix
|
* Key Prefix
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| This string is added to all cache item names to help avoid collisions
|
* This string is added to all cache item names to help avoid collisions
|
||||||
| if you run multiple applications with the same cache engine.
|
* if you run multiple applications with the same cache engine.
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $prefix = '';
|
public $prefix = '';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
| -------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Memcached settings
|
* File settings
|
||||||
| -------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Your Memcached servers can be specified below, if you are using
|
* Your file storage preferences can be specified below, if you are using
|
||||||
| the Memcached drivers.
|
* the File driver.
|
||||||
|
|
*
|
||||||
| See: https://codeigniter.com/user_guide/libraries/caching.html#memcached
|
* @var array<string, string|int|null>
|
||||||
|
|
*/
|
||||||
*/
|
public $file = [
|
||||||
|
'storePath' => WRITEPATH . 'cache/',
|
||||||
|
'mode' => 0640,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* -------------------------------------------------------------------------
|
||||||
|
* Memcached settings
|
||||||
|
* -------------------------------------------------------------------------
|
||||||
|
* Your Memcached servers can be specified below, if you are using
|
||||||
|
* the Memcached drivers.
|
||||||
|
*
|
||||||
|
* @see https://codeigniter.com/user_guide/libraries/caching.html#memcached
|
||||||
|
*
|
||||||
|
* @var array<string, string|int|boolean>
|
||||||
|
*/
|
||||||
public $memcached = [
|
public $memcached = [
|
||||||
'host' => '127.0.0.1',
|
'host' => '127.0.0.1',
|
||||||
'port' => 11211,
|
'port' => 11211,
|
||||||
|
@ -86,14 +114,15 @@ class Cache extends BaseConfig
|
||||||
'raw' => false,
|
'raw' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
/**
|
||||||
| -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
| Redis settings
|
* Redis settings
|
||||||
| -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
| Your Redis server can be specified below, if you are using
|
* Your Redis server can be specified below, if you are using
|
||||||
| the Redis or Predis drivers.
|
* the Redis or Predis drivers.
|
||||||
|
|
*
|
||||||
*/
|
* @var array<string, string|int|null>
|
||||||
|
*/
|
||||||
public $redis = [
|
public $redis = [
|
||||||
'host' => '127.0.0.1',
|
'host' => '127.0.0.1',
|
||||||
'password' => null,
|
'password' => null,
|
||||||
|
@ -102,21 +131,22 @@ class Cache extends BaseConfig
|
||||||
'database' => 0,
|
'database' => 0,
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Available Cache Handlers
|
* Available Cache Handlers
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| This is an array of cache engine alias' and class names. Only engines
|
* This is an array of cache engine alias' and class names. Only engines
|
||||||
| that are listed here are allowed to be used.
|
* that are listed here are allowed to be used.
|
||||||
|
|
*
|
||||||
*/
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
public $validHandlers = [
|
public $validHandlers = [
|
||||||
'dummy' => \CodeIgniter\Cache\Handlers\DummyHandler::class,
|
'dummy' => DummyHandler::class,
|
||||||
'file' => \CodeIgniter\Cache\Handlers\FileHandler::class,
|
'file' => FileHandler::class,
|
||||||
'memcached' => \CodeIgniter\Cache\Handlers\MemcachedHandler::class,
|
'memcached' => MemcachedHandler::class,
|
||||||
'predis' => \CodeIgniter\Cache\Handlers\PredisHandler::class,
|
'predis' => PredisHandler::class,
|
||||||
'redis' => \CodeIgniter\Cache\Handlers\RedisHandler::class,
|
'redis' => RedisHandler::class,
|
||||||
'wincache' => \CodeIgniter\Cache\Handlers\WincacheHandler::class,
|
'wincache' => WincacheHandler::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,50 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
/*
|
||||||
// Castopod Version
|
| --------------------------------------------------------------------
|
||||||
//--------------------------------------------------------------------------
|
| Castopod Version
|
||||||
// The Castopod version number to display.
|
| --------------------------------------------------------------------
|
||||||
//
|
|
|
||||||
// NOTE: this constant is updated upon release with Continuous Integration.
|
| The Castopod version number to display.
|
||||||
//
|
|
|
||||||
|
| NOTE: this constant is updated upon release with Continuous Integration.
|
||||||
|
*/
|
||||||
defined('CP_VERSION') || define('CP_VERSION', '1.0.0-alpha.41');
|
defined('CP_VERSION') || define('CP_VERSION', '1.0.0-alpha.41');
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
/*
|
||||||
// App Namespace
|
| --------------------------------------------------------------------
|
||||||
//--------------------------------------------------------------------
|
| App Namespace
|
||||||
// This defines the default Namespace that is used throughout
|
| --------------------------------------------------------------------
|
||||||
// CodeIgniter to refer to the Application directory. Change
|
|
|
||||||
// this constant to change the namespace that all application
|
| This defines the default Namespace that is used throughout
|
||||||
// classes should use.
|
| CodeIgniter to refer to the Application directory. Change
|
||||||
//
|
| this constant to change the namespace that all application
|
||||||
// NOTE: changing this will require manually modifying the
|
| classes should use.
|
||||||
// existing namespaces of App\* namespaced-classes.
|
|
|
||||||
//
|
| NOTE: changing this will require manually modifying the
|
||||||
|
| existing namespaces of App\* namespaced-classes.
|
||||||
|
*/
|
||||||
defined('APP_NAMESPACE') || define('APP_NAMESPACE', 'App');
|
defined('APP_NAMESPACE') || define('APP_NAMESPACE', 'App');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
| --------------------------------------------------------------------------
|
||||||
| Composer Path
|
| Composer Path
|
||||||
|--------------------------------------------------------------------------
|
| --------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| The path that Composer's autoload file is expected to live. By default,
|
| The path that Composer's autoload file is expected to live. By default,
|
||||||
| the vendor folder is in the Root directory, but you can customize that here.
|
| the vendor folder is in the Root directory, but you can customize that here.
|
||||||
*/
|
*/
|
||||||
defined('COMPOSER_PATH') ||
|
defined('COMPOSER_PATH') ||
|
||||||
define('COMPOSER_PATH', ROOTPATH . 'vendor/autoload.php');
|
define('COMPOSER_PATH', ROOTPATH . 'vendor/autoload.php');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Timing Constants
|
| Timing Constants
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| Provide simple ways to work with the myriad of PHP functions that
|
| Provide simple ways to work with the myriad of PHP functions that
|
||||||
| require information to be in seconds.
|
| require information to be in seconds.
|
||||||
*/
|
*/
|
||||||
defined('SECOND') || define('SECOND', 1);
|
defined('SECOND') || define('SECOND', 1);
|
||||||
defined('MINUTE') || define('MINUTE', 60);
|
defined('MINUTE') || define('MINUTE', 60);
|
||||||
defined('HOUR') || define('HOUR', 3600);
|
defined('HOUR') || define('HOUR', 3600);
|
||||||
|
@ -51,30 +55,30 @@ defined('YEAR') || define('YEAR', 31536000);
|
||||||
defined('DECADE') || define('DECADE', 315360000);
|
defined('DECADE') || define('DECADE', 315360000);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
| --------------------------------------------------------------------------
|
||||||
| Exit Status Codes
|
| Exit Status Codes
|
||||||
|--------------------------------------------------------------------------
|
| --------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| Used to indicate the conditions under which the script is exit()ing.
|
| Used to indicate the conditions under which the script is exit()ing.
|
||||||
| While there is no universal standard for error codes, there are some
|
| While there is no universal standard for error codes, there are some
|
||||||
| broad conventions. Three such conventions are mentioned below, for
|
| broad conventions. Three such conventions are mentioned below, for
|
||||||
| those who wish to make use of them. The CodeIgniter defaults were
|
| those who wish to make use of them. The CodeIgniter defaults were
|
||||||
| chosen for the least overlap with these conventions, while still
|
| chosen for the least overlap with these conventions, while still
|
||||||
| leaving room for others to be defined in future versions and user
|
| leaving room for others to be defined in future versions and user
|
||||||
| applications.
|
| applications.
|
||||||
|
|
|
|
||||||
| The three main conventions used for determining exit status codes
|
| The three main conventions used for determining exit status codes
|
||||||
| are as follows:
|
| are as follows:
|
||||||
|
|
|
|
||||||
| Standard C/C++ Library (stdlibc):
|
| Standard C/C++ Library (stdlibc):
|
||||||
| http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
|
| http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
|
||||||
| (This link also contains other GNU-specific conventions)
|
| (This link also contains other GNU-specific conventions)
|
||||||
| BSD sysexits.h:
|
| BSD sysexits.h:
|
||||||
| http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
|
| http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
|
||||||
| Bash scripting:
|
| Bash scripting:
|
||||||
| http://tldp.org/LDP/abs/html/exitcodes.html
|
| http://tldp.org/LDP/abs/html/exitcodes.html
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
defined('EXIT_SUCCESS') || define('EXIT_SUCCESS', 0); // no errors
|
defined('EXIT_SUCCESS') || define('EXIT_SUCCESS', 0); // no errors
|
||||||
defined('EXIT_ERROR') || define('EXIT_ERROR', 1); // generic error
|
defined('EXIT_ERROR') || define('EXIT_ERROR', 1); // generic error
|
||||||
defined('EXIT_CONFIG') || define('EXIT_CONFIG', 3); // configuration error
|
defined('EXIT_CONFIG') || define('EXIT_CONFIG', 3); // configuration error
|
||||||
|
|
|
@ -5,45 +5,155 @@ namespace Config;
|
||||||
use CodeIgniter\Config\BaseConfig;
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ContentSecurityPolicyConfig
|
|
||||||
*
|
|
||||||
* Stores the default settings for the ContentSecurityPolicy, if you
|
* Stores the default settings for the ContentSecurityPolicy, if you
|
||||||
* choose to use it. The values here will be read in and set as defaults
|
* choose to use it. The values here will be read in and set as defaults
|
||||||
* for the site. If needed, they can be overridden on a page-by-page basis.
|
* for the site. If needed, they can be overridden on a page-by-page basis.
|
||||||
*
|
*
|
||||||
* Suggested reference for explanations:
|
* Suggested reference for explanations:
|
||||||
* https://www.html5rocks.com/en/tutorials/security/content-security-policy/
|
|
||||||
*
|
*
|
||||||
* @package Config
|
* @see https://www.html5rocks.com/en/tutorials/security/content-security-policy/
|
||||||
*/
|
*/
|
||||||
class ContentSecurityPolicy extends BaseConfig
|
class ContentSecurityPolicy extends BaseConfig
|
||||||
{
|
{
|
||||||
// broadbrush CSP management
|
//-------------------------------------------------------------------------
|
||||||
|
// Broadbrush CSP management
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
public $reportOnly = false; // default CSP report context
|
/**
|
||||||
public $reportURI = null; // URL to send violation reports to
|
* Default CSP report context
|
||||||
public $upgradeInsecureRequests = false; // toggle for forcing https
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $reportOnly = false;
|
||||||
|
|
||||||
// sources allowed; string or array of strings
|
/**
|
||||||
|
* Specifies a URL where a browser will send reports
|
||||||
|
* when a content security policy is violated.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $reportURI = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructs user agents to rewrite URL schemes, changing
|
||||||
|
* HTTP to HTTPS. This directive is for websites with
|
||||||
|
* large numbers of old URLs that need to be rewritten.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $upgradeInsecureRequests = false;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
// Sources allowed
|
||||||
// Note: once you set a policy to 'none', it cannot be further restricted
|
// Note: once you set a policy to 'none', it cannot be further restricted
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
|
||||||
public $defaultSrc = null; // will default to self if not over-ridden
|
/**
|
||||||
|
* Will default to self if not overridden
|
||||||
|
*
|
||||||
|
* @var string|string[]|null
|
||||||
|
*/
|
||||||
|
public $defaultSrc = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists allowed scripts' URLs.
|
||||||
|
*
|
||||||
|
* @var string|string[]
|
||||||
|
*/
|
||||||
public $scriptSrc = 'self';
|
public $scriptSrc = 'self';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists allowed stylesheets' URLs.
|
||||||
|
*
|
||||||
|
* @var string|string[]
|
||||||
|
*/
|
||||||
public $styleSrc = 'self';
|
public $styleSrc = 'self';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the origins from which images can be loaded.
|
||||||
|
*
|
||||||
|
* @var string|string[]
|
||||||
|
*/
|
||||||
public $imageSrc = 'self';
|
public $imageSrc = 'self';
|
||||||
public $baseURI = null; // will default to self if not over-ridden
|
|
||||||
|
/**
|
||||||
|
* Restricts the URLs that can appear in a page's `<base>` element.
|
||||||
|
*
|
||||||
|
* Will default to self if not overridden
|
||||||
|
*
|
||||||
|
* @var string|string[]|null
|
||||||
|
*/
|
||||||
|
public $baseURI = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists the URLs for workers and embedded frame contents
|
||||||
|
*
|
||||||
|
* @var string|string[]
|
||||||
|
*/
|
||||||
public $childSrc = 'self';
|
public $childSrc = 'self';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limits the origins that you can connect to (via XHR,
|
||||||
|
* WebSockets, and EventSource).
|
||||||
|
*
|
||||||
|
* @var string|string[]
|
||||||
|
*/
|
||||||
public $connectSrc = 'self';
|
public $connectSrc = 'self';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the origins that can serve web fonts.
|
||||||
|
*
|
||||||
|
* @var string|string[]
|
||||||
|
*/
|
||||||
public $fontSrc = null;
|
public $fontSrc = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists valid endpoints for submission from `<form>` tags.
|
||||||
|
*
|
||||||
|
* @var string|string[]
|
||||||
|
*/
|
||||||
public $formAction = 'self';
|
public $formAction = 'self';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the sources that can embed the current page.
|
||||||
|
* This directive applies to `<frame>`, `<iframe>`, `<embed>`,
|
||||||
|
* and `<applet>` tags. This directive can't be used in
|
||||||
|
* `<meta>` tags and applies only to non-HTML resources.
|
||||||
|
*
|
||||||
|
* @var string|string[]|null
|
||||||
|
*/
|
||||||
public $frameAncestors = null;
|
public $frameAncestors = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restricts the origins allowed to deliver video and audio.
|
||||||
|
*
|
||||||
|
* @var string|string[]|null
|
||||||
|
*/
|
||||||
public $mediaSrc = null;
|
public $mediaSrc = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows control over Flash and other plugins.
|
||||||
|
*
|
||||||
|
* @var string|string[]
|
||||||
|
*/
|
||||||
public $objectSrc = 'self';
|
public $objectSrc = 'self';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|string[]|null
|
||||||
|
*/
|
||||||
public $manifestSrc = null;
|
public $manifestSrc = null;
|
||||||
|
|
||||||
// mime types allowed; string or array of strings
|
/**
|
||||||
|
* Limits the kinds of plugins a page may invoke.
|
||||||
|
*
|
||||||
|
* @var string|string[]|null
|
||||||
|
*/
|
||||||
public $pluginTypes = null;
|
public $pluginTypes = null;
|
||||||
|
|
||||||
// list of actions allowed; string or array of strings
|
/**
|
||||||
|
* List of actions allowed.
|
||||||
|
*
|
||||||
|
* @var string|string[]|null
|
||||||
|
*/
|
||||||
public $sandbox = null;
|
public $sandbox = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database Configuration
|
* Database Configuration
|
||||||
*
|
|
||||||
* @package Config
|
|
||||||
*/
|
*/
|
||||||
|
class Database extends Config
|
||||||
class Database extends \CodeIgniter\Database\Config
|
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The directory that holds the Migrations
|
* The directory that holds the Migrations
|
||||||
|
@ -16,7 +15,7 @@ class Database extends \CodeIgniter\Database\Config
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $filesPath = APPPATH . 'Database/';
|
public $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lets you choose which connection group to
|
* Lets you choose which connection group to
|
||||||
|
@ -41,10 +40,8 @@ class Database extends \CodeIgniter\Database\Config
|
||||||
'DBPrefix' => 'cp_',
|
'DBPrefix' => 'cp_',
|
||||||
'pConnect' => false,
|
'pConnect' => false,
|
||||||
'DBDebug' => ENVIRONMENT !== 'production',
|
'DBDebug' => ENVIRONMENT !== 'production',
|
||||||
'cacheOn' => false,
|
'charset' => 'utf8mb4',
|
||||||
'cacheDir' => '',
|
'DBCollat' => 'utf8mb4_unicode_ci',
|
||||||
'charset' => 'utf8',
|
|
||||||
'DBCollat' => 'utf8_general_ci',
|
|
||||||
'swapPre' => '',
|
'swapPre' => '',
|
||||||
'encrypt' => false,
|
'encrypt' => false,
|
||||||
'compress' => false,
|
'compress' => false,
|
||||||
|
@ -69,8 +66,6 @@ class Database extends \CodeIgniter\Database\Config
|
||||||
'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
|
'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
|
||||||
'pConnect' => false,
|
'pConnect' => false,
|
||||||
'DBDebug' => ENVIRONMENT !== 'production',
|
'DBDebug' => ENVIRONMENT !== 'production',
|
||||||
'cacheOn' => false,
|
|
||||||
'cacheDir' => '',
|
|
||||||
'charset' => 'utf8',
|
'charset' => 'utf8',
|
||||||
'DBCollat' => 'utf8_general_ci',
|
'DBCollat' => 'utf8_general_ci',
|
||||||
'swapPre' => '',
|
'swapPre' => '',
|
||||||
|
@ -92,21 +87,6 @@ class Database extends \CodeIgniter\Database\Config
|
||||||
// we don't overwrite live data on accident.
|
// we don't overwrite live data on accident.
|
||||||
if (ENVIRONMENT === 'testing') {
|
if (ENVIRONMENT === 'testing') {
|
||||||
$this->defaultGroup = 'tests';
|
$this->defaultGroup = 'tests';
|
||||||
|
|
||||||
// Under Travis-CI, we can set an ENV var named 'DB_GROUP'
|
|
||||||
// so that we can test against multiple databases.
|
|
||||||
if ($group = getenv('DB')) {
|
|
||||||
if (is_file(TESTPATH . 'travis/Database.php')) {
|
|
||||||
require TESTPATH . 'travis/Database.php';
|
|
||||||
|
|
||||||
if (
|
|
||||||
!empty($dbconfig) &&
|
|
||||||
array_key_exists($group, $dbconfig)
|
|
||||||
) {
|
|
||||||
$this->tests = $dbconfig[$group];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
/**
|
|
||||||
* DocTypes
|
|
||||||
*
|
|
||||||
* @package Config
|
|
||||||
*/
|
|
||||||
|
|
||||||
class DocTypes
|
class DocTypes
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* List of valid document types.
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
public $list = [
|
public $list = [
|
||||||
'xhtml11' =>
|
'xhtml11' =>
|
||||||
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
|
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
|
||||||
|
|
|
@ -12,25 +12,56 @@ use CodeIgniter\Config\BaseConfig;
|
||||||
*/
|
*/
|
||||||
class Encryption extends BaseConfig
|
class Encryption extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Encryption Key Starter
|
* Encryption Key Starter
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| If you use the Encryption class you must set an encryption key (seed).
|
* If you use the Encryption class you must set an encryption key (seed).
|
||||||
| You need to ensure it is long enough for the cipher and mode you plan to use.
|
* You need to ensure it is long enough for the cipher and mode you plan to use.
|
||||||
| See the user guide for more info.
|
* See the user guide for more info.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public $key = '';
|
public $key = '';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Encryption driver to use
|
* Encryption Driver to Use
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| One of the supported drivers, eg 'OpenSSL' or 'Sodium'.
|
* One of the supported encryption drivers.
|
||||||
| The default driver, if you don't specify one, is 'OpenSSL'.
|
*
|
||||||
|
* Available drivers:
|
||||||
|
* - OpenSSL
|
||||||
|
* - Sodium
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $driver = 'OpenSSL';
|
public $driver = 'OpenSSL';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* SodiumHandler's Padding Length in Bytes
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* This is the number of bytes that will be padded to the plaintext message
|
||||||
|
* before it is encrypted. This value should be greater than zero.
|
||||||
|
*
|
||||||
|
* See the user guide for more information on padding.
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
public $blockSize = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Encryption digest
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* HMAC digest to use, e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $digest = 'SHA512';
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
use CodeIgniter\Events\Events;
|
use CodeIgniter\Events\Events;
|
||||||
|
use CodeIgniter\Exceptions\FrameworkException;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
|
@ -23,11 +24,15 @@ use CodeIgniter\Events\Events;
|
||||||
|
|
||||||
Events::on('pre_system', function () {
|
Events::on('pre_system', function () {
|
||||||
if (ENVIRONMENT !== 'testing') {
|
if (ENVIRONMENT !== 'testing') {
|
||||||
while (\ob_get_level() > 0) {
|
if (ini_get('zlib.output_compression')) {
|
||||||
\ob_end_flush();
|
throw FrameworkException::forEnabledZlibOutputCompression();
|
||||||
}
|
}
|
||||||
|
|
||||||
\ob_start(function ($buffer) {
|
while (ob_get_level() > 0) {
|
||||||
|
ob_end_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
ob_start(function ($buffer) {
|
||||||
return $buffer;
|
return $buffer;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -38,11 +43,98 @@ Events::on('pre_system', function () {
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
* If you delete, they will no longer be collected.
|
* If you delete, they will no longer be collected.
|
||||||
*/
|
*/
|
||||||
if (ENVIRONMENT !== 'production') {
|
if (CI_DEBUG) {
|
||||||
Events::on(
|
Events::on(
|
||||||
'DBQuery',
|
'DBQuery',
|
||||||
'CodeIgniter\Debug\Toolbar\Collectors\Database::collect'
|
'CodeIgniter\Debug\Toolbar\Collectors\Database::collect',
|
||||||
);
|
);
|
||||||
Services::toolbar()->respond();
|
Services::toolbar()->respond();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Events::on('login', function ($user) {
|
||||||
|
helper('auth');
|
||||||
|
|
||||||
|
// set interact_as_actor_id value
|
||||||
|
$userPodcasts = $user->podcasts;
|
||||||
|
if ($userPodcasts = $user->podcasts) {
|
||||||
|
set_interact_as_actor($userPodcasts[0]->id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events::on('logout', function ($user) {
|
||||||
|
helper('auth');
|
||||||
|
|
||||||
|
// remove user's interact_as_actor session
|
||||||
|
remove_interact_as_actor($user->id);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* ActivityPub events
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* Update episode metadata counts
|
||||||
|
*/
|
||||||
|
Events::on('on_note_add', function ($note) {
|
||||||
|
if ($note->episode_id) {
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $note->episode_id)
|
||||||
|
->increment('notes_total');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events::on('on_note_remove', function ($note) {
|
||||||
|
if ($note->episode_id) {
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $note->episode_id)
|
||||||
|
->decrement('notes_total', 1 + $note->reblogs_count);
|
||||||
|
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $note->episode_id)
|
||||||
|
->decrement('reblogs_total', $note->reblogs_count);
|
||||||
|
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $note->episode_id)
|
||||||
|
->decrement('favourites_total', $note->favourites_count);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events::on('on_note_reblog', function ($actor, $note) {
|
||||||
|
if ($episodeId = $note->episode_id) {
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $episodeId)
|
||||||
|
->increment('reblogs_total');
|
||||||
|
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $episodeId)
|
||||||
|
->increment('notes_total');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events::on('on_note_undo_reblog', function ($reblogNote) {
|
||||||
|
if ($episodeId = $reblogNote->reblog_of_note->episode_id) {
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $episodeId)
|
||||||
|
->decrement('reblogs_total');
|
||||||
|
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $episodeId)
|
||||||
|
->decrement('notes_total');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events::on('on_note_favourite', function ($actor, $note) {
|
||||||
|
if ($note->episode_id) {
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $note->episode_id)
|
||||||
|
->increment('favourites_total');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events::on('on_note_undo_favourite', function ($actor, $note) {
|
||||||
|
if ($note->episode_id) {
|
||||||
|
model('EpisodeModel')
|
||||||
|
->where('id', $note->episode_id)
|
||||||
|
->decrement('favourites_total');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -2,42 +2,47 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup how the exception handler works.
|
* Setup how the exception handler works.
|
||||||
*
|
|
||||||
* @package Config
|
|
||||||
*/
|
*/
|
||||||
|
class Exceptions extends BaseConfig
|
||||||
class Exceptions
|
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| LOG EXCEPTIONS?
|
* LOG EXCEPTIONS?
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| If true, then exceptions will be logged
|
* If true, then exceptions will be logged
|
||||||
| through Services::Log.
|
* through Services::Log.
|
||||||
|
|
*
|
||||||
| Default: true
|
* Default: true
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
public $log = true;
|
public $log = true;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| DO NOT LOG STATUS CODES
|
* DO NOT LOG STATUS CODES
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Any status codes here will NOT be logged if logging is turned on.
|
* Any status codes here will NOT be logged if logging is turned on.
|
||||||
| By default, only 404 (Page Not Found) exceptions are ignored.
|
* By default, only 404 (Page Not Found) exceptions are ignored.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
*/
|
*/
|
||||||
public $ignoreCodes = [404];
|
public $ignoreCodes = [404];
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Error Views Path
|
* Error Views Path
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| This is the path to the directory that contains the 'cli' and 'html'
|
* This is the path to the directory that contains the 'cli' and 'html'
|
||||||
| directories that hold the views used to generate errors.
|
* directories that hold the views used to generate errors.
|
||||||
|
|
*
|
||||||
| Default: APPPATH.'Views/errors'
|
* Default: APPPATH.'Views/errors'
|
||||||
*/
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $errorViewPath = APPPATH . 'Views/errors';
|
public $errorViewPath = APPPATH . 'Views/errors';
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,40 +3,65 @@
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
use CodeIgniter\Config\BaseConfig;
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
use CodeIgniter\Filters\CSRF;
|
||||||
|
use CodeIgniter\Filters\DebugToolbar;
|
||||||
|
use CodeIgniter\Filters\Honeypot;
|
||||||
|
|
||||||
class Filters extends BaseConfig
|
class Filters extends BaseConfig
|
||||||
{
|
{
|
||||||
// Makes reading things below nicer,
|
/**
|
||||||
// and simpler to change out script that's used.
|
* Configures aliases for Filter classes to
|
||||||
|
* make reading things nicer and simpler.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
public $aliases = [
|
public $aliases = [
|
||||||
'csrf' => \CodeIgniter\Filters\CSRF::class,
|
'csrf' => CSRF::class,
|
||||||
'toolbar' => \CodeIgniter\Filters\DebugToolbar::class,
|
'toolbar' => DebugToolbar::class,
|
||||||
'honeypot' => \CodeIgniter\Filters\Honeypot::class,
|
'honeypot' => Honeypot::class,
|
||||||
'login' => \Myth\Auth\Filters\LoginFilter::class,
|
'login' => \Myth\Auth\Filters\LoginFilter::class,
|
||||||
'role' => \Myth\Auth\Filters\RoleFilter::class,
|
'role' => \Myth\Auth\Filters\RoleFilter::class,
|
||||||
'permission' => \App\Filters\Permission::class,
|
'permission' => \App\Filters\PermissionFilter::class,
|
||||||
|
'activity-pub' => \ActivityPub\Filters\ActivityPubFilter::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
// Always applied before every request
|
/**
|
||||||
|
* List of filter aliases that are always
|
||||||
|
* applied before and after every request.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
public $globals = [
|
public $globals = [
|
||||||
'before' => [
|
'before' => [
|
||||||
//'honeypot'
|
// 'honeypot',
|
||||||
// 'csrf',
|
// 'csrf',
|
||||||
],
|
],
|
||||||
'after' => [
|
'after' => [
|
||||||
'toolbar',
|
'toolbar',
|
||||||
//'honeypot'
|
// 'honeypot',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
// Works on all of a particular HTTP method
|
/**
|
||||||
// (GET, POST, etc) as BEFORE filters only
|
* List of filter aliases that works on a
|
||||||
// like: 'post' => ['CSRF', 'throttle'],
|
* particular HTTP method (GET, POST, etc.).
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* 'post' => ['csrf', 'throttle']
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
public $methods = [];
|
public $methods = [];
|
||||||
|
|
||||||
// List filter aliases and any before/after uri patterns
|
/**
|
||||||
// that they should run on, like:
|
* List of filter aliases that should run on any
|
||||||
// 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']],
|
* before or after URI patterns.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
public $filters = [];
|
public $filters = [];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
class ForeignCharacters extends \CodeIgniter\Config\ForeignCharacters
|
use CodeIgniter\Config\ForeignCharacters as BaseForeignCharacters;
|
||||||
|
|
||||||
|
class ForeignCharacters extends BaseForeignCharacters
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,43 +3,62 @@
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
use CodeIgniter\Config\BaseConfig;
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
use CodeIgniter\Format\FormatterInterface;
|
||||||
|
|
||||||
class Format extends BaseConfig
|
class Format extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Available Response Formats
|
* Available Response Formats
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| When you perform content negotiation with the request, these are the
|
* When you perform content negotiation with the request, these are the
|
||||||
| available formats that your application supports. This is currently
|
* available formats that your application supports. This is currently
|
||||||
| only used with the API\ResponseTrait. A valid Formatter must exist
|
* only used with the API\ResponseTrait. A valid Formatter must exist
|
||||||
| for the specified format.
|
* for the specified format.
|
||||||
|
|
*
|
||||||
| These formats are only checked when the data passed to the respond()
|
* These formats are only checked when the data passed to the respond()
|
||||||
| method is an array.
|
* method is an array.
|
||||||
|
|
*
|
||||||
*/
|
* @var string[]
|
||||||
|
*/
|
||||||
public $supportedResponseFormats = [
|
public $supportedResponseFormats = [
|
||||||
'application/json',
|
'application/json',
|
||||||
'application/xml', // machine-readable XML
|
'application/xml', // machine-readable XML
|
||||||
'text/xml', // human-readable XML
|
'text/xml', // human-readable XML
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Formatters
|
* Formatters
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| Lists the class to use to format responses with of a particular type.
|
* Lists the class to use to format responses with of a particular type.
|
||||||
| For each mime type, list the class that should be used. Formatters
|
* For each mime type, list the class that should be used. Formatters
|
||||||
| can be retrieved through the getFormatter() method.
|
* can be retrieved through the getFormatter() method.
|
||||||
|
|
*
|
||||||
*/
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
public $formatters = [
|
public $formatters = [
|
||||||
'application/json' => \CodeIgniter\Format\JSONFormatter::class,
|
'application/json' => 'CodeIgniter\Format\JSONFormatter',
|
||||||
'application/xml' => \CodeIgniter\Format\XMLFormatter::class,
|
'application/xml' => 'CodeIgniter\Format\XMLFormatter',
|
||||||
'text/xml' => \CodeIgniter\Format\XMLFormatter::class,
|
'text/xml' => 'CodeIgniter\Format\XMLFormatter',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Formatters Options
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Additional Options to adjust default formatters behaviour.
|
||||||
|
* For each mime type, list the additional options that should be used.
|
||||||
|
*
|
||||||
|
* @var array<string, int>
|
||||||
|
*/
|
||||||
|
public $formatterOptions = [
|
||||||
|
'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
|
||||||
|
'application/xml' => 0,
|
||||||
|
'text/xml' => 0,
|
||||||
];
|
];
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
@ -49,26 +68,12 @@ class Format extends BaseConfig
|
||||||
*
|
*
|
||||||
* @param string $mime
|
* @param string $mime
|
||||||
*
|
*
|
||||||
* @return \CodeIgniter\Format\FormatterInterface
|
* @return FormatterInterface
|
||||||
|
*
|
||||||
|
* @deprecated This is an alias of `\CodeIgniter\Format\Format::getFormatter`. Use that instead.
|
||||||
*/
|
*/
|
||||||
public function getFormatter(string $mime)
|
public function getFormatter(string $mime)
|
||||||
{
|
{
|
||||||
if (!array_key_exists($mime, $this->formatters)) {
|
return Services::format()->getFormatter($mime);
|
||||||
throw new \InvalidArgumentException(
|
|
||||||
'No Formatter defined for mime type: ' . $mime
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$class = $this->formatters[$mime];
|
|
||||||
|
|
||||||
if (!class_exists($class)) {
|
|
||||||
throw new \BadMethodCallException(
|
|
||||||
$class . ' is not a valid Formatter.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new $class();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Config;
|
||||||
|
|
||||||
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
|
class Generators extends BaseConfig
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Generator Commands' Views
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* This array defines the mapping of generator commands to the view files
|
||||||
|
* they are using. If you need to customize them for your own, copy these
|
||||||
|
* view files in your own folder and indicate the location here.
|
||||||
|
*
|
||||||
|
* You will notice that the views have special placeholders enclosed in
|
||||||
|
* curly braces `{...}`. These placeholders are used internally by the
|
||||||
|
* generator commands in processing replacements, thus you are warned
|
||||||
|
* not to delete them or modify the names. If you will do so, you may
|
||||||
|
* end up disrupting the scaffolding process and throw errors.
|
||||||
|
*
|
||||||
|
* YOU HAVE BEEN WARNED!
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
public $views = [
|
||||||
|
'make:command' =>
|
||||||
|
'CodeIgniter\Commands\Generators\Views\command.tpl.php',
|
||||||
|
'make:controller' =>
|
||||||
|
'CodeIgniter\Commands\Generators\Views\controller.tpl.php',
|
||||||
|
'make:entity' => 'CodeIgniter\Commands\Generators\Views\entity.tpl.php',
|
||||||
|
'make:filter' => 'CodeIgniter\Commands\Generators\Views\filter.tpl.php',
|
||||||
|
'make:migration' =>
|
||||||
|
'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
|
||||||
|
'make:model' => 'CodeIgniter\Commands\Generators\Views\model.tpl.php',
|
||||||
|
'make:seeder' => 'CodeIgniter\Commands\Generators\Views\seeder.tpl.php',
|
||||||
|
'make:validation' =>
|
||||||
|
'CodeIgniter\Commands\Generators\Views\validation.tpl.php',
|
||||||
|
'session:migration' =>
|
||||||
|
'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
|
||||||
|
];
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ class Honeypot extends BaseConfig
|
||||||
* @var boolean
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
public $hidden = true;
|
public $hidden = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Honeypot Label Content
|
* Honeypot Label Content
|
||||||
*
|
*
|
||||||
|
@ -32,4 +33,11 @@ class Honeypot extends BaseConfig
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $template = '<label>{label}</label><input type="text" name="{name}" value=""/>';
|
public $template = '<label>{label}</label><input type="text" name="{name}" value=""/>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Honeypot container
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $container = '<div style="display:none">{template}</div>';
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
use CodeIgniter\Config\BaseConfig;
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
use CodeIgniter\Images\Handlers\GDHandler;
|
||||||
|
use CodeIgniter\Images\Handlers\ImageMagickHandler;
|
||||||
|
|
||||||
class Images extends BaseConfig
|
class Images extends BaseConfig
|
||||||
{
|
{
|
||||||
|
@ -24,20 +26,20 @@ class Images extends BaseConfig
|
||||||
/**
|
/**
|
||||||
* The available handler classes.
|
* The available handler classes.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
public $handlers = [
|
public $handlers = [
|
||||||
'gd' => \CodeIgniter\Images\Handlers\GDHandler::class,
|
'gd' => GDHandler::class,
|
||||||
'imagick' => \CodeIgniter\Images\Handlers\ImageMagickHandler::class,
|
'imagick' => ImageMagickHandler::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* --------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
* Uploaded images resizing sizes (in px)
|
| Uploaded images resizing sizes (in px)
|
||||||
* --------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
* The sizes listed below determine the resizing of images when uploaded.
|
| The sizes listed below determine the resizing of images when uploaded.
|
||||||
* All uploaded images are of 1:1 ratio (width and height are the same).
|
| All uploaded images are of 1:1 ratio (width and height are the same).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var integer
|
* @var integer
|
||||||
|
@ -68,12 +70,12 @@ class Images extends BaseConfig
|
||||||
*/
|
*/
|
||||||
public $id3Size = 500;
|
public $id3Size = 500;
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* --------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
* Uploaded images naming extensions
|
| Uploaded images naming extensions
|
||||||
* --------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
* The properties listed below set the name extensions for the resized images
|
| The properties listed below set the name extensions for the resized images
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
|
|
|
@ -5,26 +5,23 @@ namespace Config;
|
||||||
use CodeIgniter\Config\BaseConfig;
|
use CodeIgniter\Config\BaseConfig;
|
||||||
use Kint\Renderer\Renderer;
|
use Kint\Renderer\Renderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Kint
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* We use Kint's `RichRenderer` and `CLIRenderer`. This area contains options
|
||||||
|
* that you can set to customize how Kint works for you.
|
||||||
|
*
|
||||||
|
* @see https://kint-php.github.io/kint/ for details on these settings.
|
||||||
|
*/
|
||||||
class Kint extends BaseConfig
|
class Kint extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Kint
|
| Global Settings
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
*/
|
||||||
| We use Kint's RichRenderer and CLIRenderer. This area contains options
|
|
||||||
| that you can set to customize how Kint works for you.
|
|
||||||
|
|
|
||||||
| For details on these settings, see Kint's docs:
|
|
||||||
| https://kint-php.github.io/kint/
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Global Settings
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
public $plugins = null;
|
public $plugins = null;
|
||||||
|
|
||||||
|
@ -35,10 +32,10 @@ class Kint extends BaseConfig
|
||||||
public $expanded = false;
|
public $expanded = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| RichRenderer Settings
|
| RichRenderer Settings
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
public $richTheme = 'aante-light.css';
|
public $richTheme = 'aante-light.css';
|
||||||
|
|
||||||
public $richFolder = false;
|
public $richFolder = false;
|
||||||
|
@ -50,10 +47,10 @@ class Kint extends BaseConfig
|
||||||
public $richTabPlugins = null;
|
public $richTabPlugins = null;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| CLI Settings
|
| CLI Settings
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
public $cliColors = true;
|
public $cliColors = true;
|
||||||
|
|
||||||
public $cliForceUTF8 = false;
|
public $cliForceUTF8 = false;
|
||||||
|
|
|
@ -6,76 +6,82 @@ use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
class Logger extends BaseConfig
|
class Logger extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Error Logging Threshold
|
* Error Logging Threshold
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| You can enable error logging by setting a threshold over zero. The
|
* You can enable error logging by setting a threshold over zero. The
|
||||||
| threshold determines what gets logged. Any values below or equal to the
|
* threshold determines what gets logged. Any values below or equal to the
|
||||||
| threshold will be logged. Threshold options are:
|
* threshold will be logged.
|
||||||
|
|
*
|
||||||
| 0 = Disables logging, Error logging TURNED OFF
|
* Threshold options are:
|
||||||
| 1 = Emergency Messages - System is unusable
|
*
|
||||||
| 2 = Alert Messages - Action Must Be Taken Immediately
|
* - 0 = Disables logging, Error logging TURNED OFF
|
||||||
| 3 = Critical Messages - Application component unavailable, unexpected exception.
|
* - 1 = Emergency Messages - System is unusable
|
||||||
| 4 = Runtime Errors - Don't need immediate action, but should be monitored.
|
* - 2 = Alert Messages - Action Must Be Taken Immediately
|
||||||
| 5 = Warnings - Exceptional occurrences that are not errors.
|
* - 3 = Critical Messages - Application component unavailable, unexpected exception.
|
||||||
| 6 = Notices - Normal but significant events.
|
* - 4 = Runtime Errors - Don't need immediate action, but should be monitored.
|
||||||
| 7 = Info - Interesting events, like user logging in, etc.
|
* - 5 = Warnings - Exceptional occurrences that are not errors.
|
||||||
| 8 = Debug - Detailed debug information.
|
* - 6 = Notices - Normal but significant events.
|
||||||
| 9 = All Messages
|
* - 7 = Info - Interesting events, like user logging in, etc.
|
||||||
|
|
* - 8 = Debug - Detailed debug information.
|
||||||
| You can also pass an array with threshold levels to show individual error types
|
* - 9 = All Messages
|
||||||
|
|
*
|
||||||
| array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages
|
* You can also pass an array with threshold levels to show individual error types
|
||||||
|
|
*
|
||||||
| For a live site you'll usually enable Critical or higher (3) to be logged otherwise
|
* array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages
|
||||||
| your log files will fill up very fast.
|
*
|
||||||
|
|
* For a live site you'll usually enable Critical or higher (3) to be logged otherwise
|
||||||
*/
|
* your log files will fill up very fast.
|
||||||
public $threshold = 3;
|
*
|
||||||
|
* @var integer|array
|
||||||
|
*/
|
||||||
|
public $threshold = 4;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Date Format for Logs
|
* Date Format for Logs
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| Each item that is logged has an associated date. You can use PHP date
|
* Each item that is logged has an associated date. You can use PHP date
|
||||||
| codes to set your own date formatting
|
* codes to set your own date formatting
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $dateFormat = 'Y-m-d H:i:s';
|
public $dateFormat = 'Y-m-d H:i:s';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Log Handlers
|
* Log Handlers
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| The logging system supports multiple actions to be taken when something
|
* The logging system supports multiple actions to be taken when something
|
||||||
| is logged. This is done by allowing for multiple Handlers, special classes
|
* is logged. This is done by allowing for multiple Handlers, special classes
|
||||||
| designed to write the log to their chosen destinations, whether that is
|
* designed to write the log to their chosen destinations, whether that is
|
||||||
| a file on the getServer, a cloud-based service, or even taking actions such
|
* a file on the getServer, a cloud-based service, or even taking actions such
|
||||||
| as emailing the dev team.
|
* as emailing the dev team.
|
||||||
|
|
*
|
||||||
| Each handler is defined by the class name used for that handler, and it
|
* Each handler is defined by the class name used for that handler, and it
|
||||||
| MUST implement the CodeIgniter\Log\Handlers\HandlerInterface interface.
|
* MUST implement the `CodeIgniter\Log\Handlers\HandlerInterface` interface.
|
||||||
|
|
*
|
||||||
| The value of each key is an array of configuration items that are sent
|
* The value of each key is an array of configuration items that are sent
|
||||||
| to the constructor of each handler. The only required configuration item
|
* to the constructor of each handler. The only required configuration item
|
||||||
| is the 'handles' element, which must be an array of integer log levels.
|
* is the 'handles' element, which must be an array of integer log levels.
|
||||||
| This is most easily handled by using the constants defined in the
|
* This is most easily handled by using the constants defined in the
|
||||||
| Psr\Log\LogLevel class.
|
* `Psr\Log\LogLevel` class.
|
||||||
|
|
*
|
||||||
| Handlers are executed in the order defined in this array, starting with
|
* Handlers are executed in the order defined in this array, starting with
|
||||||
| the handler on top and continuing down.
|
* the handler on top and continuing down.
|
||||||
|
|
*
|
||||||
*/
|
* @var array
|
||||||
|
*/
|
||||||
public $handlers = [
|
public $handlers = [
|
||||||
//--------------------------------------------------------------------
|
/*
|
||||||
// File Handler
|
* --------------------------------------------------------------------
|
||||||
//--------------------------------------------------------------------
|
* File Handler
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
'CodeIgniter\Log\Handlers\FileHandler' => [
|
'CodeIgniter\Log\Handlers\FileHandler' => [
|
||||||
/*
|
/*
|
||||||
* The log levels that this handler will handle.
|
* The log levels that this handler will handle.
|
||||||
|
|
|
@ -6,46 +6,50 @@ use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
class Migrations extends BaseConfig
|
class Migrations extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Enable/Disable Migrations
|
* Enable/Disable Migrations
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| Migrations are enabled by default for security reasons.
|
* Migrations are enabled by default.
|
||||||
| You should enable migrations whenever you intend to do a schema migration
|
*
|
||||||
| and disable it back when you're done.
|
* You should enable migrations whenever you intend to do a schema migration
|
||||||
|
|
* and disable it back when you're done.
|
||||||
*/
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
public $enabled = true;
|
public $enabled = true;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Migrations table
|
* Migrations Table
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| This is the name of the table that will store the current migrations state.
|
* This is the name of the table that will store the current migrations state.
|
||||||
| When migrations runs it will store in a database table which migration
|
* When migrations runs it will store in a database table which migration
|
||||||
| level the system is at. It then compares the migration level in this
|
* level the system is at. It then compares the migration level in this
|
||||||
| table to the $config['migration_version'] if they are not the same it
|
* table to the $config['migration_version'] if they are not the same it
|
||||||
| will migrate up. This must be set.
|
* will migrate up. This must be set.
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $table = 'migrations';
|
public $table = 'migrations';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Timestamp Format
|
* Timestamp Format
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| This is the format that will be used when creating new migrations
|
* This is the format that will be used when creating new migrations
|
||||||
| using the cli command:
|
* using the CLI command:
|
||||||
| > php spark migrate:create
|
* > php spark migrate:create
|
||||||
|
|
*
|
||||||
| Typical formats:
|
* Typical formats:
|
||||||
| YmdHis_
|
* - YmdHis_
|
||||||
| Y-m-d-His_
|
* - Y-m-d-His_
|
||||||
| Y_m_d_His_
|
* - Y_m_d_His_
|
||||||
|
|
*
|
||||||
*/
|
* @var string
|
||||||
|
*/
|
||||||
public $timestampFormat = 'Y-m-d-His_';
|
public $timestampFormat = 'Y-m-d-His_';
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,21 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
| -------------------------------------------------------------------
|
* Mimes
|
||||||
| MIME TYPES
|
*
|
||||||
| -------------------------------------------------------------------
|
* This file contains an array of mime types. It is used by the
|
||||||
| This file contains an array of mime types. It is used by the
|
* Upload class to help identify allowed file types.
|
||||||
| Upload class to help identify allowed file types.
|
*
|
||||||
|
|
* When more than one variation for an extension exist (like jpg, jpeg, etc)
|
||||||
| When more than one variation for an extension exist (like jpg, jpeg, etc)
|
* the most common one should be first in the array to aid the guess*
|
||||||
| the most common one should be first in the array to aid the guess*
|
* methods. The same applies when more than one mime-type exists for a
|
||||||
| methods. The same applies when more than one mime-type exists for a
|
* single extension.
|
||||||
| single extension.
|
*
|
||||||
|
|
* When working with mime types, please make sure you have the ´fileinfo´
|
||||||
*/
|
* extension enabled to reliably detect the media types.
|
||||||
|
*/
|
||||||
|
|
||||||
class Mimes
|
class Mimes
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -34,7 +36,6 @@ class Mimes
|
||||||
'text/csv',
|
'text/csv',
|
||||||
'text/x-comma-separated-values',
|
'text/x-comma-separated-values',
|
||||||
'text/comma-separated-values',
|
'text/comma-separated-values',
|
||||||
'application/octet-stream',
|
|
||||||
'application/vnd.ms-excel',
|
'application/vnd.ms-excel',
|
||||||
'application/x-csv',
|
'application/x-csv',
|
||||||
'text/x-csv',
|
'text/x-csv',
|
||||||
|
@ -64,7 +65,6 @@ class Mimes
|
||||||
'application/pdf',
|
'application/pdf',
|
||||||
'application/force-download',
|
'application/force-download',
|
||||||
'application/x-download',
|
'application/x-download',
|
||||||
'binary/octet-stream',
|
|
||||||
],
|
],
|
||||||
'ai' => ['application/pdf', 'application/postscript'],
|
'ai' => ['application/pdf', 'application/postscript'],
|
||||||
'eps' => 'application/postscript',
|
'eps' => 'application/postscript',
|
||||||
|
@ -134,6 +134,7 @@ class Mimes
|
||||||
'multipart/x-zip',
|
'multipart/x-zip',
|
||||||
],
|
],
|
||||||
'rar' => [
|
'rar' => [
|
||||||
|
'application/vnd.rar',
|
||||||
'application/x-rar',
|
'application/x-rar',
|
||||||
'application/rar',
|
'application/rar',
|
||||||
'application/x-rar-compressed',
|
'application/x-rar-compressed',
|
||||||
|
@ -305,15 +306,18 @@ class Mimes
|
||||||
'application/x-jar',
|
'application/x-jar',
|
||||||
'application/x-compressed',
|
'application/x-compressed',
|
||||||
],
|
],
|
||||||
'svg' => ['image/svg+xml', 'application/xml', 'text/xml'],
|
'svg' => ['image/svg+xml', 'image/svg', 'application/xml', 'text/xml'],
|
||||||
'vcf' => 'text/x-vcard',
|
'vcf' => 'text/x-vcard',
|
||||||
'srt' => ['text/srt', 'text/plain', 'application/octet-stream'],
|
'srt' => ['text/srt', 'text/plain', 'application/octet-stream'],
|
||||||
'vtt' => ['text/vtt', 'text/plain'],
|
'vtt' => ['text/vtt', 'text/plain'],
|
||||||
'ico' => ['image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon'],
|
'ico' => ['image/x-icon', 'image/x-ico', 'image/vnd.microsoft.icon'],
|
||||||
|
'stl' => [
|
||||||
|
'application/sla',
|
||||||
|
'application/vnd.ms-pki.stl',
|
||||||
|
'application/x-navistyle',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to determine the best mime type for the given file extension.
|
* Attempts to determine the best mime type for the given file extension.
|
||||||
*
|
*
|
||||||
|
@ -334,41 +338,47 @@ class Mimes
|
||||||
: static::$mimes[$extension];
|
: static::$mimes[$extension];
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to determine the best file extension for a given mime type.
|
* Attempts to determine the best file extension for a given mime type.
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @param string $type
|
||||||
* @param string $proposed_extension - default extension (in case there is more than one with the same mime type)
|
* @param string|null $proposedExtension - default extension (in case there is more than one with the same mime type)
|
||||||
*
|
*
|
||||||
* @return string|null The extension determined, or null if unable to match.
|
* @return string|null The extension determined, or null if unable to match.
|
||||||
*/
|
*/
|
||||||
public static function guessExtensionFromType(
|
public static function guessExtensionFromType(
|
||||||
string $type,
|
string $type,
|
||||||
?string $proposed_extension = null
|
string $proposedExtension = null
|
||||||
) {
|
) {
|
||||||
$type = trim(strtolower($type), '. ');
|
$type = trim(strtolower($type), '. ');
|
||||||
|
|
||||||
$proposed_extension = trim(strtolower($proposed_extension));
|
$proposedExtension = trim(strtolower($proposedExtension));
|
||||||
|
|
||||||
if (
|
if ($proposedExtension !== '') {
|
||||||
!is_null($proposed_extension) &&
|
if (
|
||||||
array_key_exists($proposed_extension, static::$mimes) &&
|
array_key_exists($proposedExtension, static::$mimes) &&
|
||||||
in_array(
|
in_array(
|
||||||
$type,
|
$type,
|
||||||
is_string(static::$mimes[$proposed_extension])
|
is_string(static::$mimes[$proposedExtension])
|
||||||
? [static::$mimes[$proposed_extension]]
|
? [static::$mimes[$proposedExtension]]
|
||||||
: static::$mimes[$proposed_extension]
|
: static::$mimes[$proposedExtension],
|
||||||
)
|
true,
|
||||||
) {
|
)
|
||||||
return $proposed_extension;
|
) {
|
||||||
|
// The detected mime type matches with the proposed extension.
|
||||||
|
return $proposedExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An extension was proposed, but the media type does not match the mime type list.
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reverse check the mime type list if no extension was proposed.
|
||||||
|
// This search is order sensitive!
|
||||||
foreach (static::$mimes as $ext => $types) {
|
foreach (static::$mimes as $ext => $types) {
|
||||||
if (
|
if (
|
||||||
(is_string($types) && $types === $type) ||
|
(is_string($types) && $types === $type) ||
|
||||||
(is_array($types) && in_array($type, $types))
|
(is_array($types) && in_array($type, $types, true))
|
||||||
) {
|
) {
|
||||||
return $ext;
|
return $ext;
|
||||||
}
|
}
|
||||||
|
@ -376,6 +386,4 @@ class Mimes
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,62 +2,46 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
// Cannot extend BaseConfig or looping resources occurs.
|
use CodeIgniter\Modules\Modules as BaseModules;
|
||||||
class Modules
|
|
||||||
|
class Modules extends BaseModules
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Auto-Discovery Enabled?
|
* Enable Auto-Discovery?
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| If true, then auto-discovery will happen across all elements listed in
|
* If true, then auto-discovery will happen across all elements listed in
|
||||||
| $activeExplorers below. If false, no auto-discovery will happen at all,
|
* $activeExplorers below. If false, no auto-discovery will happen at all,
|
||||||
| giving a slight performance boost.
|
* giving a slight performance boost.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
public $enabled = true;
|
public $enabled = true;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Auto-Discovery Within Composer Packages Enabled?
|
* Enable Auto-Discovery Within Composer Packages?
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| If true, then auto-discovery will happen across all namespaces loaded
|
* If true, then auto-discovery will happen across all namespaces loaded
|
||||||
| by Composer, as well as the namespaces configured locally.
|
* by Composer, as well as the namespaces configured locally.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
public $discoverInComposer = true;
|
public $discoverInComposer = true;
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Auto-discover Rules
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Lists the aliases of all discovery classes that will be active
|
|
||||||
| and used during the current application request. If it is not
|
|
||||||
| listed here, only the base application elements will be used.
|
|
||||||
*/
|
|
||||||
public $activeExplorers = ['events', 'registrars', 'routes', 'services'];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should the application auto-discover the requested resources.
|
* --------------------------------------------------------------------------
|
||||||
|
* Auto-Discovery Rules
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Valid values are:
|
* Aliases list of all discovery classes that will be active and used during
|
||||||
* - events
|
* the current application request.
|
||||||
* - registrars
|
|
||||||
* - routes
|
|
||||||
* - services
|
|
||||||
*
|
*
|
||||||
* @param string $alias
|
* If it is not listed, only the base application elements will be used.
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
public function shouldDiscover(string $alias)
|
public $aliases = ['events', 'filters', 'registrars', 'routes', 'services'];
|
||||||
{
|
|
||||||
if (!$this->enabled) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$alias = strtolower($alias);
|
|
||||||
|
|
||||||
return in_array($alias, $this->activeExplorers);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,32 +6,34 @@ use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
class Pager extends BaseConfig
|
class Pager extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Templates
|
* Templates
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| Pagination links are rendered out using views to configure their
|
* Pagination links are rendered out using views to configure their
|
||||||
| appearance. This array contains aliases and the view names to
|
* appearance. This array contains aliases and the view names to
|
||||||
| use when rendering the links.
|
* use when rendering the links.
|
||||||
|
|
*
|
||||||
| Within each view, the Pager object will be available as $pager,
|
* Within each view, the Pager object will be available as $pager,
|
||||||
| and the desired group as $pagerGroup;
|
* and the desired group as $pagerGroup;
|
||||||
|
|
*
|
||||||
*/
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
public $templates = [
|
public $templates = [
|
||||||
'default_full' => 'App\Views\pager\default_full',
|
'default_full' => 'App\Views\pager\default_full',
|
||||||
'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
|
'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
|
||||||
'default_head' => 'CodeIgniter\Pager\Views\default_head',
|
'default_head' => 'CodeIgniter\Pager\Views\default_head',
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Items Per Page
|
* Items Per Page
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
|
|
*
|
||||||
| The default number of results shown in a single page.
|
* The default number of results shown in a single page.
|
||||||
|
|
*
|
||||||
*/
|
* @var integer
|
||||||
|
*/
|
||||||
public $perPage = 20;
|
public $perPage = 20;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,12 @@
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Paths
|
||||||
|
*
|
||||||
* Holds the paths that are used by the system to
|
* Holds the paths that are used by the system to
|
||||||
* locate the main directories, app, system, etc.
|
* locate the main directories, app, system, etc.
|
||||||
* Modifying these allows you to re-structure your application,
|
*
|
||||||
|
* Modifying these allows you to restructure your application,
|
||||||
* share a system folder between multiple applications, and more.
|
* share a system folder between multiple applications, and more.
|
||||||
*
|
*
|
||||||
* All paths are relative to the project's root folder.
|
* All paths are relative to the project's root folder.
|
||||||
|
@ -13,34 +16,35 @@ namespace Config;
|
||||||
|
|
||||||
class Paths
|
class Paths
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
*---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
* SYSTEM FOLDER NAME
|
* SYSTEM FOLDER NAME
|
||||||
*---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* This variable must contain the name of your "system" folder.
|
* This must contain the name of your "system" folder. Include
|
||||||
* Include the path if the folder is not in the same directory
|
* the path if the folder is not in the same directory as this file.
|
||||||
* as this file.
|
*
|
||||||
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $systemDirectory =
|
public $systemDirectory =
|
||||||
__DIR__ . '/../../vendor/codeigniter4/codeigniter4/system';
|
__DIR__ . '/../../vendor/codeigniter4/codeigniter4/system';
|
||||||
|
/**
|
||||||
/*
|
* ---------------------------------------------------------------
|
||||||
*---------------------------------------------------------------
|
|
||||||
* APPLICATION FOLDER NAME
|
* APPLICATION FOLDER NAME
|
||||||
*---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* If you want this front controller to use a different "app"
|
* If you want this front controller to use a different "app"
|
||||||
* folder than the default one you can set its name here. The folder
|
* folder than the default one you can set its name here. The folder
|
||||||
* can also be renamed or relocated anywhere on your getServer. If
|
* can also be renamed or relocated anywhere on your getServer. If
|
||||||
* you do, use a full getServer path. For more info please see the user guide:
|
* you do, use a full getServer path.
|
||||||
* http://codeigniter.com/user_guide/general/managing_apps.html
|
|
||||||
*
|
*
|
||||||
* NO TRAILING SLASH!
|
* @see http://codeigniter.com/user_guide/general/managing_apps.html
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $appDirectory = __DIR__ . '/..';
|
public $appDirectory = __DIR__ . '/..';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
* WRITABLE DIRECTORY NAME
|
* WRITABLE DIRECTORY NAME
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
|
@ -50,23 +54,23 @@ class Paths
|
||||||
* need write permission to a single place that can be tucked away
|
* need write permission to a single place that can be tucked away
|
||||||
* for maximum security, keeping it out of the app and/or
|
* for maximum security, keeping it out of the app and/or
|
||||||
* system directories.
|
* system directories.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $writableDirectory = __DIR__ . '/../../writable';
|
public $writableDirectory = __DIR__ . '/../../writable';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
* TESTS DIRECTORY NAME
|
* TESTS DIRECTORY NAME
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* This variable must contain the name of your "tests" directory.
|
* This variable must contain the name of your "tests" directory.
|
||||||
* The writable directory allows you to group all directories that
|
*
|
||||||
* need write permission to a single place that can be tucked away
|
* @var string
|
||||||
* for maximum security, keeping it out of the app and/or
|
|
||||||
* system directories.
|
|
||||||
*/
|
*/
|
||||||
public $testsDirectory = __DIR__ . '/../../tests';
|
public $testsDirectory = __DIR__ . '/../../tests';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
* VIEW DIRECTORY NAME
|
* VIEW DIRECTORY NAME
|
||||||
* ---------------------------------------------------------------
|
* ---------------------------------------------------------------
|
||||||
|
@ -75,6 +79,8 @@ class Paths
|
||||||
* contains the view files used by your application. By
|
* contains the view files used by your application. By
|
||||||
* default this is in `app/Views`. This value
|
* default this is in `app/Views`. This value
|
||||||
* is used when no value is provided to `Services::renderer()`.
|
* is used when no value is provided to `Services::renderer()`.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $viewDirectory = __DIR__ . '/../Views';
|
public $viewDirectory = __DIR__ . '/../Views';
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,19 @@ $routes->setAutoRoute(false);
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$routes->addPlaceholder('podcastName', '[a-zA-Z0-9\_]{1,191}');
|
$routes->addPlaceholder('podcastName', '[a-zA-Z0-9\_]{1,32}');
|
||||||
$routes->addPlaceholder('slug', '[a-zA-Z0-9\-]{1,191}');
|
$routes->addPlaceholder('slug', '[a-zA-Z0-9\-]{1,191}');
|
||||||
$routes->addPlaceholder('base64', '[A-Za-z0-9\.\_]+\-{0,2}');
|
$routes->addPlaceholder('base64', '[A-Za-z0-9\.\_]+\-{0,2}');
|
||||||
$routes->addPlaceholder('platformType', '\bpodcasting|\bsocial|\bfunding');
|
$routes->addPlaceholder('platformType', '\bpodcasting|\bsocial|\bfunding');
|
||||||
|
$routes->addPlaceholder('noteAction', '\bfavourite|\breblog|\breply');
|
||||||
|
$routes->addPlaceholder(
|
||||||
|
'embeddablePlayerTheme',
|
||||||
|
'\blight|\bdark|\blight-transparent|\bdark-transparent',
|
||||||
|
);
|
||||||
|
$routes->addPlaceholder(
|
||||||
|
'uuid',
|
||||||
|
'[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}',
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
|
@ -62,7 +71,7 @@ $routes->group(config('App')->installGateway, function ($routes) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Route for podcast audio file analytics (/audio/pack(podcast_id,episode_id,bytes_threshold,filesize,duration,date)/podcast_folder/filename.mp3)
|
// Route for podcast audio file analytics (/audio/pack(podcast_id,episode_id,bytes_threshold,filesize,duration,date)/podcast_folder/filename.mp3)
|
||||||
$routes->add('audio/(:base64)/(:any)', 'Analytics::hit/$1/$2', [
|
$routes->get('audio/(:base64)/(:any)', 'Analytics::hit/$1/$2', [
|
||||||
'as' => 'analytics_hit',
|
'as' => 'analytics_hit',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -150,7 +159,7 @@ $routes->group(
|
||||||
$routes->post('edit', 'Podcast::attemptEdit/$1', [
|
$routes->post('edit', 'Podcast::attemptEdit/$1', [
|
||||||
'filter' => 'permission:podcast-edit',
|
'filter' => 'permission:podcast-edit',
|
||||||
]);
|
]);
|
||||||
$routes->add('delete', 'Podcast::delete/$1', [
|
$routes->get('delete', 'Podcast::delete/$1', [
|
||||||
'as' => 'podcast-delete',
|
'as' => 'podcast-delete',
|
||||||
'filter' => 'permission:podcasts-delete',
|
'filter' => 'permission:podcasts-delete',
|
||||||
]);
|
]);
|
||||||
|
@ -170,7 +179,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'podcast-person-remove',
|
'as' => 'podcast-person-remove',
|
||||||
'filter' => 'permission:podcast-edit',
|
'filter' => 'permission:podcast-edit',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -185,7 +194,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'podcast-analytics-webpages',
|
'as' => 'podcast-analytics-webpages',
|
||||||
'filter' => 'permission:podcasts-view,podcast-view',
|
'filter' => 'permission:podcasts-view,podcast-view',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'locations',
|
'locations',
|
||||||
|
@ -193,7 +202,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'podcast-analytics-locations',
|
'as' => 'podcast-analytics-locations',
|
||||||
'filter' => 'permission:podcasts-view,podcast-view',
|
'filter' => 'permission:podcasts-view,podcast-view',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'unique-listeners',
|
'unique-listeners',
|
||||||
|
@ -201,7 +210,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'podcast-analytics-unique-listeners',
|
'as' => 'podcast-analytics-unique-listeners',
|
||||||
'filter' => 'permission:podcasts-view,podcast-view',
|
'filter' => 'permission:podcasts-view,podcast-view',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'listening-time',
|
'listening-time',
|
||||||
|
@ -209,7 +218,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'podcast-analytics-listening-time',
|
'as' => 'podcast-analytics-listening-time',
|
||||||
'filter' => 'permission:podcasts-view,podcast-view',
|
'filter' => 'permission:podcasts-view,podcast-view',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'time-periods',
|
'time-periods',
|
||||||
|
@ -217,7 +226,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'podcast-analytics-time-periods',
|
'as' => 'podcast-analytics-time-periods',
|
||||||
'filter' => 'permission:podcasts-view,podcast-view',
|
'filter' => 'permission:podcasts-view,podcast-view',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'players',
|
'players',
|
||||||
|
@ -225,7 +234,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'podcast-analytics-players',
|
'as' => 'podcast-analytics-players',
|
||||||
'filter' => 'permission:podcasts-view,podcast-view',
|
'filter' => 'permission:podcasts-view,podcast-view',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -235,7 +244,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'analytics-full-data',
|
'as' => 'analytics-full-data',
|
||||||
'filter' => 'permission:podcasts-view,podcast-view',
|
'filter' => 'permission:podcasts-view,podcast-view',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'analytics-data/(:segment)/(:segment)',
|
'analytics-data/(:segment)/(:segment)',
|
||||||
|
@ -243,7 +252,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'analytics-data',
|
'as' => 'analytics-data',
|
||||||
'filter' => 'permission:podcasts-view,podcast-view',
|
'filter' => 'permission:podcasts-view,podcast-view',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'analytics-data/(:segment)/(:segment)/(:num)',
|
'analytics-data/(:segment)/(:segment)/(:num)',
|
||||||
|
@ -251,7 +260,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'analytics-filtered-data',
|
'as' => 'analytics-filtered-data',
|
||||||
'filter' => 'permission:podcasts-view,podcast-view',
|
'filter' => 'permission:podcasts-view,podcast-view',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Podcast episodes
|
// Podcast episodes
|
||||||
|
@ -283,7 +292,50 @@ $routes->group(
|
||||||
$routes->post('edit', 'Episode::attemptEdit/$1/$2', [
|
$routes->post('edit', 'Episode::attemptEdit/$1/$2', [
|
||||||
'filter' => 'permission:podcast_episodes-edit',
|
'filter' => 'permission:podcast_episodes-edit',
|
||||||
]);
|
]);
|
||||||
$routes->add('delete', 'Episode::delete/$1/$2', [
|
$routes->get('publish', 'Episode::publish/$1/$2', [
|
||||||
|
'as' => 'episode-publish',
|
||||||
|
'filter' =>
|
||||||
|
'permission:podcast-manage_publications',
|
||||||
|
]);
|
||||||
|
$routes->post(
|
||||||
|
'publish',
|
||||||
|
'Episode::attemptPublish/$1/$2',
|
||||||
|
[
|
||||||
|
'filter' =>
|
||||||
|
'permission:podcast-manage_publications',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
$routes->get(
|
||||||
|
'publish-edit',
|
||||||
|
'Episode::publishEdit/$1/$2',
|
||||||
|
[
|
||||||
|
'as' => 'episode-publish_edit',
|
||||||
|
'filter' =>
|
||||||
|
'permission:podcast-manage_publications',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
$routes->post(
|
||||||
|
'publish-edit',
|
||||||
|
'Episode::attemptPublishEdit/$1/$2',
|
||||||
|
[
|
||||||
|
'filter' =>
|
||||||
|
'permission:podcast-manage_publications',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
$routes->get('unpublish', 'Episode::unpublish/$1/$2', [
|
||||||
|
'as' => 'episode-unpublish',
|
||||||
|
'filter' =>
|
||||||
|
'permission:podcast-manage_publications',
|
||||||
|
]);
|
||||||
|
$routes->post(
|
||||||
|
'unpublish',
|
||||||
|
'Episode::attemptUnpublish/$1/$2',
|
||||||
|
[
|
||||||
|
'filter' =>
|
||||||
|
'permission:podcast-manage_publications',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
$routes->get('delete', 'Episode::delete/$1/$2', [
|
||||||
'as' => 'episode-delete',
|
'as' => 'episode-delete',
|
||||||
'filter' => 'permission:podcast_episodes-delete',
|
'filter' => 'permission:podcast_episodes-delete',
|
||||||
]);
|
]);
|
||||||
|
@ -293,7 +345,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'transcript-delete',
|
'as' => 'transcript-delete',
|
||||||
'filter' => 'permission:podcast_episodes-edit',
|
'filter' => 'permission:podcast_episodes-edit',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'chapters-delete',
|
'chapters-delete',
|
||||||
|
@ -301,7 +353,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'chapters-delete',
|
'as' => 'chapters-delete',
|
||||||
'filter' => 'permission:podcast_episodes-edit',
|
'filter' => 'permission:podcast_episodes-edit',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'soundbites',
|
'soundbites',
|
||||||
|
@ -309,22 +361,22 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'soundbites-edit',
|
'as' => 'soundbites-edit',
|
||||||
'filter' => 'permission:podcast_episodes-edit',
|
'filter' => 'permission:podcast_episodes-edit',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->post(
|
$routes->post(
|
||||||
'soundbites',
|
'soundbites',
|
||||||
'Episode::soundbitesAttemptEdit/$1/$2',
|
'Episode::soundbitesAttemptEdit/$1/$2',
|
||||||
[
|
[
|
||||||
'filter' => 'permission:podcast_episodes-edit',
|
'filter' => 'permission:podcast_episodes-edit',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->add(
|
$routes->get(
|
||||||
'soundbites/(:num)/delete',
|
'soundbites/(:num)/delete',
|
||||||
'Episode::soundbiteDelete/$1/$2/$3',
|
'Episode::soundbiteDelete/$1/$2/$3',
|
||||||
[
|
[
|
||||||
'as' => 'soundbite-delete',
|
'as' => 'soundbite-delete',
|
||||||
'filter' => 'permission:podcast_episodes-edit',
|
'filter' => 'permission:podcast_episodes-edit',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'embeddable-player',
|
'embeddable-player',
|
||||||
|
@ -332,7 +384,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'embeddable-player-add',
|
'as' => 'embeddable-player-add',
|
||||||
'filter' => 'permission:podcast_episodes-edit',
|
'filter' => 'permission:podcast_episodes-edit',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
$routes->group('persons', function ($routes) {
|
$routes->group('persons', function ($routes) {
|
||||||
|
@ -346,7 +398,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'filter' =>
|
'filter' =>
|
||||||
'permission:podcast_episodes-edit',
|
'permission:podcast_episodes-edit',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'(:num)/remove',
|
'(:num)/remove',
|
||||||
|
@ -355,7 +407,7 @@ $routes->group(
|
||||||
'as' => 'episode-person-remove',
|
'as' => 'episode-person-remove',
|
||||||
'filter' =>
|
'filter' =>
|
||||||
'permission:podcast_episodes-edit',
|
'permission:podcast_episodes-edit',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -394,9 +446,9 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'filter' =>
|
'filter' =>
|
||||||
'permission:podcast-manage_contributors',
|
'permission:podcast-manage_contributors',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->add('remove', 'Contributor::remove/$1/$2', [
|
$routes->get('remove', 'Contributor::remove/$1/$2', [
|
||||||
'as' => 'contributor-remove',
|
'as' => 'contributor-remove',
|
||||||
'filter' =>
|
'filter' =>
|
||||||
'permission:podcast-manage_contributors',
|
'permission:podcast-manage_contributors',
|
||||||
|
@ -411,7 +463,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'platforms-podcasting',
|
'as' => 'platforms-podcasting',
|
||||||
'filter' => 'permission:podcast-manage_platforms',
|
'filter' => 'permission:podcast-manage_platforms',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'social',
|
'social',
|
||||||
|
@ -419,7 +471,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'platforms-social',
|
'as' => 'platforms-social',
|
||||||
'filter' => 'permission:podcast-manage_platforms',
|
'filter' => 'permission:podcast-manage_platforms',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->get(
|
$routes->get(
|
||||||
'funding',
|
'funding',
|
||||||
|
@ -427,7 +479,7 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'platforms-funding',
|
'as' => 'platforms-funding',
|
||||||
'filter' => 'permission:podcast-manage_platforms',
|
'filter' => 'permission:podcast-manage_platforms',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->post(
|
$routes->post(
|
||||||
'save/(:platformType)',
|
'save/(:platformType)',
|
||||||
|
@ -435,20 +487,35 @@ $routes->group(
|
||||||
[
|
[
|
||||||
'as' => 'platforms-save',
|
'as' => 'platforms-save',
|
||||||
'filter' => 'permission:podcast-manage_platforms',
|
'filter' => 'permission:podcast-manage_platforms',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
$routes->add(
|
$routes->get(
|
||||||
'(:slug)/podcast-platform-remove',
|
'(:slug)/podcast-platform-remove',
|
||||||
'PodcastPlatform::removePodcastPlatform/$1/$2',
|
'PodcastPlatform::removePodcastPlatform/$1/$2',
|
||||||
[
|
[
|
||||||
'as' => 'podcast-platform-remove',
|
'as' => 'podcast-platform-remove',
|
||||||
'filter' => 'permission:podcast-manage_platforms',
|
'filter' => 'permission:podcast-manage_platforms',
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Instance wide Fediverse config
|
||||||
|
$routes->group('fediverse', function ($routes) {
|
||||||
|
$routes->get('/', 'Fediverse::dashboard', [
|
||||||
|
'as' => 'fediverse-dashboard',
|
||||||
|
]);
|
||||||
|
$routes->get('blocked-actors', 'Fediverse::blockedActors', [
|
||||||
|
'as' => 'fediverse-blocked-actors',
|
||||||
|
'filter' => 'permission:fediverse-block_actors',
|
||||||
|
]);
|
||||||
|
$routes->get('blocked-domains', 'Fediverse::blockedDomains', [
|
||||||
|
'as' => 'fediverse-blocked-domains',
|
||||||
|
'filter' => 'permission:fediverse-block_domains',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
$routes->group('pages', function ($routes) {
|
$routes->group('pages', function ($routes) {
|
||||||
$routes->get('/', 'Page::list', ['as' => 'page-list']);
|
$routes->get('/', 'Page::list', ['as' => 'page-list']);
|
||||||
|
@ -470,7 +537,7 @@ $routes->group(
|
||||||
'filter' => 'permission:pages-manage',
|
'filter' => 'permission:pages-manage',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$routes->add('delete', 'Page::delete/$1', [
|
$routes->get('delete', 'Page::delete/$1', [
|
||||||
'as' => 'page-delete',
|
'as' => 'page-delete',
|
||||||
'filter' => 'permission:pages-manage',
|
'filter' => 'permission:pages-manage',
|
||||||
]);
|
]);
|
||||||
|
@ -504,19 +571,19 @@ $routes->group(
|
||||||
$routes->post('edit', 'User::attemptEdit/$1', [
|
$routes->post('edit', 'User::attemptEdit/$1', [
|
||||||
'filter' => 'permission:users-manage_authorizations',
|
'filter' => 'permission:users-manage_authorizations',
|
||||||
]);
|
]);
|
||||||
$routes->add('ban', 'User::ban/$1', [
|
$routes->get('ban', 'User::ban/$1', [
|
||||||
'as' => 'user-ban',
|
'as' => 'user-ban',
|
||||||
'filter' => 'permission:users-manage_bans',
|
'filter' => 'permission:users-manage_bans',
|
||||||
]);
|
]);
|
||||||
$routes->add('unban', 'User::unBan/$1', [
|
$routes->get('unban', 'User::unBan/$1', [
|
||||||
'as' => 'user-unban',
|
'as' => 'user-unban',
|
||||||
'filter' => 'permission:users-manage_bans',
|
'filter' => 'permission:users-manage_bans',
|
||||||
]);
|
]);
|
||||||
$routes->add('force-pass-reset', 'User::forcePassReset/$1', [
|
$routes->get('force-pass-reset', 'User::forcePassReset/$1', [
|
||||||
'as' => 'user-force_pass_reset',
|
'as' => 'user-force_pass_reset',
|
||||||
'filter' => 'permission:users-force_pass_reset',
|
'filter' => 'permission:users-force_pass_reset',
|
||||||
]);
|
]);
|
||||||
$routes->add('delete', 'User::delete/$1', [
|
$routes->get('delete', 'User::delete/$1', [
|
||||||
'as' => 'user-delete',
|
'as' => 'user-delete',
|
||||||
'filter' => 'permission:users-delete',
|
'filter' => 'permission:users-delete',
|
||||||
]);
|
]);
|
||||||
|
@ -533,7 +600,7 @@ $routes->group(
|
||||||
]);
|
]);
|
||||||
$routes->post('change-password', 'MyAccount::attemptChange/$1');
|
$routes->post('change-password', 'MyAccount::attemptChange/$1');
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -570,35 +637,142 @@ $routes->group(config('App')->authGateway, function ($routes) {
|
||||||
$routes->post('reset-password', 'Auth::attemptReset');
|
$routes->post('reset-password', 'Auth::attemptReset');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Public routes
|
// Podcast's Public routes
|
||||||
$routes->group('@(:podcastName)', function ($routes) {
|
$routes->group('@(:podcastName)', function ($routes) {
|
||||||
$routes->get('/', 'Podcast/$1', ['as' => 'podcast']);
|
$routes->get('/', 'Podcast::activity/$1', [
|
||||||
$routes->group('(:slug)', function ($routes) {
|
'as' => 'podcast-activity',
|
||||||
|
]);
|
||||||
|
// override default ActivityPub Library's actor route
|
||||||
|
$routes->get('/', 'Podcast::activity/$1', [
|
||||||
|
'as' => 'actor',
|
||||||
|
'alternate-content' => [
|
||||||
|
'application/activity+json' => [
|
||||||
|
'namespace' => 'ActivityPub\Controllers',
|
||||||
|
'controller-method' => 'ActorController/$1',
|
||||||
|
],
|
||||||
|
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
|
||||||
|
'namespace' => 'ActivityPub\Controllers',
|
||||||
|
'controller-method' => 'ActorController/$1',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$routes->get('episodes', 'Podcast::episodes/$1', [
|
||||||
|
'as' => 'podcast-episodes',
|
||||||
|
]);
|
||||||
|
$routes->group('episodes/(:slug)', function ($routes) {
|
||||||
$routes->get('/', 'Episode/$1/$2', [
|
$routes->get('/', 'Episode/$1/$2', [
|
||||||
'as' => 'episode',
|
'as' => 'episode',
|
||||||
]);
|
]);
|
||||||
|
$routes->get('oembed.json', 'Episode::oembedJSON/$1/$2', [
|
||||||
|
'as' => 'episode-oembed-json',
|
||||||
|
]);
|
||||||
|
$routes->get('oembed.xml', 'Episode::oembedXML/$1/$2', [
|
||||||
|
'as' => 'episode-oembed-xml',
|
||||||
|
]);
|
||||||
$routes->group('embeddable-player', function ($routes) {
|
$routes->group('embeddable-player', function ($routes) {
|
||||||
$routes->get('/', 'Episode::embeddablePlayer/$1/$2', [
|
$routes->get('/', 'Episode::embeddablePlayer/$1/$2', [
|
||||||
'as' => 'embeddable-player',
|
'as' => 'embeddable-player',
|
||||||
]);
|
]);
|
||||||
$routes->get('(:slug)', 'Episode::embeddablePlayer/$1/$2/$3', [
|
$routes->get(
|
||||||
'as' => 'embeddable-player-theme',
|
'(:embeddablePlayerTheme)',
|
||||||
]);
|
'Episode::embeddablePlayer/$1/$2/$3',
|
||||||
|
[
|
||||||
|
'as' => 'embeddable-player-theme',
|
||||||
|
],
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$routes->head('feed.xml', 'Feed/$1', ['as' => 'podcast_feed']);
|
$routes->head('feed.xml', 'Feed/$1', ['as' => 'podcast_feed']);
|
||||||
$routes->get('feed.xml', 'Feed/$1', ['as' => 'podcast_feed']);
|
$routes->get('feed.xml', 'Feed/$1', ['as' => 'podcast_feed']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Other pages
|
||||||
$routes->get('/credits', 'Page::credits', ['as' => 'credits']);
|
$routes->get('/credits', 'Page::credits', ['as' => 'credits']);
|
||||||
$routes->get('/(:slug)', 'Page/$1', ['as' => 'page']);
|
$routes->get('/(:slug)', 'Page/$1', ['as' => 'page']);
|
||||||
|
|
||||||
|
// interacting as an actor
|
||||||
|
$routes->post('interact-as-actor', 'Auth::attemptInteractAsActor', [
|
||||||
|
'as' => 'interact-as-actor',
|
||||||
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Overwriting ActivityPub routes file
|
||||||
|
*/
|
||||||
|
$routes->group('@(:podcastName)', function ($routes) {
|
||||||
|
$routes->post('notes/new', 'Note::attemptCreate/$1', [
|
||||||
|
'as' => 'note-attempt-create',
|
||||||
|
'filter' => 'permission:podcast-manage_publications',
|
||||||
|
]);
|
||||||
|
// Note
|
||||||
|
$routes->group('notes/(:uuid)', function ($routes) {
|
||||||
|
$routes->get('/', 'Note/$1/$2', [
|
||||||
|
'as' => 'note',
|
||||||
|
'alternate-content' => [
|
||||||
|
'application/activity+json' => [
|
||||||
|
'namespace' => 'ActivityPub\Controllers',
|
||||||
|
'controller-method' => 'NoteController/$2',
|
||||||
|
],
|
||||||
|
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
|
||||||
|
'namespace' => 'ActivityPub\Controllers',
|
||||||
|
'controller-method' => 'NoteController/$2',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$routes->get('replies', 'Note/$1/$2', [
|
||||||
|
'as' => 'note-replies',
|
||||||
|
'alternate-content' => [
|
||||||
|
'application/activity+json' => [
|
||||||
|
'namespace' => 'ActivityPub\Controllers',
|
||||||
|
'controller-method' => 'NoteController::replies/$2',
|
||||||
|
],
|
||||||
|
'application/ld+json; profile="https://www.w3.org/ns/activitystreams' => [
|
||||||
|
'namespace' => 'ActivityPub\Controllers',
|
||||||
|
'controller-method' => 'NoteController::replies/$2',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
$routes->post('action', 'Note::attemptAction/$1/$2', [
|
||||||
|
'as' => 'note-attempt-action',
|
||||||
|
'filter' => 'permission:podcast-interact_as',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$routes->post('block-actor', 'Note::attemptBlockActor/$1/$2', [
|
||||||
|
'as' => 'note-attempt-block-actor',
|
||||||
|
'filter' => 'permission:fediverse-block_actors',
|
||||||
|
]);
|
||||||
|
$routes->post('block-domain', 'Note::attemptBlockDomain/$1/$2', [
|
||||||
|
'as' => 'note-attempt-block-domain',
|
||||||
|
'filter' => 'permission:fediverse-block_domains',
|
||||||
|
]);
|
||||||
|
$routes->post('delete', 'Note::attemptDelete/$1/$2', [
|
||||||
|
'as' => 'note-attempt-delete',
|
||||||
|
'filter' => 'permission:podcast-manage_publications',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$routes->get('remote/(:noteAction)', 'Note::remoteAction/$1/$2/$3', [
|
||||||
|
'as' => 'note-remote-action',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$routes->get('follow', 'Actor::follow/$1', [
|
||||||
|
'as' => 'follow',
|
||||||
|
]);
|
||||||
|
$routes->get('outbox', 'Actor::outbox/$1', [
|
||||||
|
'as' => 'outbox',
|
||||||
|
'filter' => 'activity-pub:verify-activitystream',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
* Additional Routing
|
* Additional Routing
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* There will often be times that you need additional routing and you
|
* There will often be times that you need additional routing and you
|
||||||
* need to it be able to override any defaults in this file. Environment
|
* need it to be able to override any defaults in this file. Environment
|
||||||
* based routes is one such time. require() additional route files here
|
* based routes is one such time. require() additional route files here
|
||||||
* to make that happen.
|
* to make that happen.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Config;
|
||||||
|
|
||||||
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
|
class Security extends BaseConfig
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Token Name
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Token name for Cross Site Request Forgery protection cookie.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $tokenName = 'csrf_test_name';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Header Name
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Token name for Cross Site Request Forgery protection cookie.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $headerName = 'X-CSRF-TOKEN';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Cookie Name
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Cookie name for Cross Site Request Forgery protection cookie.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $cookieName = 'csrf_cookie_name';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Expires
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Expiration time for Cross Site Request Forgery protection cookie.
|
||||||
|
*
|
||||||
|
* Defaults to two hours (in seconds).
|
||||||
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
public $expires = 7200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Regenerate
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Regenerate CSRF Token on every request.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $regenerate = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF Redirect
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Redirect to previous page with error on failure.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
public $redirect = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* CSRF SameSite
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Setting for CSRF SameSite cookie token.
|
||||||
|
*
|
||||||
|
* Allowed values are: None - Lax - Strict - ''.
|
||||||
|
*
|
||||||
|
* Defaults to `Lax` as recommended in this link:
|
||||||
|
* @see https://portswigger.net/web-security/csrf/samesite-cookies
|
||||||
|
*
|
||||||
|
* @var string 'Lax'|'None'|'Strict'
|
||||||
|
*/
|
||||||
|
public $samesite = 'Lax';
|
||||||
|
}
|
|
@ -2,17 +2,20 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
use CodeIgniter\Config\Services as CoreServices;
|
use CodeIgniter\Config\BaseService;
|
||||||
use CodeIgniter\Model;
|
use CodeIgniter\Model;
|
||||||
use App\Authorization\FlatAuthorization;
|
use App\Authorization\FlatAuthorization;
|
||||||
use App\Authorization\PermissionModel;
|
use App\Authorization\PermissionModel;
|
||||||
use App\Authorization\GroupModel;
|
use App\Authorization\GroupModel;
|
||||||
use App\Libraries\Breadcrumb;
|
use App\Libraries\Breadcrumb;
|
||||||
|
use App\Libraries\Negotiate;
|
||||||
|
use App\Libraries\Router;
|
||||||
use App\Models\UserModel;
|
use App\Models\UserModel;
|
||||||
|
use CodeIgniter\HTTP\Request;
|
||||||
|
use CodeIgniter\HTTP\RequestInterface;
|
||||||
|
use CodeIgniter\Router\RouteCollectionInterface;
|
||||||
use Myth\Auth\Models\LoginModel;
|
use Myth\Auth\Models\LoginModel;
|
||||||
|
|
||||||
require_once SYSTEMPATH . 'Config/Services.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Services Configuration file.
|
* Services Configuration file.
|
||||||
*
|
*
|
||||||
|
@ -26,8 +29,56 @@ require_once SYSTEMPATH . 'Config/Services.php';
|
||||||
* method format you should use for your service methods. For more examples,
|
* method format you should use for your service methods. For more examples,
|
||||||
* see the core Services file at system/Config/Services.php.
|
* see the core Services file at system/Config/Services.php.
|
||||||
*/
|
*/
|
||||||
class Services extends CoreServices
|
class Services extends BaseService
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* The Router class uses a RouteCollection's array of routes, and determines
|
||||||
|
* the correct Controller and Method to execute.
|
||||||
|
*
|
||||||
|
* @param RouteCollectionInterface|null $routes
|
||||||
|
* @param Request|null $request
|
||||||
|
* @param boolean $getShared
|
||||||
|
*
|
||||||
|
* @return Router
|
||||||
|
*/
|
||||||
|
public static function router(
|
||||||
|
RouteCollectionInterface $routes = null,
|
||||||
|
Request $request = null,
|
||||||
|
bool $getShared = true
|
||||||
|
) {
|
||||||
|
if ($getShared) {
|
||||||
|
return static::getSharedInstance('router', $routes, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$routes = $routes ?? static::routes();
|
||||||
|
$request = $request ?? static::request();
|
||||||
|
|
||||||
|
return new Router($routes, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Negotiate class provides the content negotiation features for
|
||||||
|
* working the request to determine correct language, encoding, charset,
|
||||||
|
* and more.
|
||||||
|
*
|
||||||
|
* @param RequestInterface|null $request
|
||||||
|
* @param boolean $getShared
|
||||||
|
*
|
||||||
|
* @return Negotiate
|
||||||
|
*/
|
||||||
|
public static function negotiator(
|
||||||
|
RequestInterface $request = null,
|
||||||
|
bool $getShared = true
|
||||||
|
) {
|
||||||
|
if ($getShared) {
|
||||||
|
return static::getSharedInstance('negotiator', $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = $request ?? static::request();
|
||||||
|
|
||||||
|
return new Negotiate($request);
|
||||||
|
}
|
||||||
|
|
||||||
public static function authentication(
|
public static function authentication(
|
||||||
string $lib = 'local',
|
string $lib = 'local',
|
||||||
Model $userModel = null,
|
Model $userModel = null,
|
||||||
|
@ -39,7 +90,7 @@ class Services extends CoreServices
|
||||||
'authentication',
|
'authentication',
|
||||||
$lib,
|
$lib,
|
||||||
$userModel,
|
$userModel,
|
||||||
$loginModel
|
$loginModel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +123,7 @@ class Services extends CoreServices
|
||||||
'authorization',
|
'authorization',
|
||||||
$groupModel,
|
$groupModel,
|
||||||
$permissionModel,
|
$permissionModel,
|
||||||
$userModel
|
$userModel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,69 +3,85 @@
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
use CodeIgniter\Config\BaseConfig;
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
use CodeIgniter\Debug\Toolbar\Collectors\Database;
|
||||||
|
use CodeIgniter\Debug\Toolbar\Collectors\Events;
|
||||||
|
use CodeIgniter\Debug\Toolbar\Collectors\Files;
|
||||||
|
use CodeIgniter\Debug\Toolbar\Collectors\Logs;
|
||||||
|
use CodeIgniter\Debug\Toolbar\Collectors\Routes;
|
||||||
|
use CodeIgniter\Debug\Toolbar\Collectors\Timers;
|
||||||
|
use CodeIgniter\Debug\Toolbar\Collectors\Views;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Debug Toolbar
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The Debug Toolbar provides a way to see information about the performance
|
||||||
|
* and state of your application during that page display. By default it will
|
||||||
|
* NOT be displayed under production environments, and will only display if
|
||||||
|
* `CI_DEBUG` is true, since if it's not, there's not much to display anyway.
|
||||||
|
*/
|
||||||
class Toolbar extends BaseConfig
|
class Toolbar extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Debug Toolbar
|
* Toolbar Collectors
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| The Debug Toolbar provides a way to see information about the performance
|
*
|
||||||
| and state of your application during that page display. By default it will
|
* List of toolbar collectors that will be called when Debug Toolbar
|
||||||
| NOT be displayed under production environments, and will only display if
|
* fires up and collects data from.
|
||||||
| CI_DEBUG is true, since if it's not, there's not much to display anyway.
|
*
|
||||||
|
|
* @var string[]
|
||||||
| toolbarMaxHistory = Number of history files, 0 for none or -1 for unlimited
|
*/
|
||||||
|
|
|
||||||
*/
|
|
||||||
public $collectors = [
|
public $collectors = [
|
||||||
\CodeIgniter\Debug\Toolbar\Collectors\Timers::class,
|
Timers::class,
|
||||||
\CodeIgniter\Debug\Toolbar\Collectors\Database::class,
|
Database::class,
|
||||||
\CodeIgniter\Debug\Toolbar\Collectors\Logs::class,
|
Logs::class,
|
||||||
\CodeIgniter\Debug\Toolbar\Collectors\Views::class,
|
Views::class,
|
||||||
\CodeIgniter\Debug\Toolbar\Collectors\Cache::class,
|
// Cache::class,
|
||||||
\CodeIgniter\Debug\Toolbar\Collectors\Files::class,
|
Files::class,
|
||||||
\CodeIgniter\Debug\Toolbar\Collectors\Routes::class,
|
Routes::class,
|
||||||
\CodeIgniter\Debug\Toolbar\Collectors\Events::class,
|
Events::class,
|
||||||
\Myth\Auth\Collectors\Auth::class,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Max History
|
* Max History
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| The Toolbar allows you to view recent requests that have been made to
|
*
|
||||||
| the application while the toolbar is active. This allows you to quickly
|
* `$maxHistory` sets a limit on the number of past requests that are stored,
|
||||||
| view and compare multiple requests.
|
* helping to conserve file space used to store them. You can set it to
|
||||||
|
|
* 0 (zero) to not have any history stored, or -1 for unlimited history.
|
||||||
| $maxHistory sets a limit on the number of past requests that are stored,
|
*
|
||||||
| helping to conserve file space used to store them. You can set it to
|
* @var integer
|
||||||
| 0 (zero) to not have any history stored, or -1 for unlimited history.
|
*/
|
||||||
|
|
|
||||||
*/
|
|
||||||
public $maxHistory = 20;
|
public $maxHistory = 20;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Toolbar Views Path
|
* Toolbar Views Path
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| The full path to the the views that are used by the toolbar.
|
*
|
||||||
| MUST have a trailing slash.
|
* The full path to the the views that are used by the toolbar.
|
||||||
|
|
* This MUST have a trailing slash.
|
||||||
*/
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/';
|
public $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| Max Queries
|
* Max Queries
|
||||||
|--------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
| If the Database Collector is enabled, it will log every query that the
|
*
|
||||||
| the system generates so they can be displayed on the toolbar's timeline
|
* If the Database Collector is enabled, it will log every query that the
|
||||||
| and in the query log. This can lead to memory issues in some instances
|
* the system generates so they can be displayed on the toolbar's timeline
|
||||||
| with hundreds of queries.
|
* and in the query log. This can lead to memory issues in some instances
|
||||||
|
|
* with hundreds of queries.
|
||||||
| $maxQueries defines the maximum amount of queries that will be stored.
|
*
|
||||||
|
|
* `$maxQueries` defines the maximum amount of queries that will be stored.
|
||||||
*/
|
*
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
public $maxQueries = 100;
|
public $maxQueries = 100;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,27 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
use CodeIgniter\Config\BaseConfig;
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
* User Agents
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* This file contains four arrays of user agent data. It is used by the
|
||||||
|
* User Agent Class to help identify browser, platform, robot, and
|
||||||
|
* mobile device data. The array keys are used to identify the device
|
||||||
|
* and the array values are used to set the actual name of the item.
|
||||||
|
*/
|
||||||
class UserAgents extends BaseConfig
|
class UserAgents extends BaseConfig
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
| -------------------------------------------------------------------
|
* -------------------------------------------------------------------
|
||||||
| USER AGENT TYPES
|
* OS Platforms
|
||||||
| -------------------------------------------------------------------
|
* -------------------------------------------------------------------
|
||||||
| This file contains four arrays of user agent data. It is used by the
|
*
|
||||||
| User Agent Class to help identify browser, platform, robot, and
|
* @var array<string, string>
|
||||||
| mobile device data. The array keys are used to identify the device
|
*/
|
||||||
| and the array values are used to set the actual name of the item.
|
|
||||||
*/
|
|
||||||
public $platforms = [
|
public $platforms = [
|
||||||
'windows nt 10.0' => 'Windows 10',
|
'windows nt 10.0' => 'Windows 10',
|
||||||
'windows nt 6.3' => 'Windows 8.1',
|
'windows nt 6.3' => 'Windows 8.1',
|
||||||
|
@ -60,12 +67,21 @@ class UserAgents extends BaseConfig
|
||||||
'symbian' => 'Symbian OS',
|
'symbian' => 'Symbian OS',
|
||||||
];
|
];
|
||||||
|
|
||||||
// The order of this array should NOT be changed. Many browsers return
|
/**
|
||||||
// multiple browser types so we want to identify the sub-type first.
|
* -------------------------------------------------------------------
|
||||||
|
* Browsers
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The order of this array should NOT be changed. Many browsers return
|
||||||
|
* multiple browser types so we want to identify the subtype first.
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
public $browsers = [
|
public $browsers = [
|
||||||
'OPR' => 'Opera',
|
'OPR' => 'Opera',
|
||||||
'Flock' => 'Flock',
|
'Flock' => 'Flock',
|
||||||
'Edge' => 'Spartan',
|
'Edge' => 'Spartan',
|
||||||
|
'Edg' => 'Edge',
|
||||||
'Chrome' => 'Chrome',
|
'Chrome' => 'Chrome',
|
||||||
// Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
|
// Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
|
||||||
'Opera.*?Version' => 'Opera',
|
'Opera.*?Version' => 'Opera',
|
||||||
|
@ -95,6 +111,13 @@ class UserAgents extends BaseConfig
|
||||||
'Vivaldi' => 'Vivaldi',
|
'Vivaldi' => 'Vivaldi',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
* Mobiles
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
public $mobiles = [
|
public $mobiles = [
|
||||||
// legacy array, old values commented out
|
// legacy array, old values commented out
|
||||||
'mobileexplorer' => 'Mobile Explorer',
|
'mobileexplorer' => 'Mobile Explorer',
|
||||||
|
@ -195,7 +218,15 @@ class UserAgents extends BaseConfig
|
||||||
'cellphone' => 'Generic Mobile',
|
'cellphone' => 'Generic Mobile',
|
||||||
];
|
];
|
||||||
|
|
||||||
// There are hundreds of bots but these are the most common.
|
/**
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
* Robots
|
||||||
|
* -------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* There are hundred of bots but these are the most common.
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
public $robots = [
|
public $robots = [
|
||||||
'googlebot' => 'Googlebot',
|
'googlebot' => 'Googlebot',
|
||||||
'msnbot' => 'MSNBot',
|
'msnbot' => 'MSNBot',
|
||||||
|
|
|
@ -2,6 +2,14 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
|
use App\Validation\FileRules as AppFileRules;
|
||||||
|
use App\Validation\Rules as AppRules;
|
||||||
|
use CodeIgniter\Validation\CreditCardRules;
|
||||||
|
use CodeIgniter\Validation\FileRules;
|
||||||
|
use CodeIgniter\Validation\FormatRules;
|
||||||
|
use CodeIgniter\Validation\Rules;
|
||||||
|
use Myth\Auth\Authentication\Passwords\ValidationRules as PasswordRules;
|
||||||
|
|
||||||
class Validation
|
class Validation
|
||||||
{
|
{
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
@ -12,22 +20,23 @@ class Validation
|
||||||
* Stores the classes that contain the
|
* Stores the classes that contain the
|
||||||
* rules that are available.
|
* rules that are available.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
public $ruleSets = [
|
public $ruleSets = [
|
||||||
\CodeIgniter\Validation\Rules::class,
|
Rules::class,
|
||||||
\CodeIgniter\Validation\FormatRules::class,
|
FormatRules::class,
|
||||||
\CodeIgniter\Validation\CreditCardRules::class,
|
FileRules::class,
|
||||||
\App\Validation\Rules::class,
|
CreditCardRules::class,
|
||||||
\App\Validation\FileRules::class,
|
AppRules::class,
|
||||||
\Myth\Auth\Authentication\Passwords\ValidationRules::class,
|
AppFileRules::class,
|
||||||
|
PasswordRules::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the views that are used to display the
|
* Specifies the views that are used to display the
|
||||||
* errors.
|
* errors.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array<string, string>
|
||||||
*/
|
*/
|
||||||
public $templates = [
|
public $templates = [
|
||||||
'list' => 'CodeIgniter\Validation\Views\list',
|
'list' => 'CodeIgniter\Validation\Views\list',
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
namespace Config;
|
namespace Config;
|
||||||
|
|
||||||
class View extends \CodeIgniter\Config\View
|
use CodeIgniter\Config\View as BaseView;
|
||||||
|
|
||||||
|
class View extends BaseView
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* When false, the view method will clear the data between each
|
* When false, the view method will clear the data between each
|
||||||
|
@ -11,6 +13,8 @@ class View extends \CodeIgniter\Config\View
|
||||||
* to each view. You might prefer to have the data stick around between
|
* to each view. You might prefer to have the data stick around between
|
||||||
* calls so that it is available to all views. If that is the case,
|
* calls so that it is available to all views. If that is the case,
|
||||||
* set $saveData to true.
|
* set $saveData to true.
|
||||||
|
*
|
||||||
|
* @var boolean
|
||||||
*/
|
*/
|
||||||
public $saveData = true;
|
public $saveData = true;
|
||||||
|
|
||||||
|
@ -24,6 +28,8 @@ class View extends \CodeIgniter\Config\View
|
||||||
* Examples:
|
* Examples:
|
||||||
* { title|esc(js) }
|
* { title|esc(js) }
|
||||||
* { created_on|date(Y-m-d)|esc(attr) }
|
* { created_on|date(Y-m-d)|esc(attr) }
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
*/
|
*/
|
||||||
public $filters = [];
|
public $filters = [];
|
||||||
|
|
||||||
|
@ -31,6 +37,8 @@ class View extends \CodeIgniter\Config\View
|
||||||
* Parser Plugins provide a way to extend the functionality provided
|
* Parser Plugins provide a way to extend the functionality provided
|
||||||
* by the core Parser by creating aliases that will be replaced with
|
* by the core Parser by creating aliases that will be replaced with
|
||||||
* any callable. Can be single or tag pair.
|
* any callable. Can be single or tag pair.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
*/
|
*/
|
||||||
public $plugins = [];
|
public $plugins = [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Controllers;
|
||||||
|
|
||||||
|
class Actor extends \ActivityPub\Controllers\ActorController
|
||||||
|
{
|
||||||
|
public function follow()
|
||||||
|
{
|
||||||
|
helper(['form', 'components', 'svg']);
|
||||||
|
$data = [
|
||||||
|
'actor' => $this->actor,
|
||||||
|
];
|
||||||
|
|
||||||
|
return view('podcast/follow', $data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
namespace App\Controllers\Admin;
|
namespace App\Controllers\Admin;
|
||||||
|
|
||||||
|
use CodeIgniter\Controller;
|
||||||
|
use CodeIgniter\HTTP\RequestInterface;
|
||||||
|
use CodeIgniter\HTTP\ResponseInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BaseController
|
* Class BaseController
|
||||||
*
|
*
|
||||||
|
@ -11,12 +16,8 @@ namespace App\Controllers\Admin;
|
||||||
* class Home extends BaseController
|
* class Home extends BaseController
|
||||||
*
|
*
|
||||||
* For security be sure to declare any new methods as protected or private.
|
* For security be sure to declare any new methods as protected or private.
|
||||||
*
|
|
||||||
* @package CodeIgniter
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use CodeIgniter\Controller;
|
|
||||||
|
|
||||||
class BaseController extends Controller
|
class BaseController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -30,11 +31,15 @@ class BaseController extends Controller
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @param LoggerInterface $logger
|
||||||
*/
|
*/
|
||||||
public function initController(
|
public function initController(
|
||||||
\CodeIgniter\HTTP\RequestInterface $request,
|
RequestInterface $request,
|
||||||
\CodeIgniter\HTTP\ResponseInterface $response,
|
ResponseInterface $response,
|
||||||
\Psr\Log\LoggerInterface $logger
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
// Do Not Edit This Line
|
// Do Not Edit This Line
|
||||||
parent::initController($request, $response, $logger);
|
parent::initController($request, $response, $logger);
|
||||||
|
@ -42,7 +47,6 @@ class BaseController extends Controller
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// Preload any models, libraries, etc, here.
|
// Preload any models, libraries, etc, here.
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// E.g.:
|
// E.g.: $this->session = \Config\Services::session();
|
||||||
// $this->session = \Config\Services::session();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
|
|
||||||
namespace App\Controllers\Admin;
|
namespace App\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Entities\Note;
|
||||||
use App\Models\EpisodeModel;
|
use App\Models\EpisodeModel;
|
||||||
|
use App\Models\NoteModel;
|
||||||
use App\Models\PodcastModel;
|
use App\Models\PodcastModel;
|
||||||
use App\Models\SoundbiteModel;
|
use App\Models\SoundbiteModel;
|
||||||
use CodeIgniter\I18n\Time;
|
use CodeIgniter\I18n\Time;
|
||||||
|
@ -32,7 +34,11 @@ class Episode extends BaseController
|
||||||
|
|
||||||
public function _remap($method, ...$params)
|
public function _remap($method, ...$params)
|
||||||
{
|
{
|
||||||
$this->podcast = (new PodcastModel())->getPodcastById($params[0]);
|
if (
|
||||||
|
!($this->podcast = (new PodcastModel())->getPodcastById($params[0]))
|
||||||
|
) {
|
||||||
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
if (count($params) > 1) {
|
if (count($params) > 1) {
|
||||||
if (
|
if (
|
||||||
|
@ -107,7 +113,6 @@ class Episode extends BaseController
|
||||||
'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
||||||
'transcript' => 'ext_in[transcript,txt,html,srt,json]',
|
'transcript' => 'ext_in[transcript,txt,html,srt,json]',
|
||||||
'chapters' => 'ext_in[chapters,json]',
|
'chapters' => 'ext_in[chapters,json]',
|
||||||
'publication_date' => 'valid_date[Y-m-d H:i]|permit_empty',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!$this->validate($rules)) {
|
if (!$this->validate($rules)) {
|
||||||
|
@ -117,7 +122,6 @@ class Episode extends BaseController
|
||||||
->with('errors', $this->validator->getErrors());
|
->with('errors', $this->validator->getErrors());
|
||||||
}
|
}
|
||||||
|
|
||||||
$publicationDate = $this->request->getPost('publication_date');
|
|
||||||
$newEpisode = new \App\Entities\Episode([
|
$newEpisode = new \App\Entities\Episode([
|
||||||
'podcast_id' => $this->podcast->id,
|
'podcast_id' => $this->podcast->id,
|
||||||
'title' => $this->request->getPost('title'),
|
'title' => $this->request->getPost('title'),
|
||||||
|
@ -142,15 +146,9 @@ class Episode extends BaseController
|
||||||
'type' => $this->request->getPost('type'),
|
'type' => $this->request->getPost('type'),
|
||||||
'is_blocked' => $this->request->getPost('block') == 'yes',
|
'is_blocked' => $this->request->getPost('block') == 'yes',
|
||||||
'custom_rss_string' => $this->request->getPost('custom_rss'),
|
'custom_rss_string' => $this->request->getPost('custom_rss'),
|
||||||
'created_by' => user(),
|
'created_by' => user()->id,
|
||||||
'updated_by' => user(),
|
'updated_by' => user()->id,
|
||||||
'published_at' => $publicationDate
|
'published_at' => null,
|
||||||
? Time::createFromFormat(
|
|
||||||
'Y-m-d H:i',
|
|
||||||
$publicationDate,
|
|
||||||
$this->request->getPost('client_timezone')
|
|
||||||
)->setTimezone('UTC')
|
|
||||||
: null,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$episodeModel = new EpisodeModel();
|
$episodeModel = new EpisodeModel();
|
||||||
|
@ -167,7 +165,7 @@ class Episode extends BaseController
|
||||||
|
|
||||||
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
|
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
|
||||||
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
|
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
|
||||||
'description_footer'
|
'description_footer',
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!$podcastModel->update($this->podcast->id, $this->podcast)) {
|
if (!$podcastModel->update($this->podcast->id, $this->podcast)) {
|
||||||
|
@ -209,7 +207,6 @@ class Episode extends BaseController
|
||||||
'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
|
||||||
'transcript' => 'ext_in[transcript,txt,html,srt,json]',
|
'transcript' => 'ext_in[transcript,txt,html,srt,json]',
|
||||||
'chapters' => 'ext_in[chapters,json]',
|
'chapters' => 'ext_in[chapters,json]',
|
||||||
'publication_date' => 'valid_date[Y-m-d H:i]|permit_empty',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!$this->validate($rules)) {
|
if (!$this->validate($rules)) {
|
||||||
|
@ -222,7 +219,7 @@ class Episode extends BaseController
|
||||||
$this->episode->title = $this->request->getPost('title');
|
$this->episode->title = $this->request->getPost('title');
|
||||||
$this->episode->slug = $this->request->getPost('slug');
|
$this->episode->slug = $this->request->getPost('slug');
|
||||||
$this->episode->description_markdown = $this->request->getPost(
|
$this->episode->description_markdown = $this->request->getPost(
|
||||||
'description'
|
'description',
|
||||||
);
|
);
|
||||||
$this->episode->location = $this->request->getPost('location_name');
|
$this->episode->location = $this->request->getPost('location_name');
|
||||||
$this->episode->parental_advisory =
|
$this->episode->parental_advisory =
|
||||||
|
@ -238,19 +235,10 @@ class Episode extends BaseController
|
||||||
$this->episode->type = $this->request->getPost('type');
|
$this->episode->type = $this->request->getPost('type');
|
||||||
$this->episode->is_blocked = $this->request->getPost('block') == 'yes';
|
$this->episode->is_blocked = $this->request->getPost('block') == 'yes';
|
||||||
$this->episode->custom_rss_string = $this->request->getPost(
|
$this->episode->custom_rss_string = $this->request->getPost(
|
||||||
'custom_rss'
|
'custom_rss',
|
||||||
);
|
);
|
||||||
|
|
||||||
$publicationDate = $this->request->getPost('publication_date');
|
$this->episode->updated_by = user()->id;
|
||||||
$this->episode->published_at = $publicationDate
|
|
||||||
? Time::createFromFormat(
|
|
||||||
'Y-m-d H:i',
|
|
||||||
$publicationDate,
|
|
||||||
$this->request->getPost('client_timezone')
|
|
||||||
)->setTimezone('UTC')
|
|
||||||
: null;
|
|
||||||
|
|
||||||
$this->episode->updated_by = user();
|
|
||||||
|
|
||||||
$enclosure = $this->request->getFile('enclosure');
|
$enclosure = $this->request->getFile('enclosure');
|
||||||
if ($enclosure->isValid()) {
|
if ($enclosure->isValid()) {
|
||||||
|
@ -280,7 +268,7 @@ class Episode extends BaseController
|
||||||
|
|
||||||
// update podcast's episode_description_footer_markdown if changed
|
// update podcast's episode_description_footer_markdown if changed
|
||||||
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
|
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
|
||||||
'description_footer'
|
'description_footer',
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
|
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
|
||||||
|
@ -333,6 +321,271 @@ class Episode extends BaseController
|
||||||
return redirect()->back();
|
return redirect()->back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function publish()
|
||||||
|
{
|
||||||
|
if ($this->episode->publication_status === 'not_published') {
|
||||||
|
helper(['form']);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'podcast' => $this->podcast,
|
||||||
|
'episode' => $this->episode,
|
||||||
|
];
|
||||||
|
|
||||||
|
replace_breadcrumb_params([
|
||||||
|
0 => $this->podcast->title,
|
||||||
|
1 => $this->episode->title,
|
||||||
|
]);
|
||||||
|
return view('admin/episode/publish', $data);
|
||||||
|
} else {
|
||||||
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attemptPublish()
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'publication_method' => 'required',
|
||||||
|
'scheduled_publication_date' =>
|
||||||
|
'valid_date[Y-m-d H:i]|permit_empty',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$this->validate($rules)) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $this->validator->getErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = \Config\Database::connect();
|
||||||
|
$db->transStart();
|
||||||
|
|
||||||
|
$newNote = new Note([
|
||||||
|
'actor_id' => $this->podcast->actor_id,
|
||||||
|
'episode_id' => $this->episode->id,
|
||||||
|
'message' => $this->request->getPost('message'),
|
||||||
|
'created_by' => user_id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$publishMethod = $this->request->getPost('publication_method');
|
||||||
|
if ($publishMethod === 'schedule') {
|
||||||
|
$scheduledPublicationDate = $this->request->getPost(
|
||||||
|
'scheduled_publication_date',
|
||||||
|
);
|
||||||
|
if ($scheduledPublicationDate) {
|
||||||
|
$scheduledDateUTC = Time::createFromFormat(
|
||||||
|
'Y-m-d H:i',
|
||||||
|
$scheduledPublicationDate,
|
||||||
|
$this->request->getPost('client_timezone'),
|
||||||
|
)->setTimezone('UTC');
|
||||||
|
$this->episode->published_at = $scheduledDateUTC;
|
||||||
|
$newNote->published_at = $scheduledDateUTC;
|
||||||
|
} else {
|
||||||
|
$db->transRollback();
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('error', 'Schedule date must be set!');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$dateNow = Time::now();
|
||||||
|
$this->episode->published_at = $dateNow;
|
||||||
|
$newNote->published_at = $dateNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
$noteModel = new NoteModel();
|
||||||
|
if (!$noteModel->addNote($newNote)) {
|
||||||
|
$db->transRollback();
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $noteModel->errors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$episodeModel = new EpisodeModel();
|
||||||
|
if (!$episodeModel->update($this->episode->id, $this->episode)) {
|
||||||
|
$db->transRollback();
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $episodeModel->errors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->transComplete();
|
||||||
|
|
||||||
|
return redirect()->route('episode-view', [
|
||||||
|
$this->podcast->id,
|
||||||
|
$this->episode->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function publishEdit()
|
||||||
|
{
|
||||||
|
if ($this->episode->publication_status === 'scheduled') {
|
||||||
|
helper(['form']);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'podcast' => $this->podcast,
|
||||||
|
'episode' => $this->episode,
|
||||||
|
'note' => (new NoteModel())
|
||||||
|
->where([
|
||||||
|
'actor_id' => $this->podcast->actor_id,
|
||||||
|
'episode_id' => $this->episode->id,
|
||||||
|
])
|
||||||
|
->first(),
|
||||||
|
];
|
||||||
|
|
||||||
|
replace_breadcrumb_params([
|
||||||
|
0 => $this->podcast->title,
|
||||||
|
1 => $this->episode->title,
|
||||||
|
]);
|
||||||
|
return view('admin/episode/publish_edit', $data);
|
||||||
|
} else {
|
||||||
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attemptPublishEdit()
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'note_id' => 'required',
|
||||||
|
'publication_method' => 'required',
|
||||||
|
'scheduled_publication_date' =>
|
||||||
|
'valid_date[Y-m-d H:i]|permit_empty',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$this->validate($rules)) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $this->validator->getErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = \Config\Database::connect();
|
||||||
|
$db->transStart();
|
||||||
|
|
||||||
|
$note = (new NoteModel())->getNoteById(
|
||||||
|
$this->request->getPost('note_id'),
|
||||||
|
);
|
||||||
|
$note->message = $this->request->getPost('message');
|
||||||
|
|
||||||
|
$publishMethod = $this->request->getPost('publication_method');
|
||||||
|
if ($publishMethod === 'schedule') {
|
||||||
|
$scheduledPublicationDate = $this->request->getPost(
|
||||||
|
'scheduled_publication_date',
|
||||||
|
);
|
||||||
|
if ($scheduledPublicationDate) {
|
||||||
|
$scheduledDateUTC = Time::createFromFormat(
|
||||||
|
'Y-m-d H:i',
|
||||||
|
$scheduledPublicationDate,
|
||||||
|
$this->request->getPost('client_timezone'),
|
||||||
|
)->setTimezone('UTC');
|
||||||
|
$this->episode->published_at = $scheduledDateUTC;
|
||||||
|
$note->published_at = $scheduledDateUTC;
|
||||||
|
} else {
|
||||||
|
$db->transRollback();
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('error', 'Schedule date must be set!');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$dateNow = Time::now();
|
||||||
|
$this->episode->published_at = $dateNow;
|
||||||
|
$note->published_at = $dateNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
$noteModel = new NoteModel();
|
||||||
|
if (!$noteModel->editNote($note)) {
|
||||||
|
$db->transRollback();
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $noteModel->errors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$episodeModel = new EpisodeModel();
|
||||||
|
if (!$episodeModel->update($this->episode->id, $this->episode)) {
|
||||||
|
$db->transRollback();
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $episodeModel->errors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->transComplete();
|
||||||
|
|
||||||
|
return redirect()->route('episode-view', [
|
||||||
|
$this->podcast->id,
|
||||||
|
$this->episode->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unpublish()
|
||||||
|
{
|
||||||
|
if ($this->episode->publication_status === 'published') {
|
||||||
|
helper(['form']);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'podcast' => $this->podcast,
|
||||||
|
'episode' => $this->episode,
|
||||||
|
];
|
||||||
|
|
||||||
|
replace_breadcrumb_params([
|
||||||
|
0 => $this->podcast->title,
|
||||||
|
1 => $this->episode->title,
|
||||||
|
]);
|
||||||
|
return view('admin/episode/unpublish', $data);
|
||||||
|
} else {
|
||||||
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attemptUnpublish()
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'understand' => 'required',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$this->validate($rules)) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $this->validator->getErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = \Config\Database::connect();
|
||||||
|
|
||||||
|
$db->transStart();
|
||||||
|
|
||||||
|
$allNotesLinkedToEpisode = (new NoteModel())
|
||||||
|
->where([
|
||||||
|
'episode_id' => $this->episode->id,
|
||||||
|
])
|
||||||
|
->findAll();
|
||||||
|
foreach ($allNotesLinkedToEpisode as $note) {
|
||||||
|
(new NoteModel())->removeNote($note);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set episode published_at to null to unpublish
|
||||||
|
$this->episode->published_at = null;
|
||||||
|
|
||||||
|
$episodeModel = new EpisodeModel();
|
||||||
|
if (!$episodeModel->update($this->episode->id, $this->episode)) {
|
||||||
|
$db->transRollback();
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $episodeModel->errors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->transComplete();
|
||||||
|
|
||||||
|
return redirect()->route('episode-view', [
|
||||||
|
$this->podcast->id,
|
||||||
|
$this->episode->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function delete()
|
public function delete()
|
||||||
{
|
{
|
||||||
(new EpisodeModel())->delete($this->episode->id);
|
(new EpisodeModel())->delete($this->episode->id);
|
||||||
|
@ -416,7 +669,7 @@ class Episode extends BaseController
|
||||||
(new SoundbiteModel())->deleteSoundbite(
|
(new SoundbiteModel())->deleteSoundbite(
|
||||||
$this->podcast->id,
|
$this->podcast->id,
|
||||||
$this->episode->id,
|
$this->episode->id,
|
||||||
$soundbiteId
|
$soundbiteId,
|
||||||
);
|
);
|
||||||
|
|
||||||
return redirect()->route('soundbites-edit', [
|
return redirect()->route('soundbites-edit', [
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Controllers\Admin;
|
||||||
|
|
||||||
|
use ActivityPub\Models\BlockedDomainModel;
|
||||||
|
|
||||||
|
class Fediverse extends BaseController
|
||||||
|
{
|
||||||
|
public function dashboard()
|
||||||
|
{
|
||||||
|
return view('admin/fediverse/dashboard');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function blockedActors()
|
||||||
|
{
|
||||||
|
helper(['form']);
|
||||||
|
|
||||||
|
$blockedActors = model('ActorModel')->getBlockedActors();
|
||||||
|
|
||||||
|
return view('admin/fediverse/blocked_actors', [
|
||||||
|
'blockedActors' => $blockedActors,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function blockedDomains()
|
||||||
|
{
|
||||||
|
helper(['form']);
|
||||||
|
|
||||||
|
$blockedDomains = model('BlockedDomainModel')->getBlockedDomains();
|
||||||
|
|
||||||
|
return view('admin/fediverse/blocked_domains', [
|
||||||
|
'blockedDomains' => $blockedDomains,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -125,7 +125,7 @@ class Person extends BaseController
|
||||||
$this->person->image = $image;
|
$this->person->image = $image;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->updated_by = user();
|
$this->updated_by = user()->id;
|
||||||
|
|
||||||
$personModel = new PersonModel();
|
$personModel = new PersonModel();
|
||||||
if (!$personModel->update($this->person->id, $this->person)) {
|
if (!$personModel->update($this->person->id, $this->person)) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Podcast extends BaseController
|
||||||
if (count($params) > 0) {
|
if (count($params) > 0) {
|
||||||
if (
|
if (
|
||||||
!($this->podcast = (new PodcastModel())->getPodcastById(
|
!($this->podcast = (new PodcastModel())->getPodcastById(
|
||||||
$params[0]
|
$params[0],
|
||||||
))
|
))
|
||||||
) {
|
) {
|
||||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
|
@ -124,7 +124,7 @@ class Podcast extends BaseController
|
||||||
'languageOptions' => $languageOptions,
|
'languageOptions' => $languageOptions,
|
||||||
'categoryOptions' => $categoryOptions,
|
'categoryOptions' => $categoryOptions,
|
||||||
'browserLang' => get_browser_language(
|
'browserLang' => get_browser_language(
|
||||||
$this->request->getServer('HTTP_ACCEPT_LANGUAGE')
|
$this->request->getServer('HTTP_ACCEPT_LANGUAGE'),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -170,8 +170,8 @@ class Podcast extends BaseController
|
||||||
'is_blocked' => $this->request->getPost('block') === 'yes',
|
'is_blocked' => $this->request->getPost('block') === 'yes',
|
||||||
'is_completed' => $this->request->getPost('complete') === 'yes',
|
'is_completed' => $this->request->getPost('complete') === 'yes',
|
||||||
'is_locked' => $this->request->getPost('lock') === 'yes',
|
'is_locked' => $this->request->getPost('lock') === 'yes',
|
||||||
'created_by' => user(),
|
'created_by' => user()->id,
|
||||||
'updated_by' => user(),
|
'updated_by' => user()->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$podcastModel = new PodcastModel();
|
$podcastModel = new PodcastModel();
|
||||||
|
@ -193,15 +193,19 @@ class Podcast extends BaseController
|
||||||
$podcastModel->addPodcastContributor(
|
$podcastModel->addPodcastContributor(
|
||||||
user()->id,
|
user()->id,
|
||||||
$newPodcastId,
|
$newPodcastId,
|
||||||
$podcastAdminGroup->id
|
$podcastAdminGroup->id,
|
||||||
);
|
);
|
||||||
|
|
||||||
// set Podcast categories
|
// set Podcast categories
|
||||||
(new CategoryModel())->setPodcastCategories(
|
(new CategoryModel())->setPodcastCategories(
|
||||||
$newPodcastId,
|
$newPodcastId,
|
||||||
$this->request->getPost('other_categories')
|
$this->request->getPost('other_categories'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// set interact as the newly created podcast actor
|
||||||
|
$createdPodcast = (new PodcastModel())->getPodcastById($newPodcastId);
|
||||||
|
set_interact_as_actor($createdPodcast->actor_id);
|
||||||
|
|
||||||
$db->transComplete();
|
$db->transComplete();
|
||||||
|
|
||||||
return redirect()->route('podcast-view', [$newPodcastId]);
|
return redirect()->route('podcast-view', [$newPodcastId]);
|
||||||
|
@ -239,9 +243,8 @@ class Podcast extends BaseController
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->podcast->title = $this->request->getPost('title');
|
$this->podcast->title = $this->request->getPost('title');
|
||||||
$this->podcast->name = $this->request->getPost('name');
|
|
||||||
$this->podcast->description_markdown = $this->request->getPost(
|
$this->podcast->description_markdown = $this->request->getPost(
|
||||||
'description'
|
'description',
|
||||||
);
|
);
|
||||||
|
|
||||||
$image = $this->request->getFile('image');
|
$image = $this->request->getFile('image');
|
||||||
|
@ -261,10 +264,10 @@ class Podcast extends BaseController
|
||||||
$this->podcast->copyright = $this->request->getPost('copyright');
|
$this->podcast->copyright = $this->request->getPost('copyright');
|
||||||
$this->podcast->location = $this->request->getPost('location_name');
|
$this->podcast->location = $this->request->getPost('location_name');
|
||||||
$this->podcast->payment_pointer = $this->request->getPost(
|
$this->podcast->payment_pointer = $this->request->getPost(
|
||||||
'payment_pointer'
|
'payment_pointer',
|
||||||
);
|
);
|
||||||
$this->podcast->custom_rss_string = $this->request->getPost(
|
$this->podcast->custom_rss_string = $this->request->getPost(
|
||||||
'custom_rss'
|
'custom_rss',
|
||||||
);
|
);
|
||||||
$this->podcast->partner_id = $this->request->getPost('partner_id');
|
$this->podcast->partner_id = $this->request->getPost('partner_id');
|
||||||
$this->podcast->partner_link_url = $this->request->getPost(
|
$this->podcast->partner_link_url = $this->request->getPost(
|
||||||
|
@ -277,7 +280,7 @@ class Podcast extends BaseController
|
||||||
$this->podcast->is_completed =
|
$this->podcast->is_completed =
|
||||||
$this->request->getPost('complete') === 'yes';
|
$this->request->getPost('complete') === 'yes';
|
||||||
$this->podcast->is_locked = $this->request->getPost('lock') === 'yes';
|
$this->podcast->is_locked = $this->request->getPost('lock') === 'yes';
|
||||||
$this->updated_by = user();
|
$this->updated_by = user()->id;
|
||||||
|
|
||||||
$db = \Config\Database::connect();
|
$db = \Config\Database::connect();
|
||||||
$db->transStart();
|
$db->transStart();
|
||||||
|
@ -294,7 +297,7 @@ class Podcast extends BaseController
|
||||||
// set Podcast categories
|
// set Podcast categories
|
||||||
(new CategoryModel())->setPodcastCategories(
|
(new CategoryModel())->setPodcastCategories(
|
||||||
$this->podcast->id,
|
$this->podcast->id,
|
||||||
$this->request->getPost('other_categories')
|
$this->request->getPost('other_categories'),
|
||||||
);
|
);
|
||||||
|
|
||||||
$db->transComplete();
|
$db->transComplete();
|
||||||
|
|
|
@ -31,7 +31,7 @@ class PodcastImport extends BaseController
|
||||||
if (count($params) > 0) {
|
if (count($params) > 0) {
|
||||||
if (
|
if (
|
||||||
!($this->podcast = (new PodcastModel())->getPodcastById(
|
!($this->podcast = (new PodcastModel())->getPodcastById(
|
||||||
$params[0]
|
$params[0],
|
||||||
))
|
))
|
||||||
) {
|
) {
|
||||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
|
@ -52,7 +52,7 @@ class PodcastImport extends BaseController
|
||||||
'languageOptions' => $languageOptions,
|
'languageOptions' => $languageOptions,
|
||||||
'categoryOptions' => $categoryOptions,
|
'categoryOptions' => $categoryOptions,
|
||||||
'browserLang' => get_browser_language(
|
'browserLang' => get_browser_language(
|
||||||
$this->request->getServer('HTTP_ACCEPT_LANGUAGE')
|
$this->request->getServer('HTTP_ACCEPT_LANGUAGE'),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ class PodcastImport extends BaseController
|
||||||
try {
|
try {
|
||||||
ini_set('user_agent', 'Castopod/' . CP_VERSION);
|
ini_set('user_agent', 'Castopod/' . CP_VERSION);
|
||||||
$feed = simplexml_load_file(
|
$feed = simplexml_load_file(
|
||||||
$this->request->getPost('imported_feed_url')
|
$this->request->getPost('imported_feed_url'),
|
||||||
);
|
);
|
||||||
} catch (\ErrorException $ex) {
|
} catch (\ErrorException $ex) {
|
||||||
return redirect()
|
return redirect()
|
||||||
|
@ -94,13 +94,13 @@ class PodcastImport extends BaseController
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
$nsItunes = $feed->channel[0]->children(
|
$nsItunes = $feed->channel[0]->children(
|
||||||
'http://www.itunes.com/dtds/podcast-1.0.dtd'
|
'http://www.itunes.com/dtds/podcast-1.0.dtd',
|
||||||
);
|
);
|
||||||
$nsPodcast = $feed->channel[0]->children(
|
$nsPodcast = $feed->channel[0]->children(
|
||||||
'https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md'
|
'https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md',
|
||||||
);
|
);
|
||||||
$nsContent = $feed->channel[0]->children(
|
$nsContent = $feed->channel[0]->children(
|
||||||
'http://purl.org/rss/1.0/modules/content/'
|
'http://purl.org/rss/1.0/modules/content/',
|
||||||
);
|
);
|
||||||
|
|
||||||
if ((string) $nsPodcast->locked === 'yes') {
|
if ((string) $nsPodcast->locked === 'yes') {
|
||||||
|
@ -112,28 +112,30 @@ class PodcastImport extends BaseController
|
||||||
|
|
||||||
$converter = new HtmlConverter();
|
$converter = new HtmlConverter();
|
||||||
|
|
||||||
$channelDescriptionHtml = $feed->channel[0]->description;
|
$channelDescriptionHtml = (string) $feed->channel[0]->description;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$podcast = new \App\Entities\Podcast([
|
$podcast = new \App\Entities\Podcast([
|
||||||
'name' => $this->request->getPost('name'),
|
'name' => $this->request->getPost('name'),
|
||||||
'imported_feed_url' => $this->request->getPost(
|
'imported_feed_url' => $this->request->getPost(
|
||||||
'imported_feed_url'
|
'imported_feed_url',
|
||||||
),
|
),
|
||||||
'new_feed_url' => base_url(
|
'new_feed_url' => base_url(
|
||||||
route_to('podcast_feed', $this->request->getPost('name'))
|
route_to('podcast_feed', $this->request->getPost('name')),
|
||||||
),
|
),
|
||||||
'title' => $feed->channel[0]->title,
|
'title' => (string) $feed->channel[0]->title,
|
||||||
'description_markdown' => $converter->convert(
|
'description_markdown' => $converter->convert(
|
||||||
$channelDescriptionHtml
|
$channelDescriptionHtml,
|
||||||
),
|
),
|
||||||
'description_html' => $channelDescriptionHtml,
|
'description_html' => $channelDescriptionHtml,
|
||||||
'image' =>
|
'image' =>
|
||||||
$nsItunes->image && !empty($nsItunes->image->attributes())
|
$nsItunes->image && !empty($nsItunes->image->attributes())
|
||||||
? download_file($nsItunes->image->attributes())
|
? download_file((string) $nsItunes->image->attributes())
|
||||||
: ($feed->channel[0]->image &&
|
: ($feed->channel[0]->image &&
|
||||||
!empty($feed->channel[0]->image->url)
|
!empty($feed->channel[0]->image->url)
|
||||||
? download_file($feed->channel[0]->image->url)
|
? download_file(
|
||||||
|
(string) $feed->channel[0]->image->url,
|
||||||
|
)
|
||||||
: null),
|
: null),
|
||||||
'language_code' => $this->request->getPost('language'),
|
'language_code' => $this->request->getPost('language'),
|
||||||
'category_id' => $this->request->getPost('category'),
|
'category_id' => $this->request->getPost('category'),
|
||||||
|
@ -144,11 +146,11 @@ class PodcastImport extends BaseController
|
||||||
: (in_array($nsItunes->explicit, ['no', 'false'])
|
: (in_array($nsItunes->explicit, ['no', 'false'])
|
||||||
? 'clean'
|
? 'clean'
|
||||||
: null)),
|
: null)),
|
||||||
'owner_name' => $nsItunes->owner->name,
|
'owner_name' => (string) $nsItunes->owner->name,
|
||||||
'owner_email' => $nsItunes->owner->email,
|
'owner_email' => (string) $nsItunes->owner->email,
|
||||||
'publisher' => $nsItunes->author,
|
'publisher' => (string) $nsItunes->author,
|
||||||
'type' => empty($nsItunes->type) ? 'episodic' : $nsItunes->type,
|
'type' => empty($nsItunes->type) ? 'episodic' : $nsItunes->type,
|
||||||
'copyright' => $feed->channel[0]->copyright,
|
'copyright' => (string) $feed->channel[0]->copyright,
|
||||||
'is_blocked' => empty($nsItunes->block)
|
'is_blocked' => empty($nsItunes->block)
|
||||||
? false
|
? false
|
||||||
: $nsItunes->block === 'yes',
|
: $nsItunes->block === 'yes',
|
||||||
|
@ -157,19 +159,19 @@ class PodcastImport extends BaseController
|
||||||
: $nsItunes->complete === 'yes',
|
: $nsItunes->complete === 'yes',
|
||||||
'location_name' => !$nsPodcast->location
|
'location_name' => !$nsPodcast->location
|
||||||
? null
|
? null
|
||||||
: $nsPodcast->location,
|
: (string) $nsPodcast->location,
|
||||||
'location_geo' =>
|
'location_geo' =>
|
||||||
!$nsPodcast->location ||
|
!$nsPodcast->location ||
|
||||||
empty($nsPodcast->location->attributes()['geo'])
|
empty($nsPodcast->location->attributes()['geo'])
|
||||||
? null
|
? null
|
||||||
: $nsPodcast->location->attributes()['geo'],
|
: (string) $nsPodcast->location->attributes()['geo'],
|
||||||
'location_osmid' =>
|
'location_osmid' =>
|
||||||
!$nsPodcast->location ||
|
!$nsPodcast->location ||
|
||||||
empty($nsPodcast->location->attributes()['osm'])
|
empty($nsPodcast->location->attributes()['osm'])
|
||||||
? null
|
? null
|
||||||
: $nsPodcast->location->attributes()['osm'],
|
: (string) $nsPodcast->location->attributes()['osm'],
|
||||||
'created_by' => user(),
|
'created_by' => user()->id,
|
||||||
'updated_by' => user(),
|
'updated_by' => user()->id,
|
||||||
]);
|
]);
|
||||||
} catch (\ErrorException $ex) {
|
} catch (\ErrorException $ex) {
|
||||||
return redirect()
|
return redirect()
|
||||||
|
@ -204,7 +206,7 @@ class PodcastImport extends BaseController
|
||||||
$podcastModel->addPodcastContributor(
|
$podcastModel->addPodcastContributor(
|
||||||
user()->id,
|
user()->id,
|
||||||
$newPodcastId,
|
$newPodcastId,
|
||||||
$podcastAdminGroup->id
|
$podcastAdminGroup->id,
|
||||||
);
|
);
|
||||||
|
|
||||||
$podcastsPlatformsData = [];
|
$podcastsPlatformsData = [];
|
||||||
|
@ -218,34 +220,21 @@ class PodcastImport extends BaseController
|
||||||
foreach ($platformType['elements'] as $platform) {
|
foreach ($platformType['elements'] as $platform) {
|
||||||
$platformLabel = $platform->attributes()['platform'];
|
$platformLabel = $platform->attributes()['platform'];
|
||||||
$platformSlug = slugify($platformLabel);
|
$platformSlug = slugify($platformLabel);
|
||||||
if (!$platformModel->getPlatform($platformSlug)) {
|
if ($platformModel->getPlatform($platformSlug)) {
|
||||||
if (
|
array_push($podcastsPlatformsData, [
|
||||||
!$platformModel->createPlatform(
|
'platform_slug' => $platformSlug,
|
||||||
$platformSlug,
|
'podcast_id' => $newPodcastId,
|
||||||
$platformType['name'],
|
'link_url' => $platform->attributes()['url'],
|
||||||
$platformLabel,
|
'link_content' => $platform->attributes()['id'],
|
||||||
''
|
'is_visible' => false,
|
||||||
)
|
]);
|
||||||
) {
|
|
||||||
return redirect()
|
|
||||||
->back()
|
|
||||||
->withInput()
|
|
||||||
->with('errors', $platformModel->errors());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
array_push($podcastsPlatformsData, [
|
|
||||||
'platform_slug' => $platformSlug,
|
|
||||||
'podcast_id' => $newPodcastId,
|
|
||||||
'link_url' => $platform->attributes()['url'],
|
|
||||||
'link_content' => $platform->attributes()['id'],
|
|
||||||
'is_visible' => false,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count($podcastsPlatformsData) > 1) {
|
if (count($podcastsPlatformsData) > 1) {
|
||||||
$platformModel->createPodcastPlatforms(
|
$platformModel->createPodcastPlatforms(
|
||||||
$newPodcastId,
|
$newPodcastId,
|
||||||
$podcastsPlatformsData
|
$podcastsPlatformsData,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +248,7 @@ class PodcastImport extends BaseController
|
||||||
!($newPersonId = $personModel->createPerson(
|
!($newPersonId = $personModel->createPerson(
|
||||||
$podcastPerson,
|
$podcastPerson,
|
||||||
$podcastPerson->attributes()['href'],
|
$podcastPerson->attributes()['href'],
|
||||||
$podcastPerson->attributes()['img']
|
$podcastPerson->attributes()['img'],
|
||||||
))
|
))
|
||||||
) {
|
) {
|
||||||
return redirect()
|
return redirect()
|
||||||
|
@ -312,19 +301,19 @@ class PodcastImport extends BaseController
|
||||||
$item = $feed->channel[0]->item[$numberItems - $itemNumber];
|
$item = $feed->channel[0]->item[$numberItems - $itemNumber];
|
||||||
|
|
||||||
$nsItunes = $item->children(
|
$nsItunes = $item->children(
|
||||||
'http://www.itunes.com/dtds/podcast-1.0.dtd'
|
'http://www.itunes.com/dtds/podcast-1.0.dtd',
|
||||||
);
|
);
|
||||||
$nsPodcast = $item->children(
|
$nsPodcast = $item->children(
|
||||||
'https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md'
|
'https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md',
|
||||||
);
|
);
|
||||||
$nsContent = $item->children(
|
$nsContent = $item->children(
|
||||||
'http://purl.org/rss/1.0/modules/content/'
|
'http://purl.org/rss/1.0/modules/content/',
|
||||||
);
|
);
|
||||||
|
|
||||||
$slug = slugify(
|
$slug = slugify(
|
||||||
$this->request->getPost('slug_field') === 'title'
|
$this->request->getPost('slug_field') === 'title'
|
||||||
? $item->title
|
? $item->title
|
||||||
: basename($item->link)
|
: basename($item->link),
|
||||||
);
|
);
|
||||||
if (in_array($slug, $slugs)) {
|
if (in_array($slug, $slugs)) {
|
||||||
$slugNumber = 2;
|
$slugNumber = 2;
|
||||||
|
@ -358,13 +347,15 @@ class PodcastImport extends BaseController
|
||||||
'slug' => $slug,
|
'slug' => $slug,
|
||||||
'enclosure' => download_file($item->enclosure->attributes()),
|
'enclosure' => download_file($item->enclosure->attributes()),
|
||||||
'description_markdown' => $converter->convert(
|
'description_markdown' => $converter->convert(
|
||||||
$itemDescriptionHtml
|
$itemDescriptionHtml,
|
||||||
),
|
),
|
||||||
'description_html' => $itemDescriptionHtml,
|
'description_html' => $itemDescriptionHtml,
|
||||||
'image' =>
|
'image' =>
|
||||||
!$nsItunes->image || empty($nsItunes->image->attributes())
|
!$nsItunes->image || empty($nsItunes->image->attributes())
|
||||||
? null
|
? null
|
||||||
: download_file($nsItunes->image->attributes()),
|
: download_file(
|
||||||
|
(string) $nsItunes->image->attributes(),
|
||||||
|
),
|
||||||
'parental_advisory' => empty($nsItunes->explicit)
|
'parental_advisory' => empty($nsItunes->explicit)
|
||||||
? null
|
? null
|
||||||
: (in_array($nsItunes->explicit, ['yes', 'true'])
|
: (in_array($nsItunes->explicit, ['yes', 'true'])
|
||||||
|
@ -404,8 +395,8 @@ class PodcastImport extends BaseController
|
||||||
empty($nsPodcast->location->attributes()['osm'])
|
empty($nsPodcast->location->attributes()['osm'])
|
||||||
? null
|
? null
|
||||||
: $nsPodcast->location->attributes()['osm'],
|
: $nsPodcast->location->attributes()['osm'],
|
||||||
'created_by' => user(),
|
'created_by' => user()->id,
|
||||||
'updated_by' => user(),
|
'updated_by' => user()->id,
|
||||||
'published_at' => strtotime($item->pubDate),
|
'published_at' => strtotime($item->pubDate),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -429,7 +420,7 @@ class PodcastImport extends BaseController
|
||||||
!($newPersonId = $personModel->createPerson(
|
!($newPersonId = $personModel->createPerson(
|
||||||
$episodePerson,
|
$episodePerson,
|
||||||
$episodePerson->attributes()['href'],
|
$episodePerson->attributes()['href'],
|
||||||
$episodePerson->attributes()['img']
|
$episodePerson->attributes()['img'],
|
||||||
))
|
))
|
||||||
) {
|
) {
|
||||||
return redirect()
|
return redirect()
|
||||||
|
@ -458,8 +449,8 @@ class PodcastImport extends BaseController
|
||||||
'person_group' => $personGroup['slug'],
|
'person_group' => $personGroup['slug'],
|
||||||
'person_role' => $personRole['slug'],
|
'person_role' => $personRole['slug'],
|
||||||
]);
|
]);
|
||||||
$episodePersonModel = new EpisodePersonModel();
|
|
||||||
|
|
||||||
|
$episodePersonModel = new EpisodePersonModel();
|
||||||
if (!$episodePersonModel->insert($newEpisodePerson)) {
|
if (!$episodePersonModel->insert($newEpisodePerson)) {
|
||||||
return redirect()
|
return redirect()
|
||||||
->back()
|
->back()
|
||||||
|
@ -469,6 +460,10 @@ class PodcastImport extends BaseController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set interact as the newly imported podcast actor
|
||||||
|
$importedPodcast = (new PodcastModel())->getPodcastById($newPodcastId);
|
||||||
|
set_interact_as_actor($importedPodcast->actor_id);
|
||||||
|
|
||||||
$db->transComplete();
|
$db->transComplete();
|
||||||
|
|
||||||
return redirect()->route('podcast-view', [$newPodcastId]);
|
return redirect()->route('podcast-view', [$newPodcastId]);
|
||||||
|
|
|
@ -55,7 +55,7 @@ class Auth extends \Myth\Auth\Controllers\AuthController
|
||||||
$allowedPostFields = array_merge(
|
$allowedPostFields = array_merge(
|
||||||
['password'],
|
['password'],
|
||||||
$this->config->validFields,
|
$this->config->validFields,
|
||||||
$this->config->personalFields
|
$this->config->personalFields,
|
||||||
);
|
);
|
||||||
$user = new User($this->request->getPost($allowedPostFields));
|
$user = new User($this->request->getPost($allowedPostFields));
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class Auth extends \Myth\Auth\Controllers\AuthController
|
||||||
->withInput()
|
->withInput()
|
||||||
->with(
|
->with(
|
||||||
'error',
|
'error',
|
||||||
$activator->error() ?? lang('Auth.unknownError')
|
$activator->error() ?? lang('Auth.unknownError'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ class Auth extends \Myth\Auth\Controllers\AuthController
|
||||||
$this->request->getPost('email'),
|
$this->request->getPost('email'),
|
||||||
$this->request->getPost('token'),
|
$this->request->getPost('token'),
|
||||||
$this->request->getIPAddress(),
|
$this->request->getIPAddress(),
|
||||||
(string) $this->request->getUserAgent()
|
(string) $this->request->getUserAgent(),
|
||||||
);
|
);
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
|
@ -172,4 +172,24 @@ class Auth extends \Myth\Auth\Controllers\AuthController
|
||||||
->route('login')
|
->route('login')
|
||||||
->with('message', lang('Auth.resetSuccess'));
|
->with('message', lang('Auth.resetSuccess'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function attemptInteractAsActor()
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'actor_id' => 'required|numeric',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$this->validate($rules)) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', service('validation')->getErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
helper('auth');
|
||||||
|
|
||||||
|
set_interact_as_actor($this->request->getPost('actor_id'));
|
||||||
|
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controllers;
|
||||||
|
|
||||||
|
use CodeIgniter\Controller;
|
||||||
|
use CodeIgniter\HTTP\RequestInterface;
|
||||||
|
use CodeIgniter\HTTP\ResponseInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class BaseController
|
* Class BaseController
|
||||||
*
|
*
|
||||||
|
@ -9,14 +16,7 @@
|
||||||
* class Home extends BaseController
|
* class Home extends BaseController
|
||||||
*
|
*
|
||||||
* For security be sure to declare any new methods as protected or private.
|
* For security be sure to declare any new methods as protected or private.
|
||||||
*
|
|
||||||
* @package CodeIgniter
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Controllers;
|
|
||||||
|
|
||||||
use CodeIgniter\Controller;
|
|
||||||
|
|
||||||
class BaseController extends Controller
|
class BaseController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -26,15 +26,19 @@ class BaseController extends Controller
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $helpers = ['analytics', 'svg', 'components', 'misc'];
|
protected $helpers = ['auth', 'analytics', 'svg', 'components', 'misc'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @param LoggerInterface $logger
|
||||||
*/
|
*/
|
||||||
public function initController(
|
public function initController(
|
||||||
\CodeIgniter\HTTP\RequestInterface $request,
|
RequestInterface $request,
|
||||||
\CodeIgniter\HTTP\ResponseInterface $response,
|
ResponseInterface $response,
|
||||||
\Psr\Log\LoggerInterface $logger
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
// Do Not Edit This Line
|
// Do Not Edit This Line
|
||||||
parent::initController($request, $response, $logger);
|
parent::initController($request, $response, $logger);
|
||||||
|
@ -42,8 +46,7 @@ class BaseController extends Controller
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// Preload any models, libraries, etc, here.
|
// Preload any models, libraries, etc, here.
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
// E.g.:
|
// E.g.: $this->session = \Config\Services::session();
|
||||||
// $this->session = \Config\Services::session();
|
|
||||||
|
|
||||||
set_user_session_deny_list_ip();
|
set_user_session_deny_list_ip();
|
||||||
set_user_session_browser();
|
set_user_session_browser();
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace App\Controllers;
|
||||||
|
|
||||||
use App\Models\EpisodeModel;
|
use App\Models\EpisodeModel;
|
||||||
use App\Models\PodcastModel;
|
use App\Models\PodcastModel;
|
||||||
|
use SimpleXMLElement;
|
||||||
|
|
||||||
class Episode extends BaseController
|
class Episode extends BaseController
|
||||||
{
|
{
|
||||||
|
@ -31,7 +32,7 @@ class Episode extends BaseController
|
||||||
count($params) > 1 &&
|
count($params) > 1 &&
|
||||||
!($this->episode = (new EpisodeModel())->getEpisodeBySlug(
|
!($this->episode = (new EpisodeModel())->getEpisodeBySlug(
|
||||||
$this->podcast->id,
|
$this->podcast->id,
|
||||||
$params[1]
|
$params[1],
|
||||||
))
|
))
|
||||||
) {
|
) {
|
||||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
|
@ -43,44 +44,49 @@ class Episode extends BaseController
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
self::triggerWebpageHit($this->episode->podcast_id);
|
$episodeModel = new EpisodeModel();
|
||||||
|
|
||||||
|
self::triggerWebpageHit($this->podcast->id);
|
||||||
|
|
||||||
$locale = service('request')->getLocale();
|
$locale = service('request')->getLocale();
|
||||||
$cacheName = "page_podcast{$this->episode->podcast_id}_episode{$this->episode->id}_{$locale}";
|
$cacheName = "page_podcast{$this->episode->podcast_id}_episode{$this->episode->id}_{$locale}";
|
||||||
|
|
||||||
if (!($cachedView = cache($cacheName))) {
|
if (!($cachedView = cache($cacheName))) {
|
||||||
$episodeModel = new EpisodeModel();
|
helper('persons');
|
||||||
$previousNextEpisodes = $episodeModel->getPreviousNextEpisodes(
|
$episodePersons = [];
|
||||||
$this->episode,
|
construct_person_array($this->episode->persons, $episodePersons);
|
||||||
$this->podcast->type
|
$podcastPersons = [];
|
||||||
);
|
construct_person_array($this->podcast->persons, $podcastPersons);
|
||||||
|
|
||||||
helper(['persons']);
|
|
||||||
$persons = [];
|
|
||||||
construct_episode_person_array(
|
|
||||||
$this->episode->episode_persons,
|
|
||||||
$persons
|
|
||||||
);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'previousEpisode' => $previousNextEpisodes['previous'],
|
|
||||||
'nextEpisode' => $previousNextEpisodes['next'],
|
|
||||||
'podcast' => $this->podcast,
|
'podcast' => $this->podcast,
|
||||||
'episode' => $this->episode,
|
'episode' => $this->episode,
|
||||||
'persons' => $persons,
|
'episodePersons' => $episodePersons,
|
||||||
|
'persons' => $podcastPersons,
|
||||||
];
|
];
|
||||||
|
|
||||||
$secondsToNextUnpublishedEpisode = $episodeModel->getSecondsToNextUnpublishedEpisode(
|
$secondsToNextUnpublishedEpisode = $episodeModel->getSecondsToNextUnpublishedEpisode(
|
||||||
$this->podcast->id
|
$this->podcast->id,
|
||||||
);
|
);
|
||||||
|
|
||||||
// The page cache is set to a decade so it is deleted manually upon podcast update
|
if (can_user_interact()) {
|
||||||
return view('episode', $data, [
|
helper('form');
|
||||||
'cache' => $secondsToNextUnpublishedEpisode
|
// The page cache is set to a decade so it is deleted manually upon podcast update
|
||||||
? $secondsToNextUnpublishedEpisode
|
return view('podcast/episode_authenticated', $data, [
|
||||||
: DECADE,
|
'cache' => $secondsToNextUnpublishedEpisode
|
||||||
'cache_name' => $cacheName,
|
? $secondsToNextUnpublishedEpisode
|
||||||
]);
|
: DECADE,
|
||||||
|
'cache_name' => $cacheName . '_authenticated',
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
// The page cache is set to a decade so it is deleted manually upon podcast update
|
||||||
|
return view('podcast/episode', $data, [
|
||||||
|
'cache' => $secondsToNextUnpublishedEpisode
|
||||||
|
? $secondsToNextUnpublishedEpisode
|
||||||
|
: DECADE,
|
||||||
|
'cache_name' => $cacheName,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $cachedView;
|
return $cachedView;
|
||||||
|
@ -97,7 +103,7 @@ class Episode extends BaseController
|
||||||
if (isset($_SERVER['HTTP_REFERER'])) {
|
if (isset($_SERVER['HTTP_REFERER'])) {
|
||||||
$session->set(
|
$session->set(
|
||||||
'embeddable_player_domain',
|
'embeddable_player_domain',
|
||||||
parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)
|
parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,26 +114,15 @@ class Episode extends BaseController
|
||||||
if (!($cachedView = cache($cacheName))) {
|
if (!($cachedView = cache($cacheName))) {
|
||||||
$episodeModel = new EpisodeModel();
|
$episodeModel = new EpisodeModel();
|
||||||
$theme = EpisodeModel::$themes[$theme];
|
$theme = EpisodeModel::$themes[$theme];
|
||||||
helper(['persons']);
|
|
||||||
$persons = [];
|
|
||||||
construct_episode_person_array(
|
|
||||||
$this->episode->episode_persons,
|
|
||||||
$persons
|
|
||||||
);
|
|
||||||
constructs_podcast_person_array(
|
|
||||||
$this->podcast->podcast_persons,
|
|
||||||
$persons
|
|
||||||
);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'podcast' => $this->podcast,
|
'podcast' => $this->podcast,
|
||||||
'episode' => $this->episode,
|
'episode' => $this->episode,
|
||||||
'persons' => $persons,
|
|
||||||
'theme' => $theme,
|
'theme' => $theme,
|
||||||
];
|
];
|
||||||
|
|
||||||
$secondsToNextUnpublishedEpisode = $episodeModel->getSecondsToNextUnpublishedEpisode(
|
$secondsToNextUnpublishedEpisode = $episodeModel->getSecondsToNextUnpublishedEpisode(
|
||||||
$this->podcast->id
|
$this->podcast->id,
|
||||||
);
|
);
|
||||||
|
|
||||||
// The page cache is set to a decade so it is deleted manually upon podcast update
|
// The page cache is set to a decade so it is deleted manually upon podcast update
|
||||||
|
@ -141,4 +136,56 @@ class Episode extends BaseController
|
||||||
|
|
||||||
return $cachedView;
|
return $cachedView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function oembedJSON()
|
||||||
|
{
|
||||||
|
return $this->response->setJSON([
|
||||||
|
'type' => 'rich',
|
||||||
|
'version' => '1.0',
|
||||||
|
'title' => $this->episode->title,
|
||||||
|
'provider_name' => $this->podcast->title,
|
||||||
|
'provider_url' => $this->podcast->link,
|
||||||
|
'author_name' => $this->podcast->title,
|
||||||
|
'author_url' => $this->podcast->link,
|
||||||
|
'html' =>
|
||||||
|
'<iframe src="' .
|
||||||
|
$this->episode->embeddable_player .
|
||||||
|
'" width="100%" height="200" frameborder="0" scrolling="no"></iframe>',
|
||||||
|
'width' => 600,
|
||||||
|
'height' => 200,
|
||||||
|
'thumbnail_url' => $this->episode->image->large_url,
|
||||||
|
'thumbnail_width' => config('Images')->largeSize,
|
||||||
|
'thumbnail_height' => config('Images')->largeSize,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function oembedXML()
|
||||||
|
{
|
||||||
|
$oembed = new SimpleXMLElement(
|
||||||
|
"<?xml version='1.0' encoding='utf-8' standalone='yes'?><oembed></oembed>",
|
||||||
|
);
|
||||||
|
|
||||||
|
$oembed->addChild('type', 'rich');
|
||||||
|
$oembed->addChild('version', '1.0');
|
||||||
|
$oembed->addChild('title', $this->episode->title);
|
||||||
|
$oembed->addChild('provider_name', $this->podcast->title);
|
||||||
|
$oembed->addChild('provider_url', $this->podcast->link);
|
||||||
|
$oembed->addChild('author_name', $this->podcast->title);
|
||||||
|
$oembed->addChild('author_url', $this->podcast->link);
|
||||||
|
$oembed->addChild('thumbnail', $this->episode->image->large_url);
|
||||||
|
$oembed->addChild('thumbnail_width', config('Images')->largeSize);
|
||||||
|
$oembed->addChild('thumbnail_height', config('Images')->largeSize);
|
||||||
|
$oembed->addChild(
|
||||||
|
'html',
|
||||||
|
htmlentities(
|
||||||
|
'<iframe src="' .
|
||||||
|
$this->episode->embeddable_player .
|
||||||
|
'" width="100%" height="200" frameborder="0" scrolling="no"></iframe>',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$oembed->addChild('width', 600);
|
||||||
|
$oembed->addChild('height', 200);
|
||||||
|
|
||||||
|
return $this->response->setXML($oembed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@ class Home extends BaseController
|
||||||
|
|
||||||
// check if there's only one podcast to redirect user to it
|
// check if there's only one podcast to redirect user to it
|
||||||
if (count($allPodcasts) == 1) {
|
if (count($allPodcasts) == 1) {
|
||||||
return redirect()->route('podcast', [$allPodcasts[0]->name]);
|
return redirect()->route('podcast-activity', [
|
||||||
|
$allPodcasts[0]->name,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// default behavior: list all podcasts on home page
|
// default behavior: list all podcasts on home page
|
||||||
|
|
|
@ -257,6 +257,7 @@ class Install extends Controller
|
||||||
$migrations = \Config\Services::migrations();
|
$migrations = \Config\Services::migrations();
|
||||||
|
|
||||||
!$migrations->setNamespace('Myth\Auth')->latest();
|
!$migrations->setNamespace('Myth\Auth')->latest();
|
||||||
|
!$migrations->setNamespace('ActivityPub')->latest();
|
||||||
!$migrations->setNamespace(APP_NAMESPACE)->latest();
|
!$migrations->setNamespace(APP_NAMESPACE)->latest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,212 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Controllers;
|
||||||
|
|
||||||
|
use App\Models\EpisodeModel;
|
||||||
|
use App\Models\PodcastModel;
|
||||||
|
use CodeIgniter\HTTP\URI;
|
||||||
|
use CodeIgniter\I18n\Time;
|
||||||
|
|
||||||
|
class Note extends \ActivityPub\Controllers\NoteController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \App\Entities\Podcast
|
||||||
|
*/
|
||||||
|
protected $podcast;
|
||||||
|
|
||||||
|
protected $helpers = ['auth', 'activitypub', 'svg', 'components', 'misc'];
|
||||||
|
|
||||||
|
public function _remap($method, ...$params)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
!($this->podcast = (new PodcastModel())->getPodcastByName(
|
||||||
|
$params[0],
|
||||||
|
))
|
||||||
|
) {
|
||||||
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->actor = $this->podcast->actor;
|
||||||
|
|
||||||
|
if (count($params) > 1) {
|
||||||
|
if (!($this->note = model('NoteModel')->getNoteById($params[1]))) {
|
||||||
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($params[0]);
|
||||||
|
unset($params[1]);
|
||||||
|
|
||||||
|
return $this->$method(...$params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
helper('persons');
|
||||||
|
$persons = [];
|
||||||
|
construct_person_array($this->podcast->persons, $persons);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'podcast' => $this->podcast,
|
||||||
|
'actor' => $this->actor,
|
||||||
|
'note' => $this->note,
|
||||||
|
'persons' => $persons,
|
||||||
|
];
|
||||||
|
|
||||||
|
// if user is logged in then send to the authenticated activity view
|
||||||
|
if (can_user_interact()) {
|
||||||
|
helper('form');
|
||||||
|
return view('podcast/note_authenticated', $data);
|
||||||
|
} else {
|
||||||
|
return view('podcast/note', $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attemptCreate()
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'message' => 'required|max_length[500]',
|
||||||
|
'episode_url' => 'valid_url|permit_empty',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$this->validate($rules)) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $this->validator->getErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = $this->request->getPost('message');
|
||||||
|
|
||||||
|
$newNote = new \App\Entities\Note([
|
||||||
|
'actor_id' => interact_as_actor_id(),
|
||||||
|
'published_at' => Time::now(),
|
||||||
|
'created_by' => user_id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// get episode if episodeUrl has been set
|
||||||
|
$episodeUri = $this->request->getPost('episode_url');
|
||||||
|
if (
|
||||||
|
$episodeUri &&
|
||||||
|
($params = extract_params_from_episode_uri(new URI($episodeUri)))
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
$episode = (new EpisodeModel())->getEpisodeBySlug(
|
||||||
|
$params['podcastName'],
|
||||||
|
$params['episodeSlug'],
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$newNote->episode_id = $episode->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$newNote->message = $message;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!model('NoteModel')->addNote(
|
||||||
|
$newNote,
|
||||||
|
$newNote->episode_id ? false : true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', model('NoteModel')->errors());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note has been successfully created
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attemptReply()
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'message' => 'required|max_length[500]',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$this->validate($rules)) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $this->validator->getErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
$newNote = new \ActivityPub\Entities\Note([
|
||||||
|
'actor_id' => interact_as_actor_id(),
|
||||||
|
'in_reply_to_id' => $this->note->id,
|
||||||
|
'message' => $this->request->getPost('message'),
|
||||||
|
'published_at' => Time::now(),
|
||||||
|
'created_by' => user_id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!model('NoteModel')->addReply($newNote)) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', model('NoteModel')->errors());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reply note without preview card has been successfully created
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attemptFavourite()
|
||||||
|
{
|
||||||
|
model('FavouriteModel')->toggleFavourite(
|
||||||
|
interact_as_actor(),
|
||||||
|
$this->note,
|
||||||
|
);
|
||||||
|
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attemptReblog()
|
||||||
|
{
|
||||||
|
model('NoteModel')->toggleReblog(interact_as_actor(), $this->note);
|
||||||
|
|
||||||
|
return redirect()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attemptAction()
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'action' => 'required|in_list[favourite,reblog,reply]',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$this->validate($rules)) {
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->withInput()
|
||||||
|
->with('errors', $this->validator->getErrors());
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($this->request->getPost('action')) {
|
||||||
|
case 'favourite':
|
||||||
|
return $this->attemptFavourite();
|
||||||
|
case 'reblog':
|
||||||
|
return $this->attemptReblog();
|
||||||
|
case 'reply':
|
||||||
|
return $this->attemptReply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remoteAction($action)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'podcast' => $this->podcast,
|
||||||
|
'actor' => $this->actor,
|
||||||
|
'note' => $this->note,
|
||||||
|
'action' => $action,
|
||||||
|
];
|
||||||
|
|
||||||
|
helper('form');
|
||||||
|
|
||||||
|
return view('podcast/note_remote_action', $data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -85,14 +85,23 @@ class Page extends BaseController
|
||||||
'role_label' => $credit->role_label,
|
'role_label' => $credit->role_label,
|
||||||
'is_in' => [
|
'is_in' => [
|
||||||
[
|
[
|
||||||
'link' => $credit->episode
|
'link' => $credit->episode_id
|
||||||
? $credit->episode->link
|
? $credit->episode->link
|
||||||
: $credit->podcast->link,
|
: $credit->podcast->link,
|
||||||
'title' => $credit->episode
|
'title' => $credit->episode_id
|
||||||
? (count($allPodcasts) > 1
|
? (count($allPodcasts) > 1
|
||||||
? "{$credit->podcast->title} ▸ "
|
? "{$credit->podcast->title} ▸ "
|
||||||
: '') .
|
: '') .
|
||||||
"(S{$credit->episode->season_number}E{$credit->episode->number}) {$credit->episode->title}"
|
$credit->episode
|
||||||
|
->title .
|
||||||
|
episode_numbering(
|
||||||
|
$credit->episode
|
||||||
|
->number,
|
||||||
|
$credit->episode
|
||||||
|
->season_number,
|
||||||
|
'text-xs ml-2',
|
||||||
|
true,
|
||||||
|
)
|
||||||
: $credit->podcast->title,
|
: $credit->podcast->title,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -114,14 +123,21 @@ class Page extends BaseController
|
||||||
'role_label' => $credit->role_label,
|
'role_label' => $credit->role_label,
|
||||||
'is_in' => [
|
'is_in' => [
|
||||||
[
|
[
|
||||||
'link' => $credit->episode
|
'link' => $credit->episode_id
|
||||||
? $credit->episode->link
|
? $credit->episode->link
|
||||||
: $credit->podcast->link,
|
: $credit->podcast->link,
|
||||||
'title' => $credit->episode
|
'title' => $credit->episode_id
|
||||||
? (count($allPodcasts) > 1
|
? (count($allPodcasts) > 1
|
||||||
? "{$credit->podcast->title} ▸ "
|
? "{$credit->podcast->title} ▸ "
|
||||||
: '') .
|
: '') .
|
||||||
"(S{$credit->episode->season_number}E{$credit->episode->number}) {$credit->episode->title}"
|
$credit->episode->title .
|
||||||
|
episode_numbering(
|
||||||
|
$credit->episode->number,
|
||||||
|
$credit->episode
|
||||||
|
->season_number,
|
||||||
|
'text-xs ml-2',
|
||||||
|
true,
|
||||||
|
)
|
||||||
: $credit->podcast->title,
|
: $credit->podcast->title,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -143,7 +159,13 @@ class Page extends BaseController
|
||||||
? (count($allPodcasts) > 1
|
? (count($allPodcasts) > 1
|
||||||
? "{$credit->podcast->title} ▸ "
|
? "{$credit->podcast->title} ▸ "
|
||||||
: '') .
|
: '') .
|
||||||
"(S{$credit->episode->season_number}E{$credit->episode->number}) {$credit->episode->title}"
|
$credit->episode->title .
|
||||||
|
episode_numbering(
|
||||||
|
$credit->episode->number,
|
||||||
|
$credit->episode->season_number,
|
||||||
|
'text-xs ml-2',
|
||||||
|
true,
|
||||||
|
)
|
||||||
: $credit->podcast->title,
|
: $credit->podcast->title,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -159,7 +181,13 @@ class Page extends BaseController
|
||||||
? (count($allPodcasts) > 1
|
? (count($allPodcasts) > 1
|
||||||
? "{$credit->podcast->title} ▸ "
|
? "{$credit->podcast->title} ▸ "
|
||||||
: '') .
|
: '') .
|
||||||
"(S{$credit->episode->season_number}E{$credit->episode->number}) {$credit->episode->title}"
|
$credit->episode->title .
|
||||||
|
episode_numbering(
|
||||||
|
$credit->episode->number,
|
||||||
|
$credit->episode->season_number,
|
||||||
|
'text-xs ml-2',
|
||||||
|
true,
|
||||||
|
)
|
||||||
: $credit->podcast->title,
|
: $credit->podcast->title,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace App\Controllers;
|
||||||
|
|
||||||
use App\Models\EpisodeModel;
|
use App\Models\EpisodeModel;
|
||||||
use App\Models\PodcastModel;
|
use App\Models\PodcastModel;
|
||||||
|
use App\Models\NoteModel;
|
||||||
|
|
||||||
class Podcast extends BaseController
|
class Podcast extends BaseController
|
||||||
{
|
{
|
||||||
|
@ -23,17 +24,41 @@ class Podcast extends BaseController
|
||||||
if (count($params) > 0) {
|
if (count($params) > 0) {
|
||||||
if (
|
if (
|
||||||
!($this->podcast = (new PodcastModel())->getPodcastByName(
|
!($this->podcast = (new PodcastModel())->getPodcastByName(
|
||||||
$params[0]
|
$params[0],
|
||||||
))
|
))
|
||||||
) {
|
) {
|
||||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||||
}
|
}
|
||||||
|
unset($params[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->$method();
|
return $this->$method(...$params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index()
|
public function activity()
|
||||||
|
{
|
||||||
|
helper('persons');
|
||||||
|
$persons = [];
|
||||||
|
construct_person_array($this->podcast->persons, $persons);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'podcast' => $this->podcast,
|
||||||
|
'notes' => (new NoteModel())->getActorNotes(
|
||||||
|
$this->podcast->actor_id,
|
||||||
|
),
|
||||||
|
'persons' => $persons,
|
||||||
|
];
|
||||||
|
|
||||||
|
// if user is logged in then send to the authenticated activity view
|
||||||
|
if (can_user_interact()) {
|
||||||
|
helper('form');
|
||||||
|
return view('podcast/activity_authenticated', $data);
|
||||||
|
} else {
|
||||||
|
return view('podcast/activity', $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function episodes()
|
||||||
{
|
{
|
||||||
self::triggerWebpageHit($this->podcast->id);
|
self::triggerWebpageHit($this->podcast->id);
|
||||||
|
|
||||||
|
@ -42,7 +67,7 @@ class Podcast extends BaseController
|
||||||
|
|
||||||
if (!$yearQuery and !$seasonQuery) {
|
if (!$yearQuery and !$seasonQuery) {
|
||||||
$defaultQuery = (new EpisodeModel())->getDefaultQuery(
|
$defaultQuery = (new EpisodeModel())->getDefaultQuery(
|
||||||
$this->podcast->id
|
$this->podcast->id,
|
||||||
);
|
);
|
||||||
if ($defaultQuery['type'] == 'season') {
|
if ($defaultQuery['type'] == 'season') {
|
||||||
$seasonQuery = $defaultQuery['data']['season_number'];
|
$seasonQuery = $defaultQuery['data']['season_number'];
|
||||||
|
@ -59,7 +84,7 @@ class Podcast extends BaseController
|
||||||
$yearQuery,
|
$yearQuery,
|
||||||
$seasonQuery ? 'season' . $seasonQuery : null,
|
$seasonQuery ? 'season' . $seasonQuery : null,
|
||||||
service('request')->getLocale(),
|
service('request')->getLocale(),
|
||||||
])
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!($found = cache($cacheName))) {
|
if (!($found = cache($cacheName))) {
|
||||||
|
@ -73,14 +98,19 @@ class Podcast extends BaseController
|
||||||
foreach ($years as $year) {
|
foreach ($years as $year) {
|
||||||
$isActive = $yearQuery == $year['year'];
|
$isActive = $yearQuery == $year['year'];
|
||||||
if ($isActive) {
|
if ($isActive) {
|
||||||
$activeQuery = ['type' => 'year', 'value' => $year['year']];
|
$activeQuery = [
|
||||||
|
'type' => 'year',
|
||||||
|
'value' => $year['year'],
|
||||||
|
'label' => $year['year'],
|
||||||
|
'number_of_episodes' => $year['number_of_episodes'],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
array_push($episodesNavigation, [
|
array_push($episodesNavigation, [
|
||||||
'label' => $year['year'],
|
'label' => $year['year'],
|
||||||
'number_of_episodes' => $year['number_of_episodes'],
|
'number_of_episodes' => $year['number_of_episodes'],
|
||||||
'route' =>
|
'route' =>
|
||||||
route_to('podcast', $this->podcast->name) .
|
route_to('podcast-episodes', $this->podcast->name) .
|
||||||
'?year=' .
|
'?year=' .
|
||||||
$year['year'],
|
$year['year'],
|
||||||
'is_active' => $isActive,
|
'is_active' => $isActive,
|
||||||
|
@ -93,6 +123,10 @@ class Podcast extends BaseController
|
||||||
$activeQuery = [
|
$activeQuery = [
|
||||||
'type' => 'season',
|
'type' => 'season',
|
||||||
'value' => $season['season_number'],
|
'value' => $season['season_number'],
|
||||||
|
'label' => lang('Podcast.season', [
|
||||||
|
'seasonNumber' => $season['season_number'],
|
||||||
|
]),
|
||||||
|
'number_of_episodes' => $season['number_of_episodes'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,19 +136,16 @@ class Podcast extends BaseController
|
||||||
]),
|
]),
|
||||||
'number_of_episodes' => $season['number_of_episodes'],
|
'number_of_episodes' => $season['number_of_episodes'],
|
||||||
'route' =>
|
'route' =>
|
||||||
route_to('podcast', $this->podcast->name) .
|
route_to('podcast-episodes', $this->podcast->name) .
|
||||||
'?season=' .
|
'?season=' .
|
||||||
$season['season_number'],
|
$season['season_number'],
|
||||||
'is_active' => $isActive,
|
'is_active' => $isActive,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
helper(['persons']);
|
helper('persons');
|
||||||
$persons = [];
|
$persons = [];
|
||||||
constructs_podcast_person_array(
|
construct_person_array($this->podcast->persons, $persons);
|
||||||
$this->podcast->podcast_persons,
|
|
||||||
$persons
|
|
||||||
);
|
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'podcast' => $this->podcast,
|
'podcast' => $this->podcast,
|
||||||
|
@ -124,21 +155,31 @@ class Podcast extends BaseController
|
||||||
$this->podcast->id,
|
$this->podcast->id,
|
||||||
$this->podcast->type,
|
$this->podcast->type,
|
||||||
$yearQuery,
|
$yearQuery,
|
||||||
$seasonQuery
|
$seasonQuery,
|
||||||
),
|
),
|
||||||
'personArray' => $persons,
|
'persons' => $persons,
|
||||||
];
|
];
|
||||||
|
|
||||||
$secondsToNextUnpublishedEpisode = $episodeModel->getSecondsToNextUnpublishedEpisode(
|
$secondsToNextUnpublishedEpisode = $episodeModel->getSecondsToNextUnpublishedEpisode(
|
||||||
$this->podcast->id
|
$this->podcast->id,
|
||||||
);
|
);
|
||||||
|
|
||||||
return view('podcast', $data, [
|
// if user is logged in then send to the authenticated episodes view
|
||||||
'cache' => $secondsToNextUnpublishedEpisode
|
if (can_user_interact()) {
|
||||||
? $secondsToNextUnpublishedEpisode
|
return view('podcast/episodes_authenticated', $data, [
|
||||||
: DECADE,
|
'cache' => $secondsToNextUnpublishedEpisode
|
||||||
'cache_name' => $cacheName,
|
? $secondsToNextUnpublishedEpisode
|
||||||
]);
|
: DECADE,
|
||||||
|
'cache_name' => $cacheName . '_authenticated',
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
return view('podcast/episodes', $data, [
|
||||||
|
'cache' => $secondsToNextUnpublishedEpisode
|
||||||
|
? $secondsToNextUnpublishedEpisode
|
||||||
|
: DECADE,
|
||||||
|
'cache_name' => $cacheName,
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $found;
|
return $found;
|
||||||
|
|
|
@ -39,7 +39,7 @@ class AddCategories extends Migration
|
||||||
'constraint' => 32,
|
'constraint' => 32,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$this->forge->addKey('id', true);
|
$this->forge->addPrimaryKey('id');
|
||||||
$this->forge->addUniqueKey('code');
|
$this->forge->addUniqueKey('code');
|
||||||
$this->forge->addForeignKey('parent_id', 'categories', 'id');
|
$this->forge->addForeignKey('parent_id', 'categories', 'id');
|
||||||
$this->forge->createTable('categories');
|
$this->forge->createTable('categories');
|
||||||
|
|
|
@ -28,7 +28,7 @@ class AddLanguages extends Migration
|
||||||
'constraint' => 128,
|
'constraint' => 128,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$this->forge->addKey('code', true);
|
$this->forge->addPrimaryKey('code');
|
||||||
$this->forge->createTable('languages');
|
$this->forge->createTable('languages');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,14 +23,17 @@ class AddPodcasts extends Migration
|
||||||
'unsigned' => true,
|
'unsigned' => true,
|
||||||
'auto_increment' => true,
|
'auto_increment' => true,
|
||||||
],
|
],
|
||||||
'title' => [
|
'actor_id' => [
|
||||||
'type' => 'VARCHAR',
|
'type' => 'INT',
|
||||||
'constraint' => 128,
|
'unsigned' => true,
|
||||||
],
|
],
|
||||||
'name' => [
|
'name' => [
|
||||||
'type' => 'VARCHAR',
|
'type' => 'VARCHAR',
|
||||||
'constraint' => 32,
|
'constraint' => 32,
|
||||||
'unique' => true,
|
],
|
||||||
|
'title' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 128,
|
||||||
],
|
],
|
||||||
'description_markdown' => [
|
'description_markdown' => [
|
||||||
'type' => 'TEXT',
|
'type' => 'TEXT',
|
||||||
|
@ -42,6 +45,12 @@ class AddPodcasts extends Migration
|
||||||
'type' => 'VARCHAR',
|
'type' => 'VARCHAR',
|
||||||
'constraint' => 255,
|
'constraint' => 255,
|
||||||
],
|
],
|
||||||
|
// constraint is 13 because the longest safe mimetype for images is image/svg+xml,
|
||||||
|
// see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types
|
||||||
|
'image_mimetype' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 13,
|
||||||
|
],
|
||||||
'language_code' => [
|
'language_code' => [
|
||||||
'type' => 'VARCHAR',
|
'type' => 'VARCHAR',
|
||||||
'constraint' => 2,
|
'constraint' => 2,
|
||||||
|
@ -140,6 +149,7 @@ class AddPodcasts extends Migration
|
||||||
],
|
],
|
||||||
'custom_rss' => [
|
'custom_rss' => [
|
||||||
'type' => 'JSON',
|
'type' => 'JSON',
|
||||||
|
'null' => true,
|
||||||
],
|
],
|
||||||
'partner_id' => [
|
'partner_id' => [
|
||||||
'type' => 'VARCHAR',
|
'type' => 'VARCHAR',
|
||||||
|
@ -176,7 +186,15 @@ class AddPodcasts extends Migration
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->forge->addKey('id', true);
|
$this->forge->addPrimaryKey('id');
|
||||||
|
$this->forge->addUniqueKey('name');
|
||||||
|
$this->forge->addForeignKey(
|
||||||
|
'actor_id',
|
||||||
|
'activitypub_actors',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
$this->forge->addForeignKey('category_id', 'categories', 'id');
|
$this->forge->addForeignKey('category_id', 'categories', 'id');
|
||||||
$this->forge->addForeignKey('language_code', 'languages', 'code');
|
$this->forge->addForeignKey('language_code', 'languages', 'code');
|
||||||
$this->forge->addForeignKey('created_by', 'users', 'id');
|
$this->forge->addForeignKey('created_by', 'users', 'id');
|
||||||
|
|
|
@ -73,6 +73,13 @@ class AddEpisodes extends Migration
|
||||||
'constraint' => 255,
|
'constraint' => 255,
|
||||||
'null' => true,
|
'null' => true,
|
||||||
],
|
],
|
||||||
|
// constraint is 13 because the longest safe mimetype for images is image/svg+xml,
|
||||||
|
// see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types
|
||||||
|
'image_mimetype' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 13,
|
||||||
|
'null' => true,
|
||||||
|
],
|
||||||
'transcript_uri' => [
|
'transcript_uri' => [
|
||||||
'type' => 'VARCHAR',
|
'type' => 'VARCHAR',
|
||||||
'constraint' => 255,
|
'constraint' => 255,
|
||||||
|
@ -128,6 +135,21 @@ class AddEpisodes extends Migration
|
||||||
'type' => 'JSON',
|
'type' => 'JSON',
|
||||||
'null' => true,
|
'null' => true,
|
||||||
],
|
],
|
||||||
|
'favourites_total' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'default' => 0,
|
||||||
|
],
|
||||||
|
'reblogs_total' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'default' => 0,
|
||||||
|
],
|
||||||
|
'notes_total' => [
|
||||||
|
'type' => 'INT',
|
||||||
|
'unsigned' => true,
|
||||||
|
'default' => 0,
|
||||||
|
],
|
||||||
'created_by' => [
|
'created_by' => [
|
||||||
'type' => 'INT',
|
'type' => 'INT',
|
||||||
'unsigned' => true,
|
'unsigned' => true,
|
||||||
|
@ -151,9 +173,15 @@ class AddEpisodes extends Migration
|
||||||
'null' => true,
|
'null' => true,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$this->forge->addKey('id', true);
|
$this->forge->addPrimaryKey('id');
|
||||||
$this->forge->addUniqueKey(['podcast_id', 'slug']);
|
$this->forge->addUniqueKey(['podcast_id', 'slug']);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
$this->forge->addForeignKey(
|
||||||
|
'podcast_id',
|
||||||
|
'podcasts',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
$this->forge->addForeignKey('created_by', 'users', 'id');
|
$this->forge->addForeignKey('created_by', 'users', 'id');
|
||||||
$this->forge->addForeignKey('updated_by', 'users', 'id');
|
$this->forge->addForeignKey('updated_by', 'users', 'id');
|
||||||
$this->forge->createTable('episodes');
|
$this->forge->createTable('episodes');
|
||||||
|
|
|
@ -63,8 +63,20 @@ class AddSoundbites extends Migration
|
||||||
]);
|
]);
|
||||||
$this->forge->addKey('id', true);
|
$this->forge->addKey('id', true);
|
||||||
$this->forge->addUniqueKey(['episode_id', 'start_time', 'duration']);
|
$this->forge->addUniqueKey(['episode_id', 'start_time', 'duration']);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
$this->forge->addForeignKey(
|
||||||
$this->forge->addForeignKey('episode_id', 'episodes', 'id');
|
'podcast_id',
|
||||||
|
'podcasts',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey(
|
||||||
|
'episode_id',
|
||||||
|
'episodes',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
$this->forge->addForeignKey('created_by', 'users', 'id');
|
$this->forge->addForeignKey('created_by', 'users', 'id');
|
||||||
$this->forge->addForeignKey('updated_by', 'users', 'id');
|
$this->forge->addForeignKey('updated_by', 'users', 'id');
|
||||||
$this->forge->createTable('soundbites');
|
$this->forge->createTable('soundbites');
|
||||||
|
|
|
@ -45,7 +45,7 @@ class AddPlatforms extends Migration
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT NOW() ON UPDATE NOW()'
|
'`updated_at` timestamp NOT NULL DEFAULT NOW() ON UPDATE NOW()'
|
||||||
);
|
);
|
||||||
$this->forge->addKey('slug', true);
|
$this->forge->addPrimaryKey('slug');
|
||||||
$this->forge->createTable('platforms');
|
$this->forge->createTable('platforms');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsPodcasts
|
* Class AddAnalyticsPodcasts
|
||||||
* Creates analytics_podcasts table in database
|
* Creates analytics_podcasts table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -45,12 +46,11 @@ class AddAnalyticsPodcasts extends Migration
|
||||||
]);
|
]);
|
||||||
$this->forge->addPrimaryKey(['podcast_id', 'date']);
|
$this->forge->addPrimaryKey(['podcast_id', 'date']);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->createTable('analytics_podcasts');
|
$this->forge->createTable('analytics_podcasts');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsPodcastsByEpisode
|
* Class AddAnalyticsPodcastsByEpisode
|
||||||
* Creates analytics_episodes_by_episode table in database
|
* Creates analytics_episodes_by_episode table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -41,13 +42,11 @@ class AddAnalyticsPodcastsByEpisode extends Migration
|
||||||
]);
|
]);
|
||||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'episode_id']);
|
$this->forge->addPrimaryKey(['podcast_id', 'date', 'episode_id']);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->addForeignKey('episode_id', 'episodes', 'id');
|
|
||||||
$this->forge->createTable('analytics_podcasts_by_episode');
|
$this->forge->createTable('analytics_podcasts_by_episode');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsPodcastsByHour
|
* Class AddAnalyticsPodcastsByHour
|
||||||
* Creates analytics_podcasts_by_hour table in database
|
* Creates analytics_podcasts_by_hour table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -36,12 +37,11 @@ class AddAnalyticsPodcastsByHour extends Migration
|
||||||
]);
|
]);
|
||||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'hour']);
|
$this->forge->addPrimaryKey(['podcast_id', 'date', 'hour']);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->createTable('analytics_podcasts_by_hour');
|
$this->forge->createTable('analytics_podcasts_by_hour');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsPodcastsByPlayer
|
* Class AddAnalyticsPodcastsByPlayer
|
||||||
* Creates analytics_podcasts_by_player table in database
|
* Creates analytics_podcasts_by_player table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -61,12 +62,11 @@ class AddAnalyticsPodcastsByPlayer extends Migration
|
||||||
'is_bot',
|
'is_bot',
|
||||||
]);
|
]);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->createTable('analytics_podcasts_by_player');
|
$this->forge->createTable('analytics_podcasts_by_player');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsPodcastsByCountry
|
* Class AddAnalyticsPodcastsByCountry
|
||||||
* Creates analytics_podcasts_by_country table in database
|
* Creates analytics_podcasts_by_country table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -37,12 +38,11 @@ class AddAnalyticsPodcastsByCountry extends Migration
|
||||||
]);
|
]);
|
||||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'country_code']);
|
$this->forge->addPrimaryKey(['podcast_id', 'date', 'country_code']);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->createTable('analytics_podcasts_by_country');
|
$this->forge->createTable('analytics_podcasts_by_country');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsPodcastsByRegion
|
* Class AddAnalyticsPodcastsByRegion
|
||||||
* Creates analytics_podcasts_by_region table in database
|
* Creates analytics_podcasts_by_region table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -55,12 +56,11 @@ class AddAnalyticsPodcastsByRegion extends Migration
|
||||||
'region_code',
|
'region_code',
|
||||||
]);
|
]);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->createTable('analytics_podcasts_by_region');
|
$this->forge->createTable('analytics_podcasts_by_region');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,8 +48,6 @@ class AddPodcastsPlatforms extends Migration
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->forge->addPrimaryKey(['podcast_id', 'platform_slug']);
|
$this->forge->addPrimaryKey(['podcast_id', 'platform_slug']);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->addForeignKey('platform_slug', 'platforms', 'slug');
|
|
||||||
$this->forge->createTable('podcasts_platforms');
|
$this->forge->createTable('podcasts_platforms');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsWebsiteByBrowser
|
* Class AddAnalyticsWebsiteByBrowser
|
||||||
* Creates analytics_website_by_browser table in database
|
* Creates analytics_website_by_browser table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -37,12 +38,11 @@ class AddAnalyticsWebsiteByBrowser extends Migration
|
||||||
|
|
||||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'browser']);
|
$this->forge->addPrimaryKey(['podcast_id', 'date', 'browser']);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->createTable('analytics_website_by_browser');
|
$this->forge->createTable('analytics_website_by_browser');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsWebsiteByReferer
|
* Class AddAnalyticsWebsiteByReferer
|
||||||
* Creates analytics_website_by_referer table in database
|
* Creates analytics_website_by_referer table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -46,12 +47,11 @@ class AddAnalyticsWebsiteByReferer extends Migration
|
||||||
]);
|
]);
|
||||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'referer_url']);
|
$this->forge->addPrimaryKey(['podcast_id', 'date', 'referer_url']);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->createTable('analytics_website_by_referer');
|
$this->forge->createTable('analytics_website_by_referer');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsWebsiteByEntryPage
|
* Class AddAnalyticsWebsiteByEntryPage
|
||||||
* Creates analytics_website_by_entry_page table in database
|
* Creates analytics_website_by_entry_page table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -36,12 +37,11 @@ class AddAnalyticsWebsiteByEntryPage extends Migration
|
||||||
]);
|
]);
|
||||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'entry_page_url']);
|
$this->forge->addPrimaryKey(['podcast_id', 'date', 'entry_page_url']);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()'
|
'`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()',
|
||||||
);
|
);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
|
||||||
$this->forge->createTable('analytics_website_by_entry_page');
|
$this->forge->createTable('analytics_website_by_entry_page');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsUnknownUseragents
|
* Class AddAnalyticsUnknownUseragents
|
||||||
* Creates analytics_unknown_useragents table in database
|
* Creates analytics_unknown_useragents table in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -33,7 +34,8 @@ class AddAnalyticsUnknownUseragents extends Migration
|
||||||
'default' => 1,
|
'default' => 1,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$this->forge->addKey('id', true);
|
|
||||||
|
$this->forge->addPrimaryKey('id');
|
||||||
// `created_at` and `updated_at` are created with SQL because Model class won’t be used for insertion (Procedure will be used instead)
|
// `created_at` and `updated_at` are created with SQL because Model class won’t be used for insertion (Procedure will be used instead)
|
||||||
$this->forge->addField(
|
$this->forge->addField(
|
||||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsPodcastsProcedure
|
* Class AddAnalyticsPodcastsProcedure
|
||||||
* Creates analytics_podcasts procedure in database
|
* Creates analytics_podcasts procedure in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -21,58 +22,58 @@ class AddAnalyticsPodcastsProcedure extends Migration
|
||||||
$prefix = $this->db->getPrefix();
|
$prefix = $this->db->getPrefix();
|
||||||
|
|
||||||
$createQuery = <<<EOD
|
$createQuery = <<<EOD
|
||||||
CREATE PROCEDURE `{$prefix}analytics_podcasts` (
|
CREATE PROCEDURE `{$prefix}analytics_podcasts` (
|
||||||
IN `p_podcast_id` INT UNSIGNED,
|
IN `p_podcast_id` INT UNSIGNED,
|
||||||
IN `p_episode_id` INT UNSIGNED,
|
IN `p_episode_id` INT UNSIGNED,
|
||||||
IN `p_country_code` VARCHAR(3) CHARSET utf8mb4,
|
IN `p_country_code` VARCHAR(3) CHARSET utf8mb4,
|
||||||
IN `p_region_code` VARCHAR(3) CHARSET utf8mb4,
|
IN `p_region_code` VARCHAR(3) CHARSET utf8mb4,
|
||||||
IN `p_latitude` FLOAT,
|
IN `p_latitude` FLOAT,
|
||||||
IN `p_longitude` FLOAT,
|
IN `p_longitude` FLOAT,
|
||||||
IN `p_service` VARCHAR(128) CHARSET utf8mb4,
|
IN `p_service` VARCHAR(128) CHARSET utf8mb4,
|
||||||
IN `p_app` VARCHAR(128) CHARSET utf8mb4,
|
IN `p_app` VARCHAR(128) CHARSET utf8mb4,
|
||||||
IN `p_device` VARCHAR(32) CHARSET utf8mb4,
|
IN `p_device` VARCHAR(32) CHARSET utf8mb4,
|
||||||
IN `p_os` VARCHAR(32) CHARSET utf8mb4,
|
IN `p_os` VARCHAR(32) CHARSET utf8mb4,
|
||||||
IN `p_bot` TINYINT(1) UNSIGNED,
|
IN `p_bot` TINYINT(1) UNSIGNED,
|
||||||
IN `p_filesize` INT UNSIGNED,
|
IN `p_filesize` INT UNSIGNED,
|
||||||
IN `p_duration` INT UNSIGNED,
|
IN `p_duration` INT UNSIGNED,
|
||||||
IN `p_age` INT UNSIGNED,
|
IN `p_age` INT UNSIGNED,
|
||||||
IN `p_new_listener` TINYINT(1) UNSIGNED
|
IN `p_new_listener` TINYINT(1) UNSIGNED
|
||||||
) MODIFIES SQL DATA
|
) MODIFIES SQL DATA
|
||||||
DETERMINISTIC
|
DETERMINISTIC
|
||||||
SQL SECURITY INVOKER
|
SQL SECURITY INVOKER
|
||||||
COMMENT 'Add one hit in podcast logs tables.'
|
COMMENT 'Add one hit in podcast logs tables.'
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
SET @current_datetime = NOW();
|
SET @current_datetime = NOW();
|
||||||
SET @current_date = DATE(@current_datetime);
|
SET @current_date = DATE(@current_datetime);
|
||||||
SET @current_hour = HOUR(@current_datetime);
|
SET @current_hour = HOUR(@current_datetime);
|
||||||
|
|
||||||
IF NOT `p_bot` THEN
|
IF NOT `p_bot` THEN
|
||||||
INSERT INTO `{$prefix}analytics_podcasts`(`podcast_id`, `date`)
|
INSERT INTO `{$prefix}analytics_podcasts`(`podcast_id`, `date`)
|
||||||
VALUES (p_podcast_id, @current_date)
|
VALUES (p_podcast_id, @current_date)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
`duration`=`duration`+`p_duration`,
|
`duration`=`duration`+`p_duration`,
|
||||||
`bandwidth`=`bandwidth`+`p_filesize`,
|
`bandwidth`=`bandwidth`+`p_filesize`,
|
||||||
`hits`=`hits`+1,
|
`hits`=`hits`+1,
|
||||||
`unique_listeners`=`unique_listeners`+`p_new_listener`;
|
`unique_listeners`=`unique_listeners`+`p_new_listener`;
|
||||||
INSERT INTO `{$prefix}analytics_podcasts_by_hour`(`podcast_id`, `date`, `hour`)
|
INSERT INTO `{$prefix}analytics_podcasts_by_hour`(`podcast_id`, `date`, `hour`)
|
||||||
VALUES (p_podcast_id, @current_date, @current_hour)
|
VALUES (p_podcast_id, @current_date, @current_hour)
|
||||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
INSERT INTO `{$prefix}analytics_podcasts_by_episode`(`podcast_id`, `episode_id`, `date`, `age`)
|
INSERT INTO `{$prefix}analytics_podcasts_by_episode`(`podcast_id`, `episode_id`, `date`, `age`)
|
||||||
VALUES (p_podcast_id, p_episode_id, @current_date, p_age)
|
VALUES (p_podcast_id, p_episode_id, @current_date, p_age)
|
||||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
INSERT INTO `{$prefix}analytics_podcasts_by_country`(`podcast_id`, `country_code`, `date`)
|
INSERT INTO `{$prefix}analytics_podcasts_by_country`(`podcast_id`, `country_code`, `date`)
|
||||||
VALUES (p_podcast_id, p_country_code, @current_date)
|
VALUES (p_podcast_id, p_country_code, @current_date)
|
||||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
INSERT INTO `{$prefix}analytics_podcasts_by_region`(`podcast_id`, `country_code`, `region_code`, `latitude`, `longitude`, `date`)
|
INSERT INTO `{$prefix}analytics_podcasts_by_region`(`podcast_id`, `country_code`, `region_code`, `latitude`, `longitude`, `date`)
|
||||||
VALUES (p_podcast_id, p_country_code, p_region_code, p_latitude, p_longitude, @current_date)
|
VALUES (p_podcast_id, p_country_code, p_region_code, p_latitude, p_longitude, @current_date)
|
||||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
END IF;
|
END IF;
|
||||||
INSERT INTO `{$prefix}analytics_podcasts_by_player`(`podcast_id`, `service`, `app`, `device`, `os`, `is_bot`, `date`)
|
INSERT INTO `{$prefix}analytics_podcasts_by_player`(`podcast_id`, `service`, `app`, `device`, `os`, `is_bot`, `date`)
|
||||||
VALUES (p_podcast_id, p_service, p_app, p_device, p_os, p_bot, @current_date)
|
VALUES (p_podcast_id, p_service, p_app, p_device, p_os, p_bot, @current_date)
|
||||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
END
|
END
|
||||||
EOD;
|
EOD;
|
||||||
$this->db->query($createQuery);
|
$this->db->query($createQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ EOD;
|
||||||
{
|
{
|
||||||
$prefix = $this->db->getPrefix();
|
$prefix = $this->db->getPrefix();
|
||||||
$this->db->query(
|
$this->db->query(
|
||||||
"DROP PROCEDURE IF EXISTS `{$prefix}analytics_podcasts`"
|
"DROP PROCEDURE IF EXISTS `{$prefix}analytics_podcasts`",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsUnknownUseragentsProcedure
|
* Class AddAnalyticsUnknownUseragentsProcedure
|
||||||
* Creates analytics_unknown_useragents procedure in database
|
* Creates analytics_unknown_useragents procedure in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -20,14 +21,14 @@ class AddAnalyticsUnknownUseragentsProcedure extends Migration
|
||||||
// Example: CALL analytics_unknown_useragents('Podcasts/1430.46 CFNetwork/1125.2 Darwin/19.4.0');
|
// Example: CALL analytics_unknown_useragents('Podcasts/1430.46 CFNetwork/1125.2 Darwin/19.4.0');
|
||||||
$procedureName = $this->db->prefixTable('analytics_unknown_useragents');
|
$procedureName = $this->db->prefixTable('analytics_unknown_useragents');
|
||||||
$createQuery = <<<EOD
|
$createQuery = <<<EOD
|
||||||
CREATE PROCEDURE `$procedureName` (IN `p_useragent` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
|
CREATE PROCEDURE `$procedureName` (IN `p_useragent` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
|
||||||
DETERMINISTIC
|
DETERMINISTIC
|
||||||
SQL SECURITY INVOKER
|
SQL SECURITY INVOKER
|
||||||
COMMENT 'Add an unknown useragent to table $procedureName.'
|
COMMENT 'Add an unknown useragent to table $procedureName.'
|
||||||
INSERT INTO `$procedureName`(`useragent`)
|
INSERT INTO `$procedureName`(`useragent`)
|
||||||
VALUES (p_useragent)
|
VALUES (p_useragent)
|
||||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1
|
||||||
EOD;
|
EOD;
|
||||||
$this->db->query($createQuery);
|
$this->db->query($createQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
/**
|
/**
|
||||||
* Class AddAnalyticsWebsiteProcedure
|
* Class AddAnalyticsWebsiteProcedure
|
||||||
* Creates analytics_website stored procedure in database
|
* Creates analytics_website stored procedure in database
|
||||||
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
* @link https://castopod.org/
|
* @link https://castopod.org/
|
||||||
|
@ -20,25 +21,25 @@ class AddAnalyticsWebsiteProcedure extends Migration
|
||||||
// Example: CALL analytics_website(1,'FR','Firefox');
|
// Example: CALL analytics_website(1,'FR','Firefox');
|
||||||
$procedureName = $this->db->prefixTable('analytics_website');
|
$procedureName = $this->db->prefixTable('analytics_website');
|
||||||
$createQuery = <<<EOD
|
$createQuery = <<<EOD
|
||||||
CREATE PROCEDURE `$procedureName` (IN `p_podcast_id` INT UNSIGNED, IN `p_browser` VARCHAR(191) CHARSET utf8mb4, IN `p_entry_page` VARCHAR(512) CHARSET utf8mb4, IN `p_referer_url` VARCHAR(512) CHARSET utf8mb4, IN `p_domain` VARCHAR(128) CHARSET utf8mb4, IN `p_keywords` VARCHAR(384) CHARSET utf8mb4) MODIFIES SQL DATA
|
CREATE PROCEDURE `$procedureName` (IN `p_podcast_id` INT UNSIGNED, IN `p_browser` VARCHAR(191) CHARSET utf8mb4, IN `p_entry_page` VARCHAR(512) CHARSET utf8mb4, IN `p_referer_url` VARCHAR(512) CHARSET utf8mb4, IN `p_domain` VARCHAR(128) CHARSET utf8mb4, IN `p_keywords` VARCHAR(384) CHARSET utf8mb4) MODIFIES SQL DATA
|
||||||
DETERMINISTIC
|
DETERMINISTIC
|
||||||
SQL SECURITY INVOKER
|
SQL SECURITY INVOKER
|
||||||
COMMENT 'Add one hit in website logs tables.'
|
COMMENT 'Add one hit in website logs tables.'
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
SET @current_date = DATE(NOW());
|
SET @current_date = DATE(NOW());
|
||||||
|
|
||||||
INSERT INTO {$procedureName}_by_browser(`podcast_id`, `browser`, `date`)
|
INSERT INTO {$procedureName}_by_browser(`podcast_id`, `browser`, `date`)
|
||||||
VALUES (p_podcast_id, p_browser, @current_date)
|
VALUES (p_podcast_id, p_browser, @current_date)
|
||||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
INSERT INTO {$procedureName}_by_referer(`podcast_id`, `referer_url`, `domain`, `keywords`, `date`)
|
INSERT INTO {$procedureName}_by_referer(`podcast_id`, `referer_url`, `domain`, `keywords`, `date`)
|
||||||
VALUES (p_podcast_id, p_referer_url, p_domain, p_keywords, @current_date)
|
VALUES (p_podcast_id, p_referer_url, p_domain, p_keywords, @current_date)
|
||||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
INSERT INTO {$procedureName}_by_entry_page(`podcast_id`, `entry_page_url`, `date`)
|
INSERT INTO {$procedureName}_by_entry_page(`podcast_id`, `entry_page_url`, `date`)
|
||||||
VALUES (p_podcast_id, p_entry_page, @current_date)
|
VALUES (p_podcast_id, p_entry_page, @current_date)
|
||||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||||
END
|
END
|
||||||
EOD;
|
EOD;
|
||||||
$this->db->query($createQuery);
|
$this->db->query($createQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AddLanguages
|
* Class AddPodcastUsers
|
||||||
* Creates languages table in database
|
* Creates podcast_users table in database
|
||||||
*
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
@ -32,9 +32,21 @@ class AddPodcastsUsers extends Migration
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$this->forge->addPrimaryKey(['user_id', 'podcast_id']);
|
$this->forge->addPrimaryKey(['user_id', 'podcast_id']);
|
||||||
$this->forge->addForeignKey('user_id', 'users', 'id');
|
$this->forge->addForeignKey('user_id', 'users', 'id', false, 'CASCADE');
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
$this->forge->addForeignKey(
|
||||||
$this->forge->addForeignKey('group_id', 'auth_groups', 'id');
|
'podcast_id',
|
||||||
|
'podcasts',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey(
|
||||||
|
'group_id',
|
||||||
|
'auth_groups',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
$this->forge->createTable('podcasts_users');
|
$this->forge->createTable('podcasts_users');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class AddLanguages
|
* Class AddPages
|
||||||
* Creates languages table in database
|
* Creates pages table in database
|
||||||
*
|
*
|
||||||
* @copyright 2020 Podlibre
|
* @copyright 2020 Podlibre
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
@ -46,7 +46,7 @@ class AddPages extends Migration
|
||||||
'null' => true,
|
'null' => true,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$this->forge->addKey('id', true);
|
$this->forge->addPrimaryKey('id');
|
||||||
$this->forge->createTable('pages');
|
$this->forge->createTable('pages');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,20 @@ class AddPodcastsCategories extends Migration
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
$this->forge->addPrimaryKey(['podcast_id', 'category_id']);
|
$this->forge->addPrimaryKey(['podcast_id', 'category_id']);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
$this->forge->addForeignKey(
|
||||||
$this->forge->addForeignKey('category_id', 'categories', 'id');
|
'podcast_id',
|
||||||
|
'podcasts',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey(
|
||||||
|
'category_id',
|
||||||
|
'categories',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
$this->forge->createTable('podcasts_categories');
|
$this->forge->createTable('podcasts_categories');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,12 @@ class AddPersons extends Migration
|
||||||
'type' => 'VARCHAR',
|
'type' => 'VARCHAR',
|
||||||
'constraint' => 255,
|
'constraint' => 255,
|
||||||
],
|
],
|
||||||
|
// constraint is 13 because the longest safe mimetype for images is image/svg+xml,
|
||||||
|
// see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#image_types
|
||||||
|
'image_mimetype' => [
|
||||||
|
'type' => 'VARCHAR',
|
||||||
|
'constraint' => 13,
|
||||||
|
],
|
||||||
'created_by' => [
|
'created_by' => [
|
||||||
'type' => 'INT',
|
'type' => 'INT',
|
||||||
'unsigned' => true,
|
'unsigned' => true,
|
||||||
|
|
|
@ -47,8 +47,20 @@ class AddPodcastsPersons extends Migration
|
||||||
'person_group',
|
'person_group',
|
||||||
'person_role',
|
'person_role',
|
||||||
]);
|
]);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
$this->forge->addForeignKey(
|
||||||
$this->forge->addForeignKey('person_id', 'persons', 'id');
|
'podcast_id',
|
||||||
|
'podcasts',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey(
|
||||||
|
'person_id',
|
||||||
|
'persons',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
$this->forge->createTable('podcasts_persons');
|
$this->forge->createTable('podcasts_persons');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,9 +52,27 @@ class AddEpisodesPersons extends Migration
|
||||||
'person_group',
|
'person_group',
|
||||||
'person_role',
|
'person_role',
|
||||||
]);
|
]);
|
||||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
$this->forge->addForeignKey(
|
||||||
$this->forge->addForeignKey('episode_id', 'episodes', 'id');
|
'podcast_id',
|
||||||
$this->forge->addForeignKey('person_id', 'persons', 'id');
|
'podcasts',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey(
|
||||||
|
'episode_id',
|
||||||
|
'episodes',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
|
$this->forge->addForeignKey(
|
||||||
|
'person_id',
|
||||||
|
'persons',
|
||||||
|
'id',
|
||||||
|
false,
|
||||||
|
'CASCADE',
|
||||||
|
);
|
||||||
$this->forge->createTable('episodes_persons');
|
$this->forge->createTable('episodes_persons');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,16 +22,16 @@ class AddCreditView extends Migration
|
||||||
$podcastPersonTable = $this->db->prefixTable('podcasts_persons');
|
$podcastPersonTable = $this->db->prefixTable('podcasts_persons');
|
||||||
$episodePersonTable = $this->db->prefixTable('episodes_persons');
|
$episodePersonTable = $this->db->prefixTable('episodes_persons');
|
||||||
$createQuery = <<<EOD
|
$createQuery = <<<EOD
|
||||||
CREATE VIEW `$viewName` AS
|
CREATE VIEW `$viewName` AS
|
||||||
SELECT `person_group`, `person_id`, `full_name`, `person_role`, `podcast_id`, NULL AS `episode_id` FROM `$podcastPersonTable`
|
SELECT `person_group`, `person_id`, `full_name`, `person_role`, `podcast_id`, NULL AS `episode_id` FROM `$podcastPersonTable`
|
||||||
INNER JOIN `$personTable`
|
INNER JOIN `$personTable`
|
||||||
ON (`person_id`=`$personTable`.`id`)
|
ON (`person_id`=`$personTable`.`id`)
|
||||||
UNION
|
UNION
|
||||||
SELECT `person_group`, `person_id`, `full_name`, `person_role`, `podcast_id`, `episode_id` FROM `$episodePersonTable`
|
SELECT `person_group`, `person_id`, `full_name`, `person_role`, `podcast_id`, `episode_id` FROM `$episodePersonTable`
|
||||||
INNER JOIN `$personTable`
|
INNER JOIN `$personTable`
|
||||||
ON (`person_id`=`$personTable`.`id`)
|
ON (`person_id`=`$personTable`.`id`)
|
||||||
ORDER BY `person_group`, `full_name`, `person_role`, `podcast_id`, `episode_id`;
|
ORDER BY `person_group`, `full_name`, `person_role`, `podcast_id`, `episode_id`;
|
||||||
EOD;
|
EOD;
|
||||||
$this->db->query($createQuery);
|
$this->db->query($createQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AddEpisodeIdToNotes
|
||||||
|
* Adds episode_id field to activitypub_notes table in database
|
||||||
|
*
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddEpisodeIdToNotes extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$prefix = $this->db->getPrefix();
|
||||||
|
|
||||||
|
$createQuery = <<<SQL
|
||||||
|
ALTER TABLE ${prefix}activitypub_notes
|
||||||
|
ADD COLUMN `episode_id` INT UNSIGNED NULL AFTER `replies_count`,
|
||||||
|
ADD FOREIGN KEY ${prefix}activitypub_notes_episode_id_foreign(episode_id) REFERENCES ${prefix}episodes(id) ON DELETE CASCADE;
|
||||||
|
SQL;
|
||||||
|
$this->db->query($createQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropForeignKey(
|
||||||
|
'activitypub_notes',
|
||||||
|
'activitypub_notes_episode_id_foreign',
|
||||||
|
);
|
||||||
|
$this->forge->dropColumn('activitypub_notes', 'episode_id');
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class AddCreatedByToNotes
|
||||||
|
* Adds created_by field to activitypub_notes table in database
|
||||||
|
*
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Database\Migrations;
|
||||||
|
|
||||||
|
use CodeIgniter\Database\Migration;
|
||||||
|
|
||||||
|
class AddCreatedByToNotes extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$prefix = $this->db->getPrefix();
|
||||||
|
|
||||||
|
$createQuery = <<<SQL
|
||||||
|
ALTER TABLE ${prefix}activitypub_notes
|
||||||
|
ADD COLUMN `created_by` INT UNSIGNED AFTER `episode_id`,
|
||||||
|
ADD FOREIGN KEY ${prefix}activitypub_notes_created_by_foreign(created_by) REFERENCES ${prefix}users(id) ON DELETE CASCADE;
|
||||||
|
SQL;
|
||||||
|
$this->db->query($createQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->forge->dropForeignKey(
|
||||||
|
'activitypub_notes',
|
||||||
|
'activitypub_notes_created_by_foreign',
|
||||||
|
);
|
||||||
|
$this->forge->dropColumn('activitypub_notes', 'created_by');
|
||||||
|
}
|
||||||
|
}
|
|
@ -158,6 +158,18 @@ class AuthSeeder extends Seeder
|
||||||
'description' => 'Set / remove platform links of a podcast',
|
'description' => 'Set / remove platform links of a podcast',
|
||||||
'has_permission' => ['podcast_admin'],
|
'has_permission' => ['podcast_admin'],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'name' => 'manage_publications',
|
||||||
|
'description' =>
|
||||||
|
'Publish / unpublish episodes & notes of a podcast',
|
||||||
|
'has_permission' => ['podcast_admin'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'interact_as',
|
||||||
|
'description' =>
|
||||||
|
'Interact as the podcast to favourite / share or reply to notes.',
|
||||||
|
'has_permission' => ['podcast_admin'],
|
||||||
|
],
|
||||||
],
|
],
|
||||||
'podcast_episodes' => [
|
'podcast_episodes' => [
|
||||||
[
|
[
|
||||||
|
@ -192,11 +204,6 @@ class AuthSeeder extends Seeder
|
||||||
'Delete all occurrences of an episode of a podcast from the database',
|
'Delete all occurrences of an episode of a podcast from the database',
|
||||||
'has_permission' => ['podcast_admin'],
|
'has_permission' => ['podcast_admin'],
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'name' => 'manage_publications',
|
|
||||||
'description' => 'Publish / unpublish episodes of a podcast',
|
|
||||||
'has_permission' => ['podcast_admin'],
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
'person' => [
|
'person' => [
|
||||||
[
|
[
|
||||||
|
@ -220,8 +227,23 @@ class AuthSeeder extends Seeder
|
||||||
'has_permission' => ['superadmin'],
|
'has_permission' => ['superadmin'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'delete_permanently',
|
'name' => 'delete',
|
||||||
'description' => 'Delete any person from the database',
|
'description' =>
|
||||||
|
'Delete permanently any person from the database',
|
||||||
|
'has_permission' => ['superadmin'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'fediverse' => [
|
||||||
|
[
|
||||||
|
'name' => 'block_actors',
|
||||||
|
'description' =>
|
||||||
|
'Block an activitypub actors from interacting with the instance.',
|
||||||
|
'has_permission' => ['superadmin'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'block_domains',
|
||||||
|
'description' =>
|
||||||
|
'Block an activitypub domains from interacting with the instance.',
|
||||||
'has_permission' => ['superadmin'],
|
'has_permission' => ['superadmin'],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -266,7 +288,7 @@ class AuthSeeder extends Seeder
|
||||||
array_push($dataGroupsPermissions, [
|
array_push($dataGroupsPermissions, [
|
||||||
'group_id' => $this->getGroupIdByName(
|
'group_id' => $this->getGroupIdByName(
|
||||||
$role,
|
$role,
|
||||||
$dataGroups
|
$dataGroups,
|
||||||
),
|
),
|
||||||
'permission_id' => $permissionId,
|
'permission_id' => $permissionId,
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -98,7 +98,6 @@ class PlatformSeeder extends Seeder
|
||||||
'home_url' => 'https://fyyd.de/',
|
'home_url' => 'https://fyyd.de/',
|
||||||
'submit_url' => 'https://fyyd.de/add-feed',
|
'submit_url' => 'https://fyyd.de/add-feed',
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
'slug' => 'google',
|
'slug' => 'google',
|
||||||
'type' => 'podcasting',
|
'type' => 'podcasting',
|
||||||
|
@ -249,7 +248,6 @@ class PlatformSeeder extends Seeder
|
||||||
'submit_url' =>
|
'submit_url' =>
|
||||||
'https://help.tunein.com/contact/add-podcast-S19TR3Sdf',
|
'https://help.tunein.com/contact/add-podcast-S19TR3Sdf',
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
'slug' => 'paypal',
|
'slug' => 'paypal',
|
||||||
'type' => 'funding',
|
'type' => 'funding',
|
||||||
|
@ -257,7 +255,6 @@ class PlatformSeeder extends Seeder
|
||||||
'home_url' => 'https://www.paypal.com/',
|
'home_url' => 'https://www.paypal.com/',
|
||||||
'submit_url' => 'https://www.paypal.com/paypalme/my/grab',
|
'submit_url' => 'https://www.paypal.com/paypalme/my/grab',
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
'slug' => 'gofundme',
|
'slug' => 'gofundme',
|
||||||
'type' => 'funding',
|
'type' => 'funding',
|
||||||
|
@ -322,7 +319,6 @@ class PlatformSeeder extends Seeder
|
||||||
'home_url' => 'https://www.ulule.com/',
|
'home_url' => 'https://www.ulule.com/',
|
||||||
'submit_url' => 'https://www.ulule.com/projects/create/#/',
|
'submit_url' => 'https://www.ulule.com/projects/create/#/',
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
'slug' => 'discord',
|
'slug' => 'discord',
|
||||||
'type' => 'social',
|
'type' => 'social',
|
||||||
|
@ -431,6 +427,7 @@ class PlatformSeeder extends Seeder
|
||||||
'submit_url' => 'https://creatoracademy.youtube.com/page/home',
|
'submit_url' => 'https://creatoracademy.youtube.com/page/home',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->db
|
$this->db
|
||||||
->table('platforms')
|
->table('platforms')
|
||||||
->ignore(true)
|
->ignore(true)
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Credit extends Entity
|
||||||
protected $podcast;
|
protected $podcast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \App\Entities\Episode
|
* @var \App\Entities\Episode|null
|
||||||
*/
|
*/
|
||||||
protected $episode;
|
protected $episode;
|
||||||
|
|
||||||
|
@ -44,50 +44,61 @@ class Credit extends Entity
|
||||||
public function getPodcast()
|
public function getPodcast()
|
||||||
{
|
{
|
||||||
return (new PodcastModel())->getPodcastById(
|
return (new PodcastModel())->getPodcastById(
|
||||||
$this->attributes['podcast_id']
|
$this->attributes['podcast_id'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEpisode()
|
public function getEpisode()
|
||||||
{
|
{
|
||||||
if (empty($this->attributes['episode_id'])) {
|
if (empty($this->episode_id)) {
|
||||||
return null;
|
throw new \RuntimeException(
|
||||||
} else {
|
'Credit must have episode_id before getting episode.',
|
||||||
return (new EpisodeModel())->getEpisodeById(
|
|
||||||
$this->attributes['podcast_id'],
|
|
||||||
$this->attributes['episode_id']
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (empty($this->episode)) {
|
||||||
|
$this->episode = (new EpisodeModel())->getPublishedEpisodeById(
|
||||||
|
$this->episode_id,
|
||||||
|
$this->podcast_id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->episode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPerson()
|
public function getPerson()
|
||||||
{
|
{
|
||||||
return (new PersonModel())->getPersonById(
|
if (empty($this->person_id)) {
|
||||||
$this->attributes['person_id']
|
throw new \RuntimeException(
|
||||||
);
|
'Credit must have person_id before getting person.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->person)) {
|
||||||
|
$this->person = (new PersonModel())->getPersonById(
|
||||||
|
$this->person_id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->person;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getGroupLabel()
|
public function getGroupLabel()
|
||||||
{
|
{
|
||||||
if (empty($this->attributes['person_group'])) {
|
if (empty($this->person_group)) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return lang(
|
return lang("PersonsTaxonomy.persons.{$this->person_group}.label");
|
||||||
"PersonsTaxonomy.persons.{$this->attributes['person_group']}.label"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRoleLabel()
|
public function getRoleLabel()
|
||||||
{
|
{
|
||||||
if (
|
if (empty($this->person_group) || empty($this->person_role)) {
|
||||||
empty($this->attributes['person_group']) ||
|
|
||||||
empty($this->attributes['person_role'])
|
|
||||||
) {
|
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return lang(
|
return lang(
|
||||||
"PersonsTaxonomy.persons.{$this->attributes['person_group']}.roles.{$this->attributes['person_role']}.label"
|
"PersonsTaxonomy.persons.{$this->person_group}.roles.{$this->person_role}.label",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace App\Entities;
|
||||||
use App\Models\PodcastModel;
|
use App\Models\PodcastModel;
|
||||||
use App\Models\SoundbiteModel;
|
use App\Models\SoundbiteModel;
|
||||||
use App\Models\EpisodePersonModel;
|
use App\Models\EpisodePersonModel;
|
||||||
|
use App\Models\NoteModel;
|
||||||
use CodeIgniter\Entity;
|
use CodeIgniter\Entity;
|
||||||
use CodeIgniter\I18n\Time;
|
use CodeIgniter\I18n\Time;
|
||||||
use League\CommonMark\CommonMarkConverter;
|
use League\CommonMark\CommonMarkConverter;
|
||||||
|
@ -28,7 +29,7 @@ class Episode extends Entity
|
||||||
protected $link;
|
protected $link;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \App\Entities\Image
|
* @var \App\Libraries\Image
|
||||||
*/
|
*/
|
||||||
protected $image;
|
protected $image;
|
||||||
|
|
||||||
|
@ -80,13 +81,18 @@ class Episode extends Entity
|
||||||
/**
|
/**
|
||||||
* @var \App\Entities\EpisodePerson[]
|
* @var \App\Entities\EpisodePerson[]
|
||||||
*/
|
*/
|
||||||
protected $episode_persons;
|
protected $persons;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \App\Entities\Soundbite[]
|
* @var \App\Entities\Soundbite[]
|
||||||
*/
|
*/
|
||||||
protected $soundbites;
|
protected $soundbites;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \App\Entities\Note[]
|
||||||
|
*/
|
||||||
|
protected $notes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds text only description, striped of any markdown or html special characters
|
* Holds text only description, striped of any markdown or html special characters
|
||||||
*
|
*
|
||||||
|
@ -122,6 +128,7 @@ class Episode extends Entity
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'id' => 'integer',
|
'id' => 'integer',
|
||||||
|
'podcast_id' => 'integer',
|
||||||
'guid' => 'string',
|
'guid' => 'string',
|
||||||
'slug' => 'string',
|
'slug' => 'string',
|
||||||
'title' => 'string',
|
'title' => 'string',
|
||||||
|
@ -133,6 +140,7 @@ class Episode extends Entity
|
||||||
'description_markdown' => 'string',
|
'description_markdown' => 'string',
|
||||||
'description_html' => 'string',
|
'description_html' => 'string',
|
||||||
'image_uri' => '?string',
|
'image_uri' => '?string',
|
||||||
|
'image_mimetype' => '?string',
|
||||||
'transcript_uri' => '?string',
|
'transcript_uri' => '?string',
|
||||||
'chapters_uri' => '?string',
|
'chapters_uri' => '?string',
|
||||||
'parental_advisory' => '?string',
|
'parental_advisory' => '?string',
|
||||||
|
@ -144,6 +152,9 @@ class Episode extends Entity
|
||||||
'location_geo' => '?string',
|
'location_geo' => '?string',
|
||||||
'location_osmid' => '?string',
|
'location_osmid' => '?string',
|
||||||
'custom_rss' => '?json-array',
|
'custom_rss' => '?json-array',
|
||||||
|
'favourites_total' => 'integer',
|
||||||
|
'reblogs_total' => 'integer',
|
||||||
|
'notes_total' => 'integer',
|
||||||
'created_by' => 'integer',
|
'created_by' => 'integer',
|
||||||
'updated_by' => 'integer',
|
'updated_by' => 'integer',
|
||||||
];
|
];
|
||||||
|
@ -163,15 +174,16 @@ class Episode extends Entity
|
||||||
) {
|
) {
|
||||||
helper('media');
|
helper('media');
|
||||||
|
|
||||||
// check whether the user has inputted an image and store it
|
// check whether the user has inputted an image and store
|
||||||
$this->attributes['image_uri'] = save_podcast_media(
|
$this->attributes['image_mimetype'] = $image->getMimeType();
|
||||||
|
$this->attributes['image_uri'] = save_media(
|
||||||
$image,
|
$image,
|
||||||
$this->getPodcast()->name,
|
'podcasts/' . $this->getPodcast()->name,
|
||||||
$this->attributes['slug']
|
$this->attributes['slug'],
|
||||||
);
|
);
|
||||||
|
$this->image = new \App\Libraries\Image(
|
||||||
$this->image = new \App\Entities\Image(
|
$this->attributes['image_uri'],
|
||||||
$this->attributes['image_uri']
|
$this->attributes['image_mimetype'],
|
||||||
);
|
);
|
||||||
$this->image->saveSizes();
|
$this->image->saveSizes();
|
||||||
}
|
}
|
||||||
|
@ -179,10 +191,13 @@ class Episode extends Entity
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getImage(): \App\Entities\Image
|
public function getImage(): \App\Libraries\Image
|
||||||
{
|
{
|
||||||
if ($image_uri = $this->attributes['image_uri']) {
|
if ($image_uri = $this->attributes['image_uri']) {
|
||||||
return new \App\Entities\Image($image_uri);
|
return new \App\Libraries\Image(
|
||||||
|
$image_uri,
|
||||||
|
$this->attributes['image_mimetype'],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return $this->getPodcast()->image;
|
return $this->getPodcast()->image;
|
||||||
}
|
}
|
||||||
|
@ -204,13 +219,13 @@ class Episode extends Entity
|
||||||
|
|
||||||
$enclosure_metadata = get_file_tags($enclosure);
|
$enclosure_metadata = get_file_tags($enclosure);
|
||||||
|
|
||||||
$this->attributes['enclosure_uri'] = save_podcast_media(
|
$this->attributes['enclosure_uri'] = save_media(
|
||||||
$enclosure,
|
$enclosure,
|
||||||
$this->getPodcast()->name,
|
'podcasts/' . $this->getPodcast()->name,
|
||||||
$this->attributes['slug']
|
$this->attributes['slug'],
|
||||||
);
|
);
|
||||||
$this->attributes['enclosure_duration'] = round(
|
$this->attributes['enclosure_duration'] = round(
|
||||||
$enclosure_metadata['playtime_seconds']
|
$enclosure_metadata['playtime_seconds'],
|
||||||
);
|
);
|
||||||
$this->attributes['enclosure_mimetype'] =
|
$this->attributes['enclosure_mimetype'] =
|
||||||
$enclosure_metadata['mime_type'];
|
$enclosure_metadata['mime_type'];
|
||||||
|
@ -238,10 +253,10 @@ class Episode extends Entity
|
||||||
) {
|
) {
|
||||||
helper('media');
|
helper('media');
|
||||||
|
|
||||||
$this->attributes['transcript_uri'] = save_podcast_media(
|
$this->attributes['transcript_uri'] = save_media(
|
||||||
$transcript,
|
$transcript,
|
||||||
$this->getPodcast()->name,
|
$this->getPodcast()->name,
|
||||||
$this->attributes['slug'] . '-transcript'
|
$this->attributes['slug'] . '-transcript',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,10 +278,10 @@ class Episode extends Entity
|
||||||
) {
|
) {
|
||||||
helper('media');
|
helper('media');
|
||||||
|
|
||||||
$this->attributes['chapters_uri'] = save_podcast_media(
|
$this->attributes['chapters_uri'] = save_media(
|
||||||
$chapters,
|
$chapters,
|
||||||
$this->getPodcast()->name,
|
$this->getPodcast()->name,
|
||||||
$this->attributes['slug'] . '-chapters'
|
$this->attributes['slug'] . '-chapters',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,15 +358,15 @@ class Episode extends Entity
|
||||||
$this->attributes[
|
$this->attributes[
|
||||||
'enclosure_duration'
|
'enclosure_duration'
|
||||||
]) *
|
]) *
|
||||||
60
|
60,
|
||||||
),
|
),
|
||||||
$this->attributes['enclosure_filesize'],
|
$this->attributes['enclosure_filesize'],
|
||||||
$this->attributes['enclosure_duration'],
|
$this->attributes['enclosure_duration'],
|
||||||
strtotime($this->attributes['published_at'])
|
strtotime($this->attributes['published_at']),
|
||||||
)
|
),
|
||||||
),
|
),
|
||||||
$this->attributes['enclosure_uri']
|
$this->attributes['enclosure_uri'],
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,22 +399,22 @@ class Episode extends Entity
|
||||||
*
|
*
|
||||||
* @return \App\Entities\EpisodePerson[]
|
* @return \App\Entities\EpisodePerson[]
|
||||||
*/
|
*/
|
||||||
public function getEpisodePersons()
|
public function getPersons()
|
||||||
{
|
{
|
||||||
if (empty($this->id)) {
|
if (empty($this->id)) {
|
||||||
throw new \RuntimeException(
|
throw new \RuntimeException(
|
||||||
'Episode must be created before getting persons.'
|
'Episode must be created before getting persons.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->episode_persons)) {
|
if (empty($this->persons)) {
|
||||||
$this->episode_persons = (new EpisodePersonModel())->getPersonsByEpisodeId(
|
$this->persons = (new EpisodePersonModel())->getPersonsByEpisodeId(
|
||||||
$this->podcast_id,
|
$this->podcast_id,
|
||||||
$this->id
|
$this->id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->episode_persons;
|
return $this->persons;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -411,28 +426,43 @@ class Episode extends Entity
|
||||||
{
|
{
|
||||||
if (empty($this->id)) {
|
if (empty($this->id)) {
|
||||||
throw new \RuntimeException(
|
throw new \RuntimeException(
|
||||||
'Episode must be created before getting soundbites.'
|
'Episode must be created before getting soundbites.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->soundbites)) {
|
if (empty($this->soundbites)) {
|
||||||
$this->soundbites = (new SoundbiteModel())->getEpisodeSoundbites(
|
$this->soundbites = (new SoundbiteModel())->getEpisodeSoundbites(
|
||||||
$this->getPodcast()->id,
|
$this->getPodcast()->id,
|
||||||
$this->id
|
$this->id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->soundbites;
|
return $this->soundbites;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getNotes()
|
||||||
|
{
|
||||||
|
if (empty($this->id)) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
'Episode must be created before getting soundbites.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->notes)) {
|
||||||
|
$this->notes = (new NoteModel())->getEpisodeNotes($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->notes;
|
||||||
|
}
|
||||||
|
|
||||||
public function getLink()
|
public function getLink()
|
||||||
{
|
{
|
||||||
return base_url(
|
return base_url(
|
||||||
route_to(
|
route_to(
|
||||||
'episode',
|
'episode',
|
||||||
$this->getPodcast()->name,
|
$this->getPodcast()->name,
|
||||||
$this->attributes['slug']
|
$this->attributes['slug'],
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,13 +474,13 @@ class Episode extends Entity
|
||||||
'embeddable-player-theme',
|
'embeddable-player-theme',
|
||||||
$this->getPodcast()->name,
|
$this->getPodcast()->name,
|
||||||
$this->attributes['slug'],
|
$this->attributes['slug'],
|
||||||
$theme
|
$theme,
|
||||||
)
|
)
|
||||||
: route_to(
|
: route_to(
|
||||||
'embeddable-player',
|
'embeddable-player',
|
||||||
$this->getPodcast()->name,
|
$this->getPodcast()->name,
|
||||||
$this->attributes['slug']
|
$this->attributes['slug'],
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,7 +494,7 @@ class Episode extends Entity
|
||||||
public function getPodcast()
|
public function getPodcast()
|
||||||
{
|
{
|
||||||
return (new PodcastModel())->getPodcastById(
|
return (new PodcastModel())->getPodcastById(
|
||||||
$this->attributes['podcast_id']
|
$this->attributes['podcast_id'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +507,7 @@ class Episode extends Entity
|
||||||
|
|
||||||
$this->attributes['description_markdown'] = $descriptionMarkdown;
|
$this->attributes['description_markdown'] = $descriptionMarkdown;
|
||||||
$this->attributes['description_html'] = $converter->convertToHtml(
|
$this->attributes['description_html'] = $converter->convertToHtml(
|
||||||
$descriptionMarkdown
|
$descriptionMarkdown,
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -510,25 +540,11 @@ class Episode extends Entity
|
||||||
preg_replace(
|
preg_replace(
|
||||||
'/\s+/',
|
'/\s+/',
|
||||||
' ',
|
' ',
|
||||||
strip_tags($this->attributes['description_html'])
|
strip_tags($this->attributes['description_html']),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCreatedBy(\App\Entities\User $user)
|
|
||||||
{
|
|
||||||
$this->attributes['created_by'] = $user->id;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setUpdatedBy(\App\Entities\User $user)
|
|
||||||
{
|
|
||||||
$this->attributes['updated_by'] = $user->id;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPublicationStatus()
|
public function getPublicationStatus()
|
||||||
{
|
{
|
||||||
if ($this->publication_status) {
|
if ($this->publication_status) {
|
||||||
|
@ -588,7 +604,7 @@ class Episode extends Entity
|
||||||
return '';
|
return '';
|
||||||
} else {
|
} else {
|
||||||
$xmlNode = (new \App\Libraries\SimpleRSSElement(
|
$xmlNode = (new \App\Libraries\SimpleRSSElement(
|
||||||
'<?xml version="1.0" encoding="utf-8"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:podcast="https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"/>'
|
'<?xml version="1.0" encoding="utf-8"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:podcast="https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"/>',
|
||||||
))
|
))
|
||||||
->addChild('channel')
|
->addChild('channel')
|
||||||
->addChild('item');
|
->addChild('item');
|
||||||
|
@ -596,7 +612,7 @@ class Episode extends Entity
|
||||||
[
|
[
|
||||||
'elements' => $this->custom_rss,
|
'elements' => $this->custom_rss,
|
||||||
],
|
],
|
||||||
$xmlNode
|
$xmlNode,
|
||||||
);
|
);
|
||||||
return str_replace(['<item>', '</item>'], '', $xmlNode->asXML());
|
return str_replace(['<item>', '</item>'], '', $xmlNode->asXML());
|
||||||
}
|
}
|
||||||
|
@ -615,12 +631,12 @@ class Episode extends Entity
|
||||||
simplexml_load_string(
|
simplexml_load_string(
|
||||||
'<?xml version="1.0" encoding="utf-8"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:podcast="https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"><channel><item>' .
|
'<?xml version="1.0" encoding="utf-8"?><rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:podcast="https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"><channel><item>' .
|
||||||
$customRssString .
|
$customRssString .
|
||||||
'</item></channel></rss>'
|
'</item></channel></rss>',
|
||||||
)
|
),
|
||||||
)['elements'][0]['elements'][0];
|
)['elements'][0]['elements'][0];
|
||||||
if (array_key_exists('elements', $customRssArray)) {
|
if (array_key_exists('elements', $customRssArray)) {
|
||||||
$this->attributes['custom_rss'] = json_encode(
|
$this->attributes['custom_rss'] = json_encode(
|
||||||
$customRssArray['elements']
|
$customRssArray['elements'],
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$this->attributes['custom_rss'] = null;
|
$this->attributes['custom_rss'] = null;
|
||||||
|
|
|
@ -1,151 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @copyright 2020 Podlibre
|
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
|
||||||
* @link https://castopod.org/
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Entities;
|
|
||||||
|
|
||||||
use CodeIgniter\Entity;
|
|
||||||
|
|
||||||
class Image extends Entity
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $original_path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $original_url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $thumbnail_path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $thumbnail_url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $medium_path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $medium_url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $large_path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $large_url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $feed_path;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $feed_url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $id3_path;
|
|
||||||
|
|
||||||
public function __construct($originalUri)
|
|
||||||
{
|
|
||||||
helper('media');
|
|
||||||
|
|
||||||
$originalPath = media_path($originalUri);
|
|
||||||
|
|
||||||
[
|
|
||||||
'filename' => $filename,
|
|
||||||
'dirname' => $dirname,
|
|
||||||
'extension' => $extension,
|
|
||||||
] = pathinfo($originalPath);
|
|
||||||
|
|
||||||
// load images extensions from config
|
|
||||||
$imageConfig = config('Images');
|
|
||||||
$thumbnailExtension = $imageConfig->thumbnailExtension;
|
|
||||||
$mediumExtension = $imageConfig->mediumExtension;
|
|
||||||
$largeExtension = $imageConfig->largeExtension;
|
|
||||||
$feedExtension = $imageConfig->feedExtension;
|
|
||||||
$id3Extension = $imageConfig->id3Extension;
|
|
||||||
|
|
||||||
$thumbnail =
|
|
||||||
$dirname . '/' . $filename . $thumbnailExtension . '.' . $extension;
|
|
||||||
$medium =
|
|
||||||
$dirname . '/' . $filename . $mediumExtension . '.' . $extension;
|
|
||||||
$large =
|
|
||||||
$dirname . '/' . $filename . $largeExtension . '.' . $extension;
|
|
||||||
$feed = $dirname . '/' . $filename . $feedExtension . '.' . $extension;
|
|
||||||
$id3 = $dirname . '/' . $filename . $id3Extension . '.' . $extension;
|
|
||||||
|
|
||||||
parent::__construct([
|
|
||||||
'original_path' => $originalPath,
|
|
||||||
'original_url' => media_url($originalUri),
|
|
||||||
'thumbnail_path' => $thumbnail,
|
|
||||||
'thumbnail_url' => base_url($thumbnail),
|
|
||||||
'medium_path' => $medium,
|
|
||||||
'medium_url' => base_url($medium),
|
|
||||||
'large_path' => $large,
|
|
||||||
'large_url' => base_url($large),
|
|
||||||
'feed_path' => $feed,
|
|
||||||
'feed_url' => base_url($feed),
|
|
||||||
'id3_path' => $id3,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function saveSizes()
|
|
||||||
{
|
|
||||||
// load images sizes from config
|
|
||||||
$imageConfig = config('Images');
|
|
||||||
$thumbnailSize = $imageConfig->thumbnailSize;
|
|
||||||
$mediumSize = $imageConfig->mediumSize;
|
|
||||||
$largeSize = $imageConfig->largeSize;
|
|
||||||
$feedSize = $imageConfig->feedSize;
|
|
||||||
$id3Size = $imageConfig->id3Size;
|
|
||||||
|
|
||||||
$imageService = \Config\Services::image();
|
|
||||||
|
|
||||||
$imageService
|
|
||||||
->withFile($this->attributes['original_path'])
|
|
||||||
->resize($thumbnailSize, $thumbnailSize)
|
|
||||||
->save($this->attributes['thumbnail_path']);
|
|
||||||
|
|
||||||
$imageService
|
|
||||||
->withFile($this->attributes['original_path'])
|
|
||||||
->resize($mediumSize, $mediumSize)
|
|
||||||
->save($this->attributes['medium_path']);
|
|
||||||
|
|
||||||
$imageService
|
|
||||||
->withFile($this->attributes['original_path'])
|
|
||||||
->resize($largeSize, $largeSize)
|
|
||||||
->save($this->attributes['large_path']);
|
|
||||||
|
|
||||||
$imageService
|
|
||||||
->withFile($this->attributes['original_path'])
|
|
||||||
->resize($feedSize, $feedSize)
|
|
||||||
->save($this->attributes['feed_path']);
|
|
||||||
|
|
||||||
$imageService
|
|
||||||
->withFile($this->attributes['original_path'])
|
|
||||||
->resize($id3Size, $id3Size)
|
|
||||||
->save($this->attributes['id3_path']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @copyright 2020 Podlibre
|
||||||
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||||
|
* @link https://castopod.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Entities;
|
||||||
|
|
||||||
|
use App\Models\EpisodeModel;
|
||||||
|
|
||||||
|
class Note extends \ActivityPub\Entities\Note
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var \App\Entities\Episode|null
|
||||||
|
*/
|
||||||
|
protected $episode;
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'id' => 'string',
|
||||||
|
'uri' => 'string',
|
||||||
|
'actor_id' => 'integer',
|
||||||
|
'in_reply_to_id' => '?string',
|
||||||
|
'reblog_of_id' => '?string',
|
||||||
|
'episode_id' => '?integer',
|
||||||
|
'message' => 'string',
|
||||||
|
'message_html' => 'string',
|
||||||
|
'favourites_count' => 'integer',
|
||||||
|
'reblogs_count' => 'integer',
|
||||||
|
'replies_count' => 'integer',
|
||||||
|
'created_by' => 'integer',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the note's attached episode
|
||||||
|
*
|
||||||
|
* @return \App\Entities\Episode
|
||||||
|
*/
|
||||||
|
public function getEpisode()
|
||||||
|
{
|
||||||
|
if (empty($this->episode_id)) {
|
||||||
|
throw new \RuntimeException(
|
||||||
|
'Note must have an episode_id before getting episode.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->episode)) {
|
||||||
|
$this->episode = (new EpisodeModel())->getEpisodeById(
|
||||||
|
$this->episode_id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->episode;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ use CodeIgniter\Entity;
|
||||||
class Person extends Entity
|
class Person extends Entity
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var \App\Entities\Image
|
* @var \App\Libraries\Image
|
||||||
*/
|
*/
|
||||||
protected $image;
|
protected $image;
|
||||||
|
|
||||||
|
@ -23,12 +23,13 @@ class Person extends Entity
|
||||||
'unique_name' => 'string',
|
'unique_name' => 'string',
|
||||||
'information_url' => '?string',
|
'information_url' => '?string',
|
||||||
'image_uri' => 'string',
|
'image_uri' => 'string',
|
||||||
|
'image_mimetype' => 'string',
|
||||||
'created_by' => 'integer',
|
'created_by' => 'integer',
|
||||||
'updated_by' => 'integer',
|
'updated_by' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a picture in `public/media/~person/`
|
* Saves a picture in `public/media/persons/`
|
||||||
*
|
*
|
||||||
* @param \CodeIgniter\HTTP\Files\UploadedFile|\CodeIgniter\Files\File $image
|
* @param \CodeIgniter\HTTP\Files\UploadedFile|\CodeIgniter\Files\File $image
|
||||||
*
|
*
|
||||||
|
@ -38,13 +39,15 @@ class Person extends Entity
|
||||||
if ($image) {
|
if ($image) {
|
||||||
helper('media');
|
helper('media');
|
||||||
|
|
||||||
$this->attributes['image_uri'] = save_podcast_media(
|
$this->attributes['image_mimetype'] = $image->getMimeType();
|
||||||
|
$this->attributes['image_uri'] = save_media(
|
||||||
$image,
|
$image,
|
||||||
'~person',
|
'persons',
|
||||||
$this->attributes['unique_name']
|
$this->attributes['unique_name'],
|
||||||
);
|
);
|
||||||
$this->image = new \App\Entities\Image(
|
$this->image = new \App\Libraries\Image(
|
||||||
$this->attributes['image_uri']
|
$this->attributes['image_uri'],
|
||||||
|
$this->attributes['image_mimetype'],
|
||||||
);
|
);
|
||||||
$this->image->saveSizes();
|
$this->image->saveSizes();
|
||||||
}
|
}
|
||||||
|
@ -54,6 +57,9 @@ class Person extends Entity
|
||||||
|
|
||||||
public function getImage()
|
public function getImage()
|
||||||
{
|
{
|
||||||
return new \App\Entities\Image($this->attributes['image_uri']);
|
return new \App\Libraries\Image(
|
||||||
|
$this->attributes['image_uri'],
|
||||||
|
$this->attributes['image_mimetype'],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue