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
|
||||
|
||||
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 && \
|
||||
apt-get install -y nodejs
|
||||
|
|
|
@ -138,7 +138,6 @@ node_modules
|
|||
# public folder
|
||||
public/*
|
||||
!public/media
|
||||
!public/media/~person
|
||||
!public/.htaccess
|
||||
!public/favicon.ico
|
||||
!public/index.php
|
||||
|
@ -147,10 +146,14 @@ public/*
|
|||
# public media folder
|
||||
public/media/*
|
||||
!public/media/index.html
|
||||
!public/media/podcasts
|
||||
!public/media/persons
|
||||
|
||||
# public person folder
|
||||
public/media/~person/*
|
||||
!public/media/~person/index.html
|
||||
public/media/podcasts/*
|
||||
!public/media/podcasts/index.html
|
||||
|
||||
public/media/persons/*
|
||||
!public/media/persons/index.html
|
||||
|
||||
# Generated files
|
||||
app/Language/en/PersonsTaxonomy.php
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
{
|
||||
"files": "*.php",
|
||||
"options": {
|
||||
"phpVersion": "7.2",
|
||||
"phpVersion": "7.3",
|
||||
"singleQuote": true
|
||||
}
|
||||
},
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
+ writable/***
|
||||
+ .env.example
|
||||
+ DEPENDENCIES.md
|
||||
+ LICENSE
|
||||
+ LICENSE.md
|
||||
+ README.md
|
||||
+ INSTALL.md
|
||||
- **
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
"apply",
|
||||
"responsive",
|
||||
"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:
|
||||
|
||||
- [Code Igniter 4](https://codeigniter.com)
|
||||
- [CodeIgniter 4](https://codeigniter.com)
|
||||
([MIT License](https://codeigniter.com/user_guide/license.html))
|
||||
- [WhichBrowser/Parser-PHP](https://github.com/WhichBrowser/Parser-PHP)
|
||||
([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))
|
||||
- [podlibre/ipcat](https://github.com/podlibre/ipcat)
|
||||
([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:
|
||||
|
||||
|
@ -39,9 +47,15 @@ Javascript dependencies:
|
|||
([MIT License](https://github.com/jshjohnson/Choices/blob/master/LICENSE))
|
||||
- [flatpickr](https://flatpickr.js.org/)
|
||||
([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:
|
||||
|
||||
- [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/)
|
||||
([Apache License 2.0](https://github.com/Remix-Design/RemixIcon/blob/master/License))
|
||||
- [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
|
||||
WORKDIR /castopod
|
||||
|
@ -25,3 +25,9 @@ RUN echo "file_uploads = On\n" \
|
|||
"post_max_size = 120M\n" \
|
||||
"max_execution_time = 300\n" \
|
||||
> /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
|
||||
hosting, you can install it on most PHP-MySQL compatible web servers.
|
||||
|
||||
## Table of contents <!-- omit in toc -->
|
||||
|
||||
- [Install instructions](#install-instructions)
|
||||
- [(optional) Manual configuration](#optional-manual-configuration)
|
||||
- [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)
|
||||
- [Privileges](#privileges)
|
||||
- [(Optional) Other recommendations](#optional-other-recommendations)
|
||||
- [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
|
||||
already.
|
||||
- ⚠️ 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.
|
||||
3. Follow the instructions on your screen.
|
||||
4. Follow the instructions on your screen.
|
||||
|
||||
All done, start podcasting!
|
||||
|
||||
|
@ -36,13 +46,12 @@ Before uploading Castopod files to your web server:
|
|||
|
||||
## 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)
|
||||
- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use
|
||||
the HTTP\CURLRequest library
|
||||
- [libcurl](http://php.net/manual/en/curl.requirements.php)
|
||||
- [mbstring](http://php.net/manual/en/mbstring.installation.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.\
|
||||
Whether you are a beginner, an amateur or a professional, you will get everything
|
||||
you need:\
|
||||
Create, upload, publish, and get comprehensive audience measurement that respects your
|
||||
listeners privacy.
|
||||
Create, upload, publish, and get comprehensive audience measurement that
|
||||
respects your listeners privacy.
|
||||
|
||||
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
|
||||
professional, all your data and analytics belong to you and you only.
|
||||
Whether you choose to install it on your own server or have it hosted by a professional,
|
||||
all your data and analytics belong to you and you only.
|
||||
|
||||
![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.
|
||||
|
||||
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)”.
|
||||
|
||||
## 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
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Base Site URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| URL to your CodeIgniter root. Typically this will be your base URL,
|
||||
| WITH a trailing slash:
|
||||
|
|
||||
| http://example.com/
|
||||
|
|
||||
| If this is not set then CodeIgniter will try guess the protocol, domain
|
||||
| and path to your installation. However, you should always configure this
|
||||
| explicitly and never rely on auto-guessing, especially in production
|
||||
| environments.
|
||||
|
|
||||
*/
|
||||
public $baseURL = 'http://127.0.0.1:8080/';
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Base Site URL
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* URL to your CodeIgniter root. Typically this will be your base URL,
|
||||
* WITH a trailing slash:
|
||||
*
|
||||
* http://example.com/
|
||||
*
|
||||
* If this is not set then CodeIgniter will try guess the protocol, domain
|
||||
* and path to your installation. However, you should always configure this
|
||||
* explicitly and never rely on auto-guessing, especially in production
|
||||
* environments.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $baseURL = 'http://localhost:8080/';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Media Base URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| URL to your media root. Typically this will be your base URL,
|
||||
| WITH a trailing slash:
|
||||
|
|
||||
| http://cdn.example.com/
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Media Base URL
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* URL to your media root. Typically this will be your base URL,
|
||||
* WITH a trailing slash:
|
||||
*
|
||||
* http://cdn.example.com/
|
||||
*/
|
||||
public $mediaBaseURL = 'http://127.0.0.2:8080/';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Index File
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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
|
||||
| variable so that it is blank.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Index File
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
* variable so that it is blank.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $indexPage = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| URI PROTOCOL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This item determines which getServer global should be used to retrieve the
|
||||
| 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:
|
||||
|
|
||||
| 'REQUEST_URI' Uses $_SERVER['REQUEST_URI']
|
||||
| 'QUERY_STRING' Uses $_SERVER['QUERY_STRING']
|
||||
| 'PATH_INFO' Uses $_SERVER['PATH_INFO']
|
||||
|
|
||||
| WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* URI PROTOCOL
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This item determines which getServer global should be used to retrieve the
|
||||
* 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:
|
||||
*
|
||||
* 'REQUEST_URI' Uses $_SERVER['REQUEST_URI']
|
||||
* 'QUERY_STRING' Uses $_SERVER['QUERY_STRING']
|
||||
* 'PATH_INFO' Uses $_SERVER['PATH_INFO']
|
||||
*
|
||||
* WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $uriProtocol = 'REQUEST_URI';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Locale
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The Locale roughly represents the language and location that your visitor
|
||||
| is viewing the site from. It affects the language strings and other
|
||||
| strings (like currency markers, numbers, etc), that your program
|
||||
| should run under for this request.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Default Locale
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The Locale roughly represents the language and location that your visitor
|
||||
* is viewing the site from. It affects the language strings and other
|
||||
* strings (like currency markers, numbers, etc), that your program
|
||||
* should run under for this request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $defaultLocale = 'en';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Negotiate Locale
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If true, the current Request object will automatically determine the
|
||||
| language to use based on the value of the Accept-Language header.
|
||||
|
|
||||
| If false, no automatic detection will be performed.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Negotiate Locale
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If true, the current Request object will automatically determine the
|
||||
* language to use based on the value of the Accept-Language header.
|
||||
*
|
||||
* If false, no automatic detection will be performed.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $negotiateLocale = true;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Supported Locales
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If $negotiateLocale is true, this array lists the locales supported
|
||||
| by the application in descending order of priority. If no match is
|
||||
| found, the first locale will be used.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Supported Locales
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If $negotiateLocale is true, this array lists the locales supported
|
||||
* by the application in descending order of priority. If no match is
|
||||
* found, the first locale will be used.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $supportedLocales = ['en', 'fr'];
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default timezone that will be used in your application to display
|
||||
| dates with the date helper, and can be retrieved through app_timezone()
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Application Timezone
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The default timezone that will be used in your application to display
|
||||
* dates with the date helper, and can be retrieved through app_timezone()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $appTimezone = 'UTC';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Character Set
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This determines which character set is used by default in various methods
|
||||
| that require a character set to be provided.
|
||||
|
|
||||
| See http://php.net/htmlspecialchars for a list of supported charsets.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Default Character Set
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This determines which character set is used by default in various methods
|
||||
* that require a character set to be provided.
|
||||
*
|
||||
* @see http://php.net/htmlspecialchars for a list of supported charsets.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $charset = 'UTF-8';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| URI PROTOCOL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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
|
||||
| secure, the user will be redirected to a secure version of the page
|
||||
| and the HTTP Strict Transport Security header will be set.
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* URI PROTOCOL
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
* secure, the user will be redirected to a secure version of the page
|
||||
* and the HTTP Strict Transport Security header will be set.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $forceGlobalSecureRequests = false;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 'sessionDriver'
|
||||
|
|
||||
| The storage driver to use: files, database, redis, memcached
|
||||
| - CodeIgniter\Session\Handlers\FileHandler
|
||||
| - CodeIgniter\Session\Handlers\DatabaseHandler
|
||||
| - CodeIgniter\Session\Handlers\MemcachedHandler
|
||||
| - CodeIgniter\Session\Handlers\RedisHandler
|
||||
|
|
||||
| '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.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Driver
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The session storage driver to use:
|
||||
* - `CodeIgniter\Session\Handlers\FileHandler`
|
||||
* - `CodeIgniter\Session\Handlers\DatabaseHandler`
|
||||
* - `CodeIgniter\Session\Handlers\MemcachedHandler`
|
||||
* - `CodeIgniter\Session\Handlers\RedisHandler`
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
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';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Time to Update
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* How many seconds between CI regenerating the session ID.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cookie Related Variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 'cookiePrefix' = 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
|
||||
| '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.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Prefix
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Set a cookie name prefix if you need to avoid collisions.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $cookiePrefix = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Domain
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Set to `.your-domain.com` for site-wide cookies.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $cookieDomain = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Path
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Typically will be a forward slash.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $cookiePath = '/';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Secure
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Cookie will only be set if a secure HTTPS connection exists.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $cookieSecure = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie HTTP Only
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Cookie will only be accessible via HTTP(S) (no JavaScript).
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $cookieHTTPOnly = false;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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: array('10.0.1.200', '192.168.5.0/24')
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie SameSite
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Configure cookie SameSite setting. Allowed values are:
|
||||
* - None
|
||||
* - Lax
|
||||
* - Strict
|
||||
* - ''
|
||||
*
|
||||
* Defaults to `Lax` for compatibility with modern browsers. Setting `''`
|
||||
* (empty string) means no SameSite attribute will be set on cookies. If
|
||||
* set to `None`, `$cookieSecure` must also be set.
|
||||
*
|
||||
* @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 = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cross Site Request Forgery
|
||||
|--------------------------------------------------------------------------
|
||||
| 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
|
||||
| recommended CSRF protection be enabled.
|
||||
|
|
||||
| CSRFTokenName = The token name
|
||||
| CSRFHeaderName = The header name
|
||||
| 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
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Token Name
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The token name.
|
||||
*
|
||||
* @deprecated Use `Config\Security` $tokenName property instead of using this property.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
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';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Cookie Name
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The cookie name.
|
||||
*
|
||||
* @deprecated Use `Config\Security` $cookieName property instead of using this property.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Regenerate
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Regenerate token on every submission?
|
||||
*
|
||||
* @deprecated Use `Config\Security` $regenerate property instead of using this property.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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:
|
||||
| - http://www.html5rocks.com/en/tutorials/security/content-security-policy/
|
||||
| - http://www.w3.org/TR/CSP/
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* 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
|
||||
*
|
||||
* @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;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Media root folder
|
||||
|--------------------------------------------------------------------------
|
||||
| Defines the root folder for media files storage
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Media root folder
|
||||
* --------------------------------------------------------------------------
|
||||
* Defines the root folder for media files storage
|
||||
*/
|
||||
public $mediaRoot = 'media';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Admin gateway
|
||||
|--------------------------------------------------------------------------
|
||||
| Defines a base route for all admin pages
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Admin gateway
|
||||
* --------------------------------------------------------------------------
|
||||
* Defines a base route for all admin pages
|
||||
*/
|
||||
public $adminGateway = 'cp-admin';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Auth gateway
|
||||
|--------------------------------------------------------------------------
|
||||
| Defines a base route for all authentication related pages
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Auth gateway
|
||||
* --------------------------------------------------------------------------
|
||||
* Defines a base route for all authentication related pages
|
||||
*/
|
||||
public $authGateway = 'cp-auth';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Install gateway
|
||||
|--------------------------------------------------------------------------
|
||||
| Defines a base route for instance installation
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Install gateway
|
||||
* --------------------------------------------------------------------------
|
||||
* Defines a base route for instance installation
|
||||
*/
|
||||
public $installGateway = 'cp-install';
|
||||
}
|
||||
|
|
|
@ -2,90 +2,66 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
require_once SYSTEMPATH . 'Config/AutoloadConfig.php';
|
||||
use CodeIgniter\Config\AutoloadConfig;
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* AUTO-LOADER
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* This file defines the namespaces and class maps so the Autoloader
|
||||
* 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 = [
|
||||
'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
|
||||
* the values in this file will overwrite the framework's values.
|
||||
* Prototype:
|
||||
*
|
||||
* $classmap = [
|
||||
* 'MyClass' => '/path/to/class/file.php'
|
||||
* ];
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
public $classmap = [];
|
||||
}
|
||||
|
|
|
@ -1,33 +1,32 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ERROR DISPLAY
|
||||
|--------------------------------------------------------------------------
|
||||
| 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
|
||||
| painful debugging.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* ERROR DISPLAY
|
||||
* --------------------------------------------------------------------------
|
||||
* 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
|
||||
* painful debugging.
|
||||
*/
|
||||
error_reporting(-1);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG BACKTRACES
|
||||
|--------------------------------------------------------------------------
|
||||
| If true, this constant will tell the error screens to display debug
|
||||
| backtraces along with the other error information. If you would
|
||||
| prefer to not see this, set this value to false.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* DEBUG BACKTRACES
|
||||
* --------------------------------------------------------------------------
|
||||
* If true, this constant will tell the error screens to display debug
|
||||
* backtraces along with the other error information. If you would
|
||||
* prefer to not see this, set this value to false.
|
||||
*/
|
||||
defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG MODE
|
||||
|--------------------------------------------------------------------------
|
||||
| Debug mode is an experimental flag that can allow changes throughout
|
||||
| the system. This will control whether Kint is loaded, and a few other
|
||||
| items. It can always be used within your own application too.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* DEBUG MODE
|
||||
* --------------------------------------------------------------------------
|
||||
* Debug mode is an experimental flag that can allow changes throughout
|
||||
* the system. This will control whether Kint is loaded, and a few other
|
||||
* items. It can always be used within your own application too.
|
||||
*/
|
||||
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', 1);
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', true);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ERROR DISPLAY
|
||||
|--------------------------------------------------------------------------
|
||||
| Don't show ANY in production environments. Instead, let the system catch
|
||||
| it and display a generic error message.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* ERROR DISPLAY
|
||||
* --------------------------------------------------------------------------
|
||||
* Don't show ANY in production environments. Instead, let the system catch
|
||||
* it and display a generic error message.
|
||||
*/
|
||||
ini_set('display_errors', '0');
|
||||
error_reporting(
|
||||
|
@ -14,16 +14,15 @@ error_reporting(
|
|||
~E_DEPRECATED &
|
||||
~E_STRICT &
|
||||
~E_USER_NOTICE &
|
||||
~E_USER_DEPRECATED
|
||||
~E_USER_DEPRECATED,
|
||||
);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG MODE
|
||||
|--------------------------------------------------------------------------
|
||||
| Debug mode is an experimental flag that can allow changes throughout
|
||||
| the system. It's not widely used currently, and may not survive
|
||||
| release of the framework.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* DEBUG MODE
|
||||
* --------------------------------------------------------------------------
|
||||
* Debug mode is an experimental flag that can allow changes throughout
|
||||
* the system. It's not widely used currently, and may not survive
|
||||
* release of the framework.
|
||||
*/
|
||||
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', 0);
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', false);
|
||||
|
|
|
@ -1,33 +1,32 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ERROR DISPLAY
|
||||
|--------------------------------------------------------------------------
|
||||
| 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
|
||||
| painful debugging.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* ERROR DISPLAY
|
||||
* --------------------------------------------------------------------------
|
||||
* 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
|
||||
* painful debugging.
|
||||
*/
|
||||
error_reporting(-1);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG BACKTRACES
|
||||
|--------------------------------------------------------------------------
|
||||
| If true, this constant will tell the error screens to display debug
|
||||
| backtraces along with the other error information. If you would
|
||||
| prefer to not see this, set this value to false.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* DEBUG BACKTRACES
|
||||
* --------------------------------------------------------------------------
|
||||
* If true, this constant will tell the error screens to display debug
|
||||
* backtraces along with the other error information. If you would
|
||||
* prefer to not see this, set this value to false.
|
||||
*/
|
||||
defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG MODE
|
||||
|--------------------------------------------------------------------------
|
||||
| Debug mode is an experimental flag that can allow changes throughout
|
||||
| the system. It's not widely used currently, and may not survive
|
||||
| release of the framework.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* DEBUG MODE
|
||||
* --------------------------------------------------------------------------
|
||||
* Debug mode is an experimental flag that can allow changes throughout
|
||||
* the system. It's not widely used currently, and may not survive
|
||||
* release of the framework.
|
||||
*/
|
||||
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', 1);
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', true);
|
||||
|
|
|
@ -2,83 +2,111 @@
|
|||
|
||||
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;
|
||||
|
||||
class Cache extends BaseConfig
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Primary Handler
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Primary Handler
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $handler = 'file';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Backup Handler
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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
|
||||
| always available, though that's not always practical for the app.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Backup Handler
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
* always available, though that's not always practical for the app.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $backupHandler = 'dummy';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Directory Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The path to where cache files should be stored, if using a file-based
|
||||
| system.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cache Directory Path
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The path to where cache files should be stored, if using a file-based
|
||||
* system.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @deprecated Use the driver-specific variant under $file
|
||||
*/
|
||||
public $storePath = WRITEPATH . 'cache/';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Include Query String
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Whether to take the URL query string into consideration when generating
|
||||
| output cache files. Valid options are:
|
||||
|
|
||||
| false = Disabled
|
||||
| true = Enabled, take all query parameters into account.
|
||||
| Please be aware that this may result in numerous cache
|
||||
| files generated for the same page over and over again.
|
||||
| array('q') = Enabled, but only take into account the specified list
|
||||
| of query parameters.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cache Include Query String
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Whether to take the URL query string into consideration when generating
|
||||
* output cache files. Valid options are:
|
||||
*
|
||||
* false = Disabled
|
||||
* true = Enabled, take all query parameters into account.
|
||||
* Please be aware that this may result in numerous cache
|
||||
* files generated for the same page over and over again.
|
||||
* array('q') = Enabled, but only take into account the specified list
|
||||
* of query parameters.
|
||||
*
|
||||
* @var boolean|string[]
|
||||
*/
|
||||
public $cacheQueryString = false;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Key Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This string is added to all cache item names to help avoid collisions
|
||||
| if you run multiple applications with the same cache engine.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Key Prefix
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This string is added to all cache item names to help avoid collisions
|
||||
* if you run multiple applications with the same cache engine.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $prefix = '';
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------------
|
||||
| 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
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* File settings
|
||||
* --------------------------------------------------------------------------
|
||||
* Your file storage preferences can be specified below, if you are using
|
||||
* the File driver.
|
||||
*
|
||||
* @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 = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
|
@ -86,14 +114,15 @@ class Cache extends BaseConfig
|
|||
'raw' => false,
|
||||
];
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------------
|
||||
| Redis settings
|
||||
| -------------------------------------------------------------------------
|
||||
| Your Redis server can be specified below, if you are using
|
||||
| the Redis or Predis drivers.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* -------------------------------------------------------------------------
|
||||
* Redis settings
|
||||
* -------------------------------------------------------------------------
|
||||
* Your Redis server can be specified below, if you are using
|
||||
* the Redis or Predis drivers.
|
||||
*
|
||||
* @var array<string, string|int|null>
|
||||
*/
|
||||
public $redis = [
|
||||
'host' => '127.0.0.1',
|
||||
'password' => null,
|
||||
|
@ -102,21 +131,22 @@ class Cache extends BaseConfig
|
|||
'database' => 0,
|
||||
];
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available Cache Handlers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is an array of cache engine alias' and class names. Only engines
|
||||
| that are listed here are allowed to be used.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Available Cache Handlers
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This is an array of cache engine alias' and class names. Only engines
|
||||
* that are listed here are allowed to be used.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $validHandlers = [
|
||||
'dummy' => \CodeIgniter\Cache\Handlers\DummyHandler::class,
|
||||
'file' => \CodeIgniter\Cache\Handlers\FileHandler::class,
|
||||
'memcached' => \CodeIgniter\Cache\Handlers\MemcachedHandler::class,
|
||||
'predis' => \CodeIgniter\Cache\Handlers\PredisHandler::class,
|
||||
'redis' => \CodeIgniter\Cache\Handlers\RedisHandler::class,
|
||||
'wincache' => \CodeIgniter\Cache\Handlers\WincacheHandler::class,
|
||||
'dummy' => DummyHandler::class,
|
||||
'file' => FileHandler::class,
|
||||
'memcached' => MemcachedHandler::class,
|
||||
'predis' => PredisHandler::class,
|
||||
'redis' => RedisHandler::class,
|
||||
'wincache' => WincacheHandler::class,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,46 +1,50 @@
|
|||
<?php
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Castopod Version
|
||||
//--------------------------------------------------------------------------
|
||||
// The Castopod version number to display.
|
||||
//
|
||||
// NOTE: this constant is updated upon release with Continuous Integration.
|
||||
//
|
||||
/*
|
||||
| --------------------------------------------------------------------
|
||||
| Castopod Version
|
||||
| --------------------------------------------------------------------
|
||||
|
|
||||
| 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');
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 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
|
||||
// classes should use.
|
||||
//
|
||||
// NOTE: changing this will require manually modifying the
|
||||
// existing namespaces of App\* namespaced-classes.
|
||||
//
|
||||
/*
|
||||
| --------------------------------------------------------------------
|
||||
| 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
|
||||
| classes should use.
|
||||
|
|
||||
| NOTE: changing this will require manually modifying the
|
||||
| existing namespaces of App\* namespaced-classes.
|
||||
*/
|
||||
defined('APP_NAMESPACE') || define('APP_NAMESPACE', 'App');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Composer Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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.
|
||||
*/
|
||||
| --------------------------------------------------------------------------
|
||||
| Composer Path
|
||||
| --------------------------------------------------------------------------
|
||||
|
|
||||
| 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.
|
||||
*/
|
||||
defined('COMPOSER_PATH') ||
|
||||
define('COMPOSER_PATH', ROOTPATH . 'vendor/autoload.php');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Timing Constants
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Provide simple ways to work with the myriad of PHP functions that
|
||||
| require information to be in seconds.
|
||||
*/
|
||||
|--------------------------------------------------------------------------
|
||||
| Timing Constants
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Provide simple ways to work with the myriad of PHP functions that
|
||||
| require information to be in seconds.
|
||||
*/
|
||||
defined('SECOND') || define('SECOND', 1);
|
||||
defined('MINUTE') || define('MINUTE', 60);
|
||||
defined('HOUR') || define('HOUR', 3600);
|
||||
|
@ -51,30 +55,30 @@ defined('YEAR') || define('YEAR', 31536000);
|
|||
defined('DECADE') || define('DECADE', 315360000);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Exit Status Codes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Used to indicate the conditions under which the script is exit()ing.
|
||||
| While there is no universal standard for error codes, there are some
|
||||
| broad conventions. Three such conventions are mentioned below, for
|
||||
| those who wish to make use of them. The CodeIgniter defaults were
|
||||
| chosen for the least overlap with these conventions, while still
|
||||
| leaving room for others to be defined in future versions and user
|
||||
| applications.
|
||||
|
|
||||
| The three main conventions used for determining exit status codes
|
||||
| are as follows:
|
||||
|
|
||||
| Standard C/C++ Library (stdlibc):
|
||||
| http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
|
||||
| (This link also contains other GNU-specific conventions)
|
||||
| BSD sysexits.h:
|
||||
| http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
|
||||
| Bash scripting:
|
||||
| http://tldp.org/LDP/abs/html/exitcodes.html
|
||||
|
|
||||
*/
|
||||
| --------------------------------------------------------------------------
|
||||
| Exit Status Codes
|
||||
| --------------------------------------------------------------------------
|
||||
|
|
||||
| Used to indicate the conditions under which the script is exit()ing.
|
||||
| While there is no universal standard for error codes, there are some
|
||||
| broad conventions. Three such conventions are mentioned below, for
|
||||
| those who wish to make use of them. The CodeIgniter defaults were
|
||||
| chosen for the least overlap with these conventions, while still
|
||||
| leaving room for others to be defined in future versions and user
|
||||
| applications.
|
||||
|
|
||||
| The three main conventions used for determining exit status codes
|
||||
| are as follows:
|
||||
|
|
||||
| Standard C/C++ Library (stdlibc):
|
||||
| http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
|
||||
| (This link also contains other GNU-specific conventions)
|
||||
| BSD sysexits.h:
|
||||
| http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
|
||||
| Bash scripting:
|
||||
| http://tldp.org/LDP/abs/html/exitcodes.html
|
||||
|
|
||||
*/
|
||||
defined('EXIT_SUCCESS') || define('EXIT_SUCCESS', 0); // no errors
|
||||
defined('EXIT_ERROR') || define('EXIT_ERROR', 1); // generic error
|
||||
defined('EXIT_CONFIG') || define('EXIT_CONFIG', 3); // configuration error
|
||||
|
|
|
@ -5,45 +5,155 @@ namespace Config;
|
|||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
/**
|
||||
* Class ContentSecurityPolicyConfig
|
||||
*
|
||||
* Stores the default settings for the ContentSecurityPolicy, if you
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
{
|
||||
// broadbrush CSP management
|
||||
//-------------------------------------------------------------------------
|
||||
// Broadbrush CSP management
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
public $reportOnly = false; // default CSP report context
|
||||
public $reportURI = null; // URL to send violation reports to
|
||||
public $upgradeInsecureRequests = false; // toggle for forcing https
|
||||
/**
|
||||
* Default CSP report context
|
||||
*
|
||||
* @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
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
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';
|
||||
|
||||
/**
|
||||
* Lists allowed stylesheets' URLs.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public $styleSrc = 'self';
|
||||
|
||||
/**
|
||||
* Defines the origins from which images can be loaded.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
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';
|
||||
|
||||
/**
|
||||
* Limits the origins that you can connect to (via XHR,
|
||||
* WebSockets, and EventSource).
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public $connectSrc = 'self';
|
||||
|
||||
/**
|
||||
* Specifies the origins that can serve web fonts.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public $fontSrc = null;
|
||||
|
||||
/**
|
||||
* Lists valid endpoints for submission from `<form>` tags.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Restricts the origins allowed to deliver video and audio.
|
||||
*
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
public $mediaSrc = null;
|
||||
|
||||
/**
|
||||
* Allows control over Flash and other plugins.
|
||||
*
|
||||
* @var string|string[]
|
||||
*/
|
||||
public $objectSrc = 'self';
|
||||
|
||||
/**
|
||||
* @var string|string[]|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;
|
||||
|
||||
// list of actions allowed; string or array of strings
|
||||
/**
|
||||
* List of actions allowed.
|
||||
*
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
public $sandbox = null;
|
||||
}
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Database\Config;
|
||||
|
||||
/**
|
||||
* Database Configuration
|
||||
*
|
||||
* @package Config
|
||||
*/
|
||||
|
||||
class Database extends \CodeIgniter\Database\Config
|
||||
class Database extends Config
|
||||
{
|
||||
/**
|
||||
* The directory that holds the Migrations
|
||||
|
@ -16,7 +15,7 @@ class Database extends \CodeIgniter\Database\Config
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
public $filesPath = APPPATH . 'Database/';
|
||||
public $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
|
||||
|
||||
/**
|
||||
* Lets you choose which connection group to
|
||||
|
@ -41,10 +40,8 @@ class Database extends \CodeIgniter\Database\Config
|
|||
'DBPrefix' => 'cp_',
|
||||
'pConnect' => false,
|
||||
'DBDebug' => ENVIRONMENT !== 'production',
|
||||
'cacheOn' => false,
|
||||
'cacheDir' => '',
|
||||
'charset' => 'utf8',
|
||||
'DBCollat' => 'utf8_general_ci',
|
||||
'charset' => 'utf8mb4',
|
||||
'DBCollat' => 'utf8mb4_unicode_ci',
|
||||
'swapPre' => '',
|
||||
'encrypt' => 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
|
||||
'pConnect' => false,
|
||||
'DBDebug' => ENVIRONMENT !== 'production',
|
||||
'cacheOn' => false,
|
||||
'cacheDir' => '',
|
||||
'charset' => 'utf8',
|
||||
'DBCollat' => 'utf8_general_ci',
|
||||
'swapPre' => '',
|
||||
|
@ -92,21 +87,6 @@ class Database extends \CodeIgniter\Database\Config
|
|||
// we don't overwrite live data on accident.
|
||||
if (ENVIRONMENT === 'testing') {
|
||||
$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;
|
||||
|
||||
/**
|
||||
* DocTypes
|
||||
*
|
||||
* @package Config
|
||||
*/
|
||||
|
||||
class DocTypes
|
||||
{
|
||||
/**
|
||||
* List of valid document types.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $list = [
|
||||
'xhtml11' =>
|
||||
'<!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
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption Key Starter
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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.
|
||||
| See the user guide for more info.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Encryption Key Starter
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
* See the user guide for more info.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
|
||||
public $key = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption driver to use
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| One of the supported drivers, eg 'OpenSSL' or 'Sodium'.
|
||||
| The default driver, if you don't specify one, is 'OpenSSL'.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Encryption Driver to Use
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* One of the supported encryption drivers.
|
||||
*
|
||||
* Available drivers:
|
||||
* - OpenSSL
|
||||
* - Sodium
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
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;
|
||||
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\Exceptions\FrameworkException;
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------
|
||||
|
@ -23,11 +24,15 @@ use CodeIgniter\Events\Events;
|
|||
|
||||
Events::on('pre_system', function () {
|
||||
if (ENVIRONMENT !== 'testing') {
|
||||
while (\ob_get_level() > 0) {
|
||||
\ob_end_flush();
|
||||
if (ini_get('zlib.output_compression')) {
|
||||
throw FrameworkException::forEnabledZlibOutputCompression();
|
||||
}
|
||||
|
||||
\ob_start(function ($buffer) {
|
||||
while (ob_get_level() > 0) {
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
ob_start(function ($buffer) {
|
||||
return $buffer;
|
||||
});
|
||||
}
|
||||
|
@ -38,11 +43,98 @@ Events::on('pre_system', function () {
|
|||
* --------------------------------------------------------------------
|
||||
* If you delete, they will no longer be collected.
|
||||
*/
|
||||
if (ENVIRONMENT !== 'production') {
|
||||
if (CI_DEBUG) {
|
||||
Events::on(
|
||||
'DBQuery',
|
||||
'CodeIgniter\Debug\Toolbar\Collectors\Database::collect'
|
||||
'CodeIgniter\Debug\Toolbar\Collectors\Database::collect',
|
||||
);
|
||||
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;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
/**
|
||||
* Setup how the exception handler works.
|
||||
*
|
||||
* @package Config
|
||||
*/
|
||||
|
||||
class Exceptions
|
||||
class Exceptions extends BaseConfig
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| LOG EXCEPTIONS?
|
||||
|--------------------------------------------------------------------------
|
||||
| If true, then exceptions will be logged
|
||||
| through Services::Log.
|
||||
|
|
||||
| Default: true
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* LOG EXCEPTIONS?
|
||||
* --------------------------------------------------------------------------
|
||||
* If true, then exceptions will be logged
|
||||
* through Services::Log.
|
||||
*
|
||||
* Default: true
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $log = true;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DO NOT LOG STATUS CODES
|
||||
|--------------------------------------------------------------------------
|
||||
| Any status codes here will NOT be logged if logging is turned on.
|
||||
| By default, only 404 (Page Not Found) exceptions are ignored.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* DO NOT LOG STATUS CODES
|
||||
* --------------------------------------------------------------------------
|
||||
* Any status codes here will NOT be logged if logging is turned on.
|
||||
* By default, only 404 (Page Not Found) exceptions are ignored.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $ignoreCodes = [404];
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Error Views Path
|
||||
|--------------------------------------------------------------------------
|
||||
| This is the path to the directory that contains the 'cli' and 'html'
|
||||
| directories that hold the views used to generate errors.
|
||||
|
|
||||
| Default: APPPATH.'Views/errors'
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Error Views Path
|
||||
* --------------------------------------------------------------------------
|
||||
* This is the path to the directory that contains the 'cli' and 'html'
|
||||
* directories that hold the views used to generate errors.
|
||||
*
|
||||
* Default: APPPATH.'Views/errors'
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $errorViewPath = APPPATH . 'Views/errors';
|
||||
}
|
||||
|
|
|
@ -3,40 +3,65 @@
|
|||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Filters\CSRF;
|
||||
use CodeIgniter\Filters\DebugToolbar;
|
||||
use CodeIgniter\Filters\Honeypot;
|
||||
|
||||
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 = [
|
||||
'csrf' => \CodeIgniter\Filters\CSRF::class,
|
||||
'toolbar' => \CodeIgniter\Filters\DebugToolbar::class,
|
||||
'honeypot' => \CodeIgniter\Filters\Honeypot::class,
|
||||
'csrf' => CSRF::class,
|
||||
'toolbar' => DebugToolbar::class,
|
||||
'honeypot' => Honeypot::class,
|
||||
'login' => \Myth\Auth\Filters\LoginFilter::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 = [
|
||||
'before' => [
|
||||
//'honeypot'
|
||||
// 'honeypot',
|
||||
// 'csrf',
|
||||
],
|
||||
'after' => [
|
||||
'toolbar',
|
||||
//'honeypot'
|
||||
// 'honeypot',
|
||||
],
|
||||
];
|
||||
|
||||
// Works on all of a particular HTTP method
|
||||
// (GET, POST, etc) as BEFORE filters only
|
||||
// like: 'post' => ['CSRF', 'throttle'],
|
||||
/**
|
||||
* List of filter aliases that works on a
|
||||
* particular HTTP method (GET, POST, etc.).
|
||||
*
|
||||
* Example:
|
||||
* 'post' => ['csrf', 'throttle']
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $methods = [];
|
||||
|
||||
// List filter aliases and any before/after uri patterns
|
||||
// that they should run on, like:
|
||||
// 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']],
|
||||
/**
|
||||
* List of filter aliases that should run on any
|
||||
* before or after URI patterns.
|
||||
*
|
||||
* Example:
|
||||
* 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $filters = [];
|
||||
|
||||
public function __construct()
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
class ForeignCharacters extends \CodeIgniter\Config\ForeignCharacters
|
||||
use CodeIgniter\Config\ForeignCharacters as BaseForeignCharacters;
|
||||
|
||||
class ForeignCharacters extends BaseForeignCharacters
|
||||
{
|
||||
}
|
||||
|
|
|
@ -3,43 +3,62 @@
|
|||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Format\FormatterInterface;
|
||||
|
||||
class Format extends BaseConfig
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available Response Formats
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When you perform content negotiation with the request, these are the
|
||||
| available formats that your application supports. This is currently
|
||||
| only used with the API\ResponseTrait. A valid Formatter must exist
|
||||
| for the specified format.
|
||||
|
|
||||
| These formats are only checked when the data passed to the respond()
|
||||
| method is an array.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Available Response Formats
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* When you perform content negotiation with the request, these are the
|
||||
* available formats that your application supports. This is currently
|
||||
* only used with the API\ResponseTrait. A valid Formatter must exist
|
||||
* for the specified format.
|
||||
*
|
||||
* These formats are only checked when the data passed to the respond()
|
||||
* method is an array.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $supportedResponseFormats = [
|
||||
'application/json',
|
||||
'application/xml', // machine-readable XML
|
||||
'text/xml', // human-readable XML
|
||||
];
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Formatters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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
|
||||
| can be retrieved through the getFormatter() method.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Formatters
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
* can be retrieved through the getFormatter() method.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $formatters = [
|
||||
'application/json' => \CodeIgniter\Format\JSONFormatter::class,
|
||||
'application/xml' => \CodeIgniter\Format\XMLFormatter::class,
|
||||
'text/xml' => \CodeIgniter\Format\XMLFormatter::class,
|
||||
'application/json' => 'CodeIgniter\Format\JSONFormatter',
|
||||
'application/xml' => 'CodeIgniter\Format\XMLFormatter',
|
||||
'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
|
||||
*
|
||||
* @return \CodeIgniter\Format\FormatterInterface
|
||||
* @return FormatterInterface
|
||||
*
|
||||
* @deprecated This is an alias of `\CodeIgniter\Format\Format::getFormatter`. Use that instead.
|
||||
*/
|
||||
public function getFormatter(string $mime)
|
||||
{
|
||||
if (!array_key_exists($mime, $this->formatters)) {
|
||||
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();
|
||||
return Services::format()->getFormatter($mime);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
public $hidden = true;
|
||||
|
||||
/**
|
||||
* Honeypot Label Content
|
||||
*
|
||||
|
@ -32,4 +33,11 @@ class Honeypot extends BaseConfig
|
|||
* @var string
|
||||
*/
|
||||
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;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Images\Handlers\GDHandler;
|
||||
use CodeIgniter\Images\Handlers\ImageMagickHandler;
|
||||
|
||||
class Images extends BaseConfig
|
||||
{
|
||||
|
@ -24,20 +26,20 @@ class Images extends BaseConfig
|
|||
/**
|
||||
* The available handler classes.
|
||||
*
|
||||
* @var array
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $handlers = [
|
||||
'gd' => \CodeIgniter\Images\Handlers\GDHandler::class,
|
||||
'imagick' => \CodeIgniter\Images\Handlers\ImageMagickHandler::class,
|
||||
'gd' => GDHandler::class,
|
||||
'imagick' => ImageMagickHandler::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Uploaded images resizing sizes (in px)
|
||||
* --------------------------------------------------------------------------
|
||||
* 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).
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Uploaded images resizing sizes (in px)
|
||||
|--------------------------------------------------------------------------
|
||||
| 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).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
|
@ -68,12 +70,12 @@ class Images extends BaseConfig
|
|||
*/
|
||||
public $id3Size = 500;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Uploaded images naming extensions
|
||||
* --------------------------------------------------------------------------
|
||||
* The properties listed below set the name extensions for the resized images
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Uploaded images naming extensions
|
||||
|--------------------------------------------------------------------------
|
||||
| The properties listed below set the name extensions for the resized images
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
|
|
@ -5,26 +5,23 @@ namespace Config;
|
|||
use CodeIgniter\Config\BaseConfig;
|
||||
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
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Kint
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|--------------------------------------------------------------------------
|
||||
| Global Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public $plugins = null;
|
||||
|
||||
|
@ -35,10 +32,10 @@ class Kint extends BaseConfig
|
|||
public $expanded = false;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| RichRenderer Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|--------------------------------------------------------------------------
|
||||
| RichRenderer Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
public $richTheme = 'aante-light.css';
|
||||
|
||||
public $richFolder = false;
|
||||
|
@ -50,10 +47,10 @@ class Kint extends BaseConfig
|
|||
public $richTabPlugins = null;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| CLI Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|--------------------------------------------------------------------------
|
||||
| CLI Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
public $cliColors = true;
|
||||
|
||||
public $cliForceUTF8 = false;
|
||||
|
|
|
@ -6,76 +6,82 @@ use CodeIgniter\Config\BaseConfig;
|
|||
|
||||
class Logger extends BaseConfig
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Error Logging Threshold
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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 will be logged. Threshold options are:
|
||||
|
|
||||
| 0 = Disables logging, Error logging TURNED OFF
|
||||
| 1 = Emergency Messages - System is unusable
|
||||
| 2 = Alert Messages - Action Must Be Taken Immediately
|
||||
| 3 = Critical Messages - Application component unavailable, unexpected exception.
|
||||
| 4 = Runtime Errors - Don't need immediate action, but should be monitored.
|
||||
| 5 = Warnings - Exceptional occurrences that are not errors.
|
||||
| 6 = Notices - Normal but significant events.
|
||||
| 7 = Info - Interesting events, like user logging in, etc.
|
||||
| 8 = Debug - Detailed debug information.
|
||||
| 9 = All Messages
|
||||
|
|
||||
| You can also pass an array with threshold levels to show individual error types
|
||||
|
|
||||
| array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages
|
||||
|
|
||||
| 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;
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Error Logging Threshold
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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 will be logged.
|
||||
*
|
||||
* Threshold options are:
|
||||
*
|
||||
* - 0 = Disables logging, Error logging TURNED OFF
|
||||
* - 1 = Emergency Messages - System is unusable
|
||||
* - 2 = Alert Messages - Action Must Be Taken Immediately
|
||||
* - 3 = Critical Messages - Application component unavailable, unexpected exception.
|
||||
* - 4 = Runtime Errors - Don't need immediate action, but should be monitored.
|
||||
* - 5 = Warnings - Exceptional occurrences that are not errors.
|
||||
* - 6 = Notices - Normal but significant events.
|
||||
* - 7 = Info - Interesting events, like user logging in, etc.
|
||||
* - 8 = Debug - Detailed debug information.
|
||||
* - 9 = All Messages
|
||||
*
|
||||
* You can also pass an array with threshold levels to show individual error types
|
||||
*
|
||||
* array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages
|
||||
*
|
||||
* For a live site you'll usually enable Critical or higher (3) to be logged otherwise
|
||||
* your log files will fill up very fast.
|
||||
*
|
||||
* @var integer|array
|
||||
*/
|
||||
public $threshold = 4;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Date Format for Logs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Each item that is logged has an associated date. You can use PHP date
|
||||
| codes to set your own date formatting
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Date Format for Logs
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Each item that is logged has an associated date. You can use PHP date
|
||||
* codes to set your own date formatting
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $dateFormat = 'Y-m-d H:i:s';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log Handlers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The logging system supports multiple actions to be taken when something
|
||||
| is logged. This is done by allowing for multiple Handlers, special classes
|
||||
| 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
|
||||
| as emailing the dev team.
|
||||
|
|
||||
| Each handler is defined by the class name used for that handler, and it
|
||||
| MUST implement the CodeIgniter\Log\Handlers\HandlerInterface interface.
|
||||
|
|
||||
| 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
|
||||
| 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
|
||||
| Psr\Log\LogLevel class.
|
||||
|
|
||||
| Handlers are executed in the order defined in this array, starting with
|
||||
| the handler on top and continuing down.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Log Handlers
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The logging system supports multiple actions to be taken when something
|
||||
* is logged. This is done by allowing for multiple Handlers, special classes
|
||||
* 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
|
||||
* as emailing the dev team.
|
||||
*
|
||||
* Each handler is defined by the class name used for that handler, and it
|
||||
* MUST implement the `CodeIgniter\Log\Handlers\HandlerInterface` interface.
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* `Psr\Log\LogLevel` class.
|
||||
*
|
||||
* Handlers are executed in the order defined in this array, starting with
|
||||
* the handler on top and continuing down.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $handlers = [
|
||||
//--------------------------------------------------------------------
|
||||
// File Handler
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------
|
||||
* File Handler
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
'CodeIgniter\Log\Handlers\FileHandler' => [
|
||||
/*
|
||||
* The log levels that this handler will handle.
|
||||
|
|
|
@ -6,46 +6,50 @@ use CodeIgniter\Config\BaseConfig;
|
|||
|
||||
class Migrations extends BaseConfig
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enable/Disable Migrations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Migrations are enabled by default for security reasons.
|
||||
| You should enable migrations whenever you intend to do a schema migration
|
||||
| and disable it back when you're done.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Enable/Disable Migrations
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $enabled = true;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Migrations table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 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
|
||||
| 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
|
||||
| will migrate up. This must be set.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Migrations Table
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* will migrate up. This must be set.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $table = 'migrations';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Timestamp Format
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the format that will be used when creating new migrations
|
||||
| using the cli command:
|
||||
| > php spark migrate:create
|
||||
|
|
||||
| Typical formats:
|
||||
| YmdHis_
|
||||
| Y-m-d-His_
|
||||
| Y_m_d_His_
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Timestamp Format
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This is the format that will be used when creating new migrations
|
||||
* using the CLI command:
|
||||
* > php spark migrate:create
|
||||
*
|
||||
* Typical formats:
|
||||
* - YmdHis_
|
||||
* - Y-m-d-His_
|
||||
* - Y_m_d_His_
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $timestampFormat = 'Y-m-d-His_';
|
||||
}
|
||||
|
|
|
@ -2,19 +2,21 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| MIME TYPES
|
||||
| -------------------------------------------------------------------
|
||||
| This file contains an array of mime types. It is used by the
|
||||
| Upload class to help identify allowed file types.
|
||||
|
|
||||
| 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*
|
||||
| methods. The same applies when more than one mime-type exists for a
|
||||
| single extension.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* Mimes
|
||||
*
|
||||
* This file contains an array of mime types. It is used by the
|
||||
* Upload class to help identify allowed file types.
|
||||
*
|
||||
* 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*
|
||||
* methods. The same applies when more than one mime-type exists for a
|
||||
* single extension.
|
||||
*
|
||||
* When working with mime types, please make sure you have the ´fileinfo´
|
||||
* extension enabled to reliably detect the media types.
|
||||
*/
|
||||
|
||||
class Mimes
|
||||
{
|
||||
/**
|
||||
|
@ -34,7 +36,6 @@ class Mimes
|
|||
'text/csv',
|
||||
'text/x-comma-separated-values',
|
||||
'text/comma-separated-values',
|
||||
'application/octet-stream',
|
||||
'application/vnd.ms-excel',
|
||||
'application/x-csv',
|
||||
'text/x-csv',
|
||||
|
@ -64,7 +65,6 @@ class Mimes
|
|||
'application/pdf',
|
||||
'application/force-download',
|
||||
'application/x-download',
|
||||
'binary/octet-stream',
|
||||
],
|
||||
'ai' => ['application/pdf', 'application/postscript'],
|
||||
'eps' => 'application/postscript',
|
||||
|
@ -134,6 +134,7 @@ class Mimes
|
|||
'multipart/x-zip',
|
||||
],
|
||||
'rar' => [
|
||||
'application/vnd.rar',
|
||||
'application/x-rar',
|
||||
'application/rar',
|
||||
'application/x-rar-compressed',
|
||||
|
@ -305,15 +306,18 @@ class Mimes
|
|||
'application/x-jar',
|
||||
'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',
|
||||
'srt' => ['text/srt', 'text/plain', 'application/octet-stream'],
|
||||
'vtt' => ['text/vtt', 'text/plain'],
|
||||
'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.
|
||||
*
|
||||
|
@ -334,41 +338,47 @@ class Mimes
|
|||
: static::$mimes[$extension];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Attempts to determine the best file extension for a given mime type.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $proposed_extension - default extension (in case there is more than one with the same mime type)
|
||||
* @param string $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.
|
||||
*/
|
||||
public static function guessExtensionFromType(
|
||||
string $type,
|
||||
?string $proposed_extension = null
|
||||
string $proposedExtension = null
|
||||
) {
|
||||
$type = trim(strtolower($type), '. ');
|
||||
|
||||
$proposed_extension = trim(strtolower($proposed_extension));
|
||||
$proposedExtension = trim(strtolower($proposedExtension));
|
||||
|
||||
if (
|
||||
!is_null($proposed_extension) &&
|
||||
array_key_exists($proposed_extension, static::$mimes) &&
|
||||
in_array(
|
||||
$type,
|
||||
is_string(static::$mimes[$proposed_extension])
|
||||
? [static::$mimes[$proposed_extension]]
|
||||
: static::$mimes[$proposed_extension]
|
||||
)
|
||||
) {
|
||||
return $proposed_extension;
|
||||
if ($proposedExtension !== '') {
|
||||
if (
|
||||
array_key_exists($proposedExtension, static::$mimes) &&
|
||||
in_array(
|
||||
$type,
|
||||
is_string(static::$mimes[$proposedExtension])
|
||||
? [static::$mimes[$proposedExtension]]
|
||||
: static::$mimes[$proposedExtension],
|
||||
true,
|
||||
)
|
||||
) {
|
||||
// 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) {
|
||||
if (
|
||||
(is_string($types) && $types === $type) ||
|
||||
(is_array($types) && in_array($type, $types))
|
||||
(is_array($types) && in_array($type, $types, true))
|
||||
) {
|
||||
return $ext;
|
||||
}
|
||||
|
@ -376,6 +386,4 @@ class Mimes
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
|
|
|
@ -2,62 +2,46 @@
|
|||
|
||||
namespace Config;
|
||||
|
||||
// Cannot extend BaseConfig or looping resources occurs.
|
||||
class Modules
|
||||
use CodeIgniter\Modules\Modules as BaseModules;
|
||||
|
||||
class Modules extends BaseModules
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Auto-Discovery Enabled?
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If true, then auto-discovery will happen across all elements listed in
|
||||
| $activeExplorers below. If false, no auto-discovery will happen at all,
|
||||
| giving a slight performance boost.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Enable Auto-Discovery?
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If true, then auto-discovery will happen across all elements listed in
|
||||
* $activeExplorers below. If false, no auto-discovery will happen at all,
|
||||
* giving a slight performance boost.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $enabled = true;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Auto-Discovery Within Composer Packages Enabled?
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If true, then auto-discovery will happen across all namespaces loaded
|
||||
| by Composer, as well as the namespaces configured locally.
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Enable Auto-Discovery Within Composer Packages?
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If true, then auto-discovery will happen across all namespaces loaded
|
||||
* by Composer, as well as the namespaces configured locally.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
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:
|
||||
* - events
|
||||
* - registrars
|
||||
* - routes
|
||||
* - services
|
||||
* Aliases list of all discovery classes that will be active and used during
|
||||
* the current application request.
|
||||
*
|
||||
* @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)
|
||||
{
|
||||
if (!$this->enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$alias = strtolower($alias);
|
||||
|
||||
return in_array($alias, $this->activeExplorers);
|
||||
}
|
||||
public $aliases = ['events', 'filters', 'registrars', 'routes', 'services'];
|
||||
}
|
||||
|
|
|
@ -6,32 +6,34 @@ use CodeIgniter\Config\BaseConfig;
|
|||
|
||||
class Pager extends BaseConfig
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Templates
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Pagination links are rendered out using views to configure their
|
||||
| appearance. This array contains aliases and the view names to
|
||||
| use when rendering the links.
|
||||
|
|
||||
| Within each view, the Pager object will be available as $pager,
|
||||
| and the desired group as $pagerGroup;
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Templates
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Pagination links are rendered out using views to configure their
|
||||
* appearance. This array contains aliases and the view names to
|
||||
* use when rendering the links.
|
||||
*
|
||||
* Within each view, the Pager object will be available as $pager,
|
||||
* and the desired group as $pagerGroup;
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $templates = [
|
||||
'default_full' => 'App\Views\pager\default_full',
|
||||
'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
|
||||
'default_head' => 'CodeIgniter\Pager\Views\default_head',
|
||||
];
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Items Per Page
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default number of results shown in a single page.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Items Per Page
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The default number of results shown in a single page.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $perPage = 20;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
namespace Config;
|
||||
|
||||
/**
|
||||
* Paths
|
||||
*
|
||||
* Holds the paths that are used by the system to
|
||||
* 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.
|
||||
*
|
||||
* All paths are relative to the project's root folder.
|
||||
|
@ -13,34 +16,35 @@ namespace Config;
|
|||
|
||||
class Paths
|
||||
{
|
||||
/*
|
||||
*---------------------------------------------------------------
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* SYSTEM FOLDER NAME
|
||||
*---------------------------------------------------------------
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* This variable must contain the name of your "system" folder.
|
||||
* Include the path if the folder is not in the same directory
|
||||
* as this file.
|
||||
* This must contain the name of your "system" folder. Include
|
||||
* the path if the folder is not in the same directory as this file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $systemDirectory =
|
||||
__DIR__ . '/../../vendor/codeigniter4/codeigniter4/system';
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* APPLICATION FOLDER NAME
|
||||
*---------------------------------------------------------------
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* If you want this front controller to use a different "app"
|
||||
* folder than the default one you can set its name here. The folder
|
||||
* 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:
|
||||
* http://codeigniter.com/user_guide/general/managing_apps.html
|
||||
* you do, use a full getServer path.
|
||||
*
|
||||
* NO TRAILING SLASH!
|
||||
* @see http://codeigniter.com/user_guide/general/managing_apps.html
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $appDirectory = __DIR__ . '/..';
|
||||
|
||||
/*
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* WRITABLE DIRECTORY NAME
|
||||
* ---------------------------------------------------------------
|
||||
|
@ -50,23 +54,23 @@ class Paths
|
|||
* need write permission to a single place that can be tucked away
|
||||
* for maximum security, keeping it out of the app and/or
|
||||
* system directories.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $writableDirectory = __DIR__ . '/../../writable';
|
||||
|
||||
/*
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* TESTS DIRECTORY NAME
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
* for maximum security, keeping it out of the app and/or
|
||||
* system directories.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $testsDirectory = __DIR__ . '/../../tests';
|
||||
|
||||
/*
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* VIEW DIRECTORY NAME
|
||||
* ---------------------------------------------------------------
|
||||
|
@ -75,6 +79,8 @@ class Paths
|
|||
* contains the view files used by your application. By
|
||||
* default this is in `app/Views`. This value
|
||||
* is used when no value is provided to `Services::renderer()`.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
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('base64', '[A-Za-z0-9\.\_]+\-{0,2}');
|
||||
$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)
|
||||
$routes->add('audio/(:base64)/(:any)', 'Analytics::hit/$1/$2', [
|
||||
$routes->get('audio/(:base64)/(:any)', 'Analytics::hit/$1/$2', [
|
||||
'as' => 'analytics_hit',
|
||||
]);
|
||||
|
||||
|
@ -150,7 +159,7 @@ $routes->group(
|
|||
$routes->post('edit', 'Podcast::attemptEdit/$1', [
|
||||
'filter' => 'permission:podcast-edit',
|
||||
]);
|
||||
$routes->add('delete', 'Podcast::delete/$1', [
|
||||
$routes->get('delete', 'Podcast::delete/$1', [
|
||||
'as' => 'podcast-delete',
|
||||
'filter' => 'permission:podcasts-delete',
|
||||
]);
|
||||
|
@ -170,7 +179,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'podcast-person-remove',
|
||||
'filter' => 'permission:podcast-edit',
|
||||
]
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -185,7 +194,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'podcast-analytics-webpages',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'locations',
|
||||
|
@ -193,7 +202,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'podcast-analytics-locations',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'unique-listeners',
|
||||
|
@ -201,7 +210,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'podcast-analytics-unique-listeners',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'listening-time',
|
||||
|
@ -209,7 +218,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'podcast-analytics-listening-time',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'time-periods',
|
||||
|
@ -217,7 +226,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'podcast-analytics-time-periods',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'players',
|
||||
|
@ -225,7 +234,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'podcast-analytics-players',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -235,7 +244,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'analytics-full-data',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'analytics-data/(:segment)/(:segment)',
|
||||
|
@ -243,7 +252,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'analytics-data',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'analytics-data/(:segment)/(:segment)/(:num)',
|
||||
|
@ -251,7 +260,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'analytics-filtered-data',
|
||||
'filter' => 'permission:podcasts-view,podcast-view',
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
// Podcast episodes
|
||||
|
@ -283,7 +292,50 @@ $routes->group(
|
|||
$routes->post('edit', 'Episode::attemptEdit/$1/$2', [
|
||||
'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',
|
||||
'filter' => 'permission:podcast_episodes-delete',
|
||||
]);
|
||||
|
@ -293,7 +345,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'transcript-delete',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'chapters-delete',
|
||||
|
@ -301,7 +353,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'chapters-delete',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'soundbites',
|
||||
|
@ -309,22 +361,22 @@ $routes->group(
|
|||
[
|
||||
'as' => 'soundbites-edit',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'soundbites',
|
||||
'Episode::soundbitesAttemptEdit/$1/$2',
|
||||
[
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->add(
|
||||
$routes->get(
|
||||
'soundbites/(:num)/delete',
|
||||
'Episode::soundbiteDelete/$1/$2/$3',
|
||||
[
|
||||
'as' => 'soundbite-delete',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'embeddable-player',
|
||||
|
@ -332,7 +384,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'embeddable-player-add',
|
||||
'filter' => 'permission:podcast_episodes-edit',
|
||||
]
|
||||
],
|
||||
);
|
||||
|
||||
$routes->group('persons', function ($routes) {
|
||||
|
@ -346,7 +398,7 @@ $routes->group(
|
|||
[
|
||||
'filter' =>
|
||||
'permission:podcast_episodes-edit',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'(:num)/remove',
|
||||
|
@ -355,7 +407,7 @@ $routes->group(
|
|||
'as' => 'episode-person-remove',
|
||||
'filter' =>
|
||||
'permission:podcast_episodes-edit',
|
||||
]
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -394,9 +446,9 @@ $routes->group(
|
|||
[
|
||||
'filter' =>
|
||||
'permission:podcast-manage_contributors',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->add('remove', 'Contributor::remove/$1/$2', [
|
||||
$routes->get('remove', 'Contributor::remove/$1/$2', [
|
||||
'as' => 'contributor-remove',
|
||||
'filter' =>
|
||||
'permission:podcast-manage_contributors',
|
||||
|
@ -411,7 +463,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'platforms-podcasting',
|
||||
'filter' => 'permission:podcast-manage_platforms',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'social',
|
||||
|
@ -419,7 +471,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'platforms-social',
|
||||
'filter' => 'permission:podcast-manage_platforms',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->get(
|
||||
'funding',
|
||||
|
@ -427,7 +479,7 @@ $routes->group(
|
|||
[
|
||||
'as' => 'platforms-funding',
|
||||
'filter' => 'permission:podcast-manage_platforms',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->post(
|
||||
'save/(:platformType)',
|
||||
|
@ -435,20 +487,35 @@ $routes->group(
|
|||
[
|
||||
'as' => 'platforms-save',
|
||||
'filter' => 'permission:podcast-manage_platforms',
|
||||
]
|
||||
],
|
||||
);
|
||||
$routes->add(
|
||||
$routes->get(
|
||||
'(:slug)/podcast-platform-remove',
|
||||
'PodcastPlatform::removePodcastPlatform/$1/$2',
|
||||
[
|
||||
'as' => 'podcast-platform-remove',
|
||||
'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
|
||||
$routes->group('pages', function ($routes) {
|
||||
$routes->get('/', 'Page::list', ['as' => 'page-list']);
|
||||
|
@ -470,7 +537,7 @@ $routes->group(
|
|||
'filter' => 'permission:pages-manage',
|
||||
]);
|
||||
|
||||
$routes->add('delete', 'Page::delete/$1', [
|
||||
$routes->get('delete', 'Page::delete/$1', [
|
||||
'as' => 'page-delete',
|
||||
'filter' => 'permission:pages-manage',
|
||||
]);
|
||||
|
@ -504,19 +571,19 @@ $routes->group(
|
|||
$routes->post('edit', 'User::attemptEdit/$1', [
|
||||
'filter' => 'permission:users-manage_authorizations',
|
||||
]);
|
||||
$routes->add('ban', 'User::ban/$1', [
|
||||
$routes->get('ban', 'User::ban/$1', [
|
||||
'as' => 'user-ban',
|
||||
'filter' => 'permission:users-manage_bans',
|
||||
]);
|
||||
$routes->add('unban', 'User::unBan/$1', [
|
||||
$routes->get('unban', 'User::unBan/$1', [
|
||||
'as' => 'user-unban',
|
||||
'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',
|
||||
'filter' => 'permission:users-force_pass_reset',
|
||||
]);
|
||||
$routes->add('delete', 'User::delete/$1', [
|
||||
$routes->get('delete', 'User::delete/$1', [
|
||||
'as' => 'user-delete',
|
||||
'filter' => 'permission:users-delete',
|
||||
]);
|
||||
|
@ -533,7 +600,7 @@ $routes->group(
|
|||
]);
|
||||
$routes->post('change-password', 'MyAccount::attemptChange/$1');
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -570,35 +637,142 @@ $routes->group(config('App')->authGateway, function ($routes) {
|
|||
$routes->post('reset-password', 'Auth::attemptReset');
|
||||
});
|
||||
|
||||
// Public routes
|
||||
// Podcast's Public routes
|
||||
$routes->group('@(:podcastName)', function ($routes) {
|
||||
$routes->get('/', 'Podcast/$1', ['as' => 'podcast']);
|
||||
$routes->group('(:slug)', function ($routes) {
|
||||
$routes->get('/', 'Podcast::activity/$1', [
|
||||
'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', [
|
||||
'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->get('/', 'Episode::embeddablePlayer/$1/$2', [
|
||||
'as' => 'embeddable-player',
|
||||
]);
|
||||
$routes->get('(:slug)', 'Episode::embeddablePlayer/$1/$2/$3', [
|
||||
'as' => 'embeddable-player-theme',
|
||||
]);
|
||||
$routes->get(
|
||||
'(:embeddablePlayerTheme)',
|
||||
'Episode::embeddablePlayer/$1/$2/$3',
|
||||
[
|
||||
'as' => 'embeddable-player-theme',
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
$routes->head('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('/(: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
|
||||
* --------------------------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
use CodeIgniter\Config\Services as CoreServices;
|
||||
use CodeIgniter\Config\BaseService;
|
||||
use CodeIgniter\Model;
|
||||
use App\Authorization\FlatAuthorization;
|
||||
use App\Authorization\PermissionModel;
|
||||
use App\Authorization\GroupModel;
|
||||
use App\Libraries\Breadcrumb;
|
||||
use App\Libraries\Negotiate;
|
||||
use App\Libraries\Router;
|
||||
use App\Models\UserModel;
|
||||
use CodeIgniter\HTTP\Request;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\Router\RouteCollectionInterface;
|
||||
use Myth\Auth\Models\LoginModel;
|
||||
|
||||
require_once SYSTEMPATH . 'Config/Services.php';
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* 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(
|
||||
string $lib = 'local',
|
||||
Model $userModel = null,
|
||||
|
@ -39,7 +90,7 @@ class Services extends CoreServices
|
|||
'authentication',
|
||||
$lib,
|
||||
$userModel,
|
||||
$loginModel
|
||||
$loginModel,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -72,7 +123,7 @@ class Services extends CoreServices
|
|||
'authorization',
|
||||
$groupModel,
|
||||
$permissionModel,
|
||||
$userModel
|
||||
$userModel,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,69 +3,85 @@
|
|||
namespace Config;
|
||||
|
||||
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
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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.
|
||||
|
|
||||
| toolbarMaxHistory = Number of history files, 0 for none or -1 for unlimited
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Toolbar Collectors
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* List of toolbar collectors that will be called when Debug Toolbar
|
||||
* fires up and collects data from.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $collectors = [
|
||||
\CodeIgniter\Debug\Toolbar\Collectors\Timers::class,
|
||||
\CodeIgniter\Debug\Toolbar\Collectors\Database::class,
|
||||
\CodeIgniter\Debug\Toolbar\Collectors\Logs::class,
|
||||
\CodeIgniter\Debug\Toolbar\Collectors\Views::class,
|
||||
\CodeIgniter\Debug\Toolbar\Collectors\Cache::class,
|
||||
\CodeIgniter\Debug\Toolbar\Collectors\Files::class,
|
||||
\CodeIgniter\Debug\Toolbar\Collectors\Routes::class,
|
||||
\CodeIgniter\Debug\Toolbar\Collectors\Events::class,
|
||||
\Myth\Auth\Collectors\Auth::class,
|
||||
Timers::class,
|
||||
Database::class,
|
||||
Logs::class,
|
||||
Views::class,
|
||||
// Cache::class,
|
||||
Files::class,
|
||||
Routes::class,
|
||||
Events::class,
|
||||
];
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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
|
||||
| view and compare multiple requests.
|
||||
|
|
||||
| $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
|
||||
| 0 (zero) to not have any history stored, or -1 for unlimited history.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Max 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
|
||||
* 0 (zero) to not have any history stored, or -1 for unlimited history.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $maxHistory = 20;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Toolbar Views Path
|
||||
|--------------------------------------------------------------------------
|
||||
| The full path to the the views that are used by the toolbar.
|
||||
| MUST have a trailing slash.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Toolbar Views Path
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* 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/';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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
|
||||
| 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.
|
||||
|
|
||||
*/
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $maxQueries = 100;
|
||||
}
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
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
|
||||
{
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| USER AGENT TYPES
|
||||
| -------------------------------------------------------------------
|
||||
| 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.
|
||||
*/
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* OS Platforms
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $platforms = [
|
||||
'windows nt 10.0' => 'Windows 10',
|
||||
'windows nt 6.3' => 'Windows 8.1',
|
||||
|
@ -60,12 +67,21 @@ class UserAgents extends BaseConfig
|
|||
'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 = [
|
||||
'OPR' => 'Opera',
|
||||
'Flock' => 'Flock',
|
||||
'Edge' => 'Spartan',
|
||||
'Edg' => 'Edge',
|
||||
'Chrome' => 'Chrome',
|
||||
// Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
|
||||
'Opera.*?Version' => 'Opera',
|
||||
|
@ -95,6 +111,13 @@ class UserAgents extends BaseConfig
|
|||
'Vivaldi' => 'Vivaldi',
|
||||
];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Mobiles
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $mobiles = [
|
||||
// legacy array, old values commented out
|
||||
'mobileexplorer' => 'Mobile Explorer',
|
||||
|
@ -195,7 +218,15 @@ class UserAgents extends BaseConfig
|
|||
'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 = [
|
||||
'googlebot' => 'Googlebot',
|
||||
'msnbot' => 'MSNBot',
|
||||
|
|
|
@ -2,6 +2,14 @@
|
|||
|
||||
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
|
||||
{
|
||||
//--------------------------------------------------------------------
|
||||
|
@ -12,22 +20,23 @@ class Validation
|
|||
* Stores the classes that contain the
|
||||
* rules that are available.
|
||||
*
|
||||
* @var array
|
||||
* @var string[]
|
||||
*/
|
||||
public $ruleSets = [
|
||||
\CodeIgniter\Validation\Rules::class,
|
||||
\CodeIgniter\Validation\FormatRules::class,
|
||||
\CodeIgniter\Validation\CreditCardRules::class,
|
||||
\App\Validation\Rules::class,
|
||||
\App\Validation\FileRules::class,
|
||||
\Myth\Auth\Authentication\Passwords\ValidationRules::class,
|
||||
Rules::class,
|
||||
FormatRules::class,
|
||||
FileRules::class,
|
||||
CreditCardRules::class,
|
||||
AppRules::class,
|
||||
AppFileRules::class,
|
||||
PasswordRules::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Specifies the views that are used to display the
|
||||
* errors.
|
||||
*
|
||||
* @var array
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $templates = [
|
||||
'list' => 'CodeIgniter\Validation\Views\list',
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
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
|
||||
|
@ -11,6 +13,8 @@ class View extends \CodeIgniter\Config\View
|
|||
* 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,
|
||||
* set $saveData to true.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $saveData = true;
|
||||
|
||||
|
@ -24,6 +28,8 @@ class View extends \CodeIgniter\Config\View
|
|||
* Examples:
|
||||
* { title|esc(js) }
|
||||
* { created_on|date(Y-m-d)|esc(attr) }
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $filters = [];
|
||||
|
||||
|
@ -31,6 +37,8 @@ class View extends \CodeIgniter\Config\View
|
|||
* Parser Plugins provide a way to extend the functionality provided
|
||||
* by the core Parser by creating aliases that will be replaced with
|
||||
* any callable. Can be single or tag pair.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
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;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class BaseController
|
||||
*
|
||||
|
@ -11,12 +16,8 @@ namespace App\Controllers\Admin;
|
|||
* class Home extends BaseController
|
||||
*
|
||||
* For security be sure to declare any new methods as protected or private.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
*/
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
|
||||
class BaseController extends Controller
|
||||
{
|
||||
/**
|
||||
|
@ -30,11 +31,15 @@ class BaseController extends Controller
|
|||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function initController(
|
||||
\CodeIgniter\HTTP\RequestInterface $request,
|
||||
\CodeIgniter\HTTP\ResponseInterface $response,
|
||||
\Psr\Log\LoggerInterface $logger
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
// Do Not Edit This Line
|
||||
parent::initController($request, $response, $logger);
|
||||
|
@ -42,7 +47,6 @@ class BaseController extends Controller
|
|||
//--------------------------------------------------------------------
|
||||
// Preload any models, libraries, etc, here.
|
||||
//--------------------------------------------------------------------
|
||||
// E.g.:
|
||||
// $this->session = \Config\Services::session();
|
||||
// E.g.: $this->session = \Config\Services::session();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Entities\Note;
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\NoteModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\SoundbiteModel;
|
||||
use CodeIgniter\I18n\Time;
|
||||
|
@ -32,7 +34,11 @@ class Episode extends BaseController
|
|||
|
||||
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 (
|
||||
|
@ -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]',
|
||||
'transcript' => 'ext_in[transcript,txt,html,srt,json]',
|
||||
'chapters' => 'ext_in[chapters,json]',
|
||||
'publication_date' => 'valid_date[Y-m-d H:i]|permit_empty',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
|
@ -117,7 +122,6 @@ class Episode extends BaseController
|
|||
->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$publicationDate = $this->request->getPost('publication_date');
|
||||
$newEpisode = new \App\Entities\Episode([
|
||||
'podcast_id' => $this->podcast->id,
|
||||
'title' => $this->request->getPost('title'),
|
||||
|
@ -142,15 +146,9 @@ class Episode extends BaseController
|
|||
'type' => $this->request->getPost('type'),
|
||||
'is_blocked' => $this->request->getPost('block') == 'yes',
|
||||
'custom_rss_string' => $this->request->getPost('custom_rss'),
|
||||
'created_by' => user(),
|
||||
'updated_by' => user(),
|
||||
'published_at' => $publicationDate
|
||||
? Time::createFromFormat(
|
||||
'Y-m-d H:i',
|
||||
$publicationDate,
|
||||
$this->request->getPost('client_timezone')
|
||||
)->setTimezone('UTC')
|
||||
: null,
|
||||
'created_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
'published_at' => null,
|
||||
]);
|
||||
|
||||
$episodeModel = new EpisodeModel();
|
||||
|
@ -167,7 +165,7 @@ class Episode extends BaseController
|
|||
|
||||
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
|
||||
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
|
||||
'description_footer'
|
||||
'description_footer',
|
||||
);
|
||||
|
||||
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]',
|
||||
'transcript' => 'ext_in[transcript,txt,html,srt,json]',
|
||||
'chapters' => 'ext_in[chapters,json]',
|
||||
'publication_date' => 'valid_date[Y-m-d H:i]|permit_empty',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
|
@ -222,7 +219,7 @@ class Episode extends BaseController
|
|||
$this->episode->title = $this->request->getPost('title');
|
||||
$this->episode->slug = $this->request->getPost('slug');
|
||||
$this->episode->description_markdown = $this->request->getPost(
|
||||
'description'
|
||||
'description',
|
||||
);
|
||||
$this->episode->location = $this->request->getPost('location_name');
|
||||
$this->episode->parental_advisory =
|
||||
|
@ -238,19 +235,10 @@ class Episode extends BaseController
|
|||
$this->episode->type = $this->request->getPost('type');
|
||||
$this->episode->is_blocked = $this->request->getPost('block') == 'yes';
|
||||
$this->episode->custom_rss_string = $this->request->getPost(
|
||||
'custom_rss'
|
||||
'custom_rss',
|
||||
);
|
||||
|
||||
$publicationDate = $this->request->getPost('publication_date');
|
||||
$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();
|
||||
$this->episode->updated_by = user()->id;
|
||||
|
||||
$enclosure = $this->request->getFile('enclosure');
|
||||
if ($enclosure->isValid()) {
|
||||
|
@ -280,7 +268,7 @@ class Episode extends BaseController
|
|||
|
||||
// update podcast's episode_description_footer_markdown if changed
|
||||
$this->podcast->episode_description_footer_markdown = $this->request->getPost(
|
||||
'description_footer'
|
||||
'description_footer',
|
||||
);
|
||||
|
||||
if ($this->podcast->hasChanged('episode_description_footer_markdown')) {
|
||||
|
@ -333,6 +321,271 @@ class Episode extends BaseController
|
|||
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()
|
||||
{
|
||||
(new EpisodeModel())->delete($this->episode->id);
|
||||
|
@ -416,7 +669,7 @@ class Episode extends BaseController
|
|||
(new SoundbiteModel())->deleteSoundbite(
|
||||
$this->podcast->id,
|
||||
$this->episode->id,
|
||||
$soundbiteId
|
||||
$soundbiteId,
|
||||
);
|
||||
|
||||
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->updated_by = user();
|
||||
$this->updated_by = user()->id;
|
||||
|
||||
$personModel = new PersonModel();
|
||||
if (!$personModel->update($this->person->id, $this->person)) {
|
||||
|
|
|
@ -26,7 +26,7 @@ class Podcast extends BaseController
|
|||
if (count($params) > 0) {
|
||||
if (
|
||||
!($this->podcast = (new PodcastModel())->getPodcastById(
|
||||
$params[0]
|
||||
$params[0],
|
||||
))
|
||||
) {
|
||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||
|
@ -124,7 +124,7 @@ class Podcast extends BaseController
|
|||
'languageOptions' => $languageOptions,
|
||||
'categoryOptions' => $categoryOptions,
|
||||
'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_completed' => $this->request->getPost('complete') === 'yes',
|
||||
'is_locked' => $this->request->getPost('lock') === 'yes',
|
||||
'created_by' => user(),
|
||||
'updated_by' => user(),
|
||||
'created_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
]);
|
||||
|
||||
$podcastModel = new PodcastModel();
|
||||
|
@ -193,15 +193,19 @@ class Podcast extends BaseController
|
|||
$podcastModel->addPodcastContributor(
|
||||
user()->id,
|
||||
$newPodcastId,
|
||||
$podcastAdminGroup->id
|
||||
$podcastAdminGroup->id,
|
||||
);
|
||||
|
||||
// set Podcast categories
|
||||
(new CategoryModel())->setPodcastCategories(
|
||||
$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();
|
||||
|
||||
return redirect()->route('podcast-view', [$newPodcastId]);
|
||||
|
@ -239,9 +243,8 @@ class Podcast extends BaseController
|
|||
}
|
||||
|
||||
$this->podcast->title = $this->request->getPost('title');
|
||||
$this->podcast->name = $this->request->getPost('name');
|
||||
$this->podcast->description_markdown = $this->request->getPost(
|
||||
'description'
|
||||
'description',
|
||||
);
|
||||
|
||||
$image = $this->request->getFile('image');
|
||||
|
@ -261,10 +264,10 @@ class Podcast extends BaseController
|
|||
$this->podcast->copyright = $this->request->getPost('copyright');
|
||||
$this->podcast->location = $this->request->getPost('location_name');
|
||||
$this->podcast->payment_pointer = $this->request->getPost(
|
||||
'payment_pointer'
|
||||
'payment_pointer',
|
||||
);
|
||||
$this->podcast->custom_rss_string = $this->request->getPost(
|
||||
'custom_rss'
|
||||
'custom_rss',
|
||||
);
|
||||
$this->podcast->partner_id = $this->request->getPost('partner_id');
|
||||
$this->podcast->partner_link_url = $this->request->getPost(
|
||||
|
@ -277,7 +280,7 @@ class Podcast extends BaseController
|
|||
$this->podcast->is_completed =
|
||||
$this->request->getPost('complete') === 'yes';
|
||||
$this->podcast->is_locked = $this->request->getPost('lock') === 'yes';
|
||||
$this->updated_by = user();
|
||||
$this->updated_by = user()->id;
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
$db->transStart();
|
||||
|
@ -294,7 +297,7 @@ class Podcast extends BaseController
|
|||
// set Podcast categories
|
||||
(new CategoryModel())->setPodcastCategories(
|
||||
$this->podcast->id,
|
||||
$this->request->getPost('other_categories')
|
||||
$this->request->getPost('other_categories'),
|
||||
);
|
||||
|
||||
$db->transComplete();
|
||||
|
|
|
@ -31,7 +31,7 @@ class PodcastImport extends BaseController
|
|||
if (count($params) > 0) {
|
||||
if (
|
||||
!($this->podcast = (new PodcastModel())->getPodcastById(
|
||||
$params[0]
|
||||
$params[0],
|
||||
))
|
||||
) {
|
||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||
|
@ -52,7 +52,7 @@ class PodcastImport extends BaseController
|
|||
'languageOptions' => $languageOptions,
|
||||
'categoryOptions' => $categoryOptions,
|
||||
'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 {
|
||||
ini_set('user_agent', 'Castopod/' . CP_VERSION);
|
||||
$feed = simplexml_load_file(
|
||||
$this->request->getPost('imported_feed_url')
|
||||
$this->request->getPost('imported_feed_url'),
|
||||
);
|
||||
} catch (\ErrorException $ex) {
|
||||
return redirect()
|
||||
|
@ -94,13 +94,13 @@ class PodcastImport extends BaseController
|
|||
]);
|
||||
}
|
||||
$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(
|
||||
'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(
|
||||
'http://purl.org/rss/1.0/modules/content/'
|
||||
'http://purl.org/rss/1.0/modules/content/',
|
||||
);
|
||||
|
||||
if ((string) $nsPodcast->locked === 'yes') {
|
||||
|
@ -112,28 +112,30 @@ class PodcastImport extends BaseController
|
|||
|
||||
$converter = new HtmlConverter();
|
||||
|
||||
$channelDescriptionHtml = $feed->channel[0]->description;
|
||||
$channelDescriptionHtml = (string) $feed->channel[0]->description;
|
||||
|
||||
try {
|
||||
$podcast = new \App\Entities\Podcast([
|
||||
'name' => $this->request->getPost('name'),
|
||||
'imported_feed_url' => $this->request->getPost(
|
||||
'imported_feed_url'
|
||||
'imported_feed_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(
|
||||
$channelDescriptionHtml
|
||||
$channelDescriptionHtml,
|
||||
),
|
||||
'description_html' => $channelDescriptionHtml,
|
||||
'image' =>
|
||||
$nsItunes->image && !empty($nsItunes->image->attributes())
|
||||
? download_file($nsItunes->image->attributes())
|
||||
? download_file((string) $nsItunes->image->attributes())
|
||||
: ($feed->channel[0]->image &&
|
||||
!empty($feed->channel[0]->image->url)
|
||||
? download_file($feed->channel[0]->image->url)
|
||||
? download_file(
|
||||
(string) $feed->channel[0]->image->url,
|
||||
)
|
||||
: null),
|
||||
'language_code' => $this->request->getPost('language'),
|
||||
'category_id' => $this->request->getPost('category'),
|
||||
|
@ -144,11 +146,11 @@ class PodcastImport extends BaseController
|
|||
: (in_array($nsItunes->explicit, ['no', 'false'])
|
||||
? 'clean'
|
||||
: null)),
|
||||
'owner_name' => $nsItunes->owner->name,
|
||||
'owner_email' => $nsItunes->owner->email,
|
||||
'publisher' => $nsItunes->author,
|
||||
'owner_name' => (string) $nsItunes->owner->name,
|
||||
'owner_email' => (string) $nsItunes->owner->email,
|
||||
'publisher' => (string) $nsItunes->author,
|
||||
'type' => empty($nsItunes->type) ? 'episodic' : $nsItunes->type,
|
||||
'copyright' => $feed->channel[0]->copyright,
|
||||
'copyright' => (string) $feed->channel[0]->copyright,
|
||||
'is_blocked' => empty($nsItunes->block)
|
||||
? false
|
||||
: $nsItunes->block === 'yes',
|
||||
|
@ -157,19 +159,19 @@ class PodcastImport extends BaseController
|
|||
: $nsItunes->complete === 'yes',
|
||||
'location_name' => !$nsPodcast->location
|
||||
? null
|
||||
: $nsPodcast->location,
|
||||
: (string) $nsPodcast->location,
|
||||
'location_geo' =>
|
||||
!$nsPodcast->location ||
|
||||
empty($nsPodcast->location->attributes()['geo'])
|
||||
? null
|
||||
: $nsPodcast->location->attributes()['geo'],
|
||||
: (string) $nsPodcast->location->attributes()['geo'],
|
||||
'location_osmid' =>
|
||||
!$nsPodcast->location ||
|
||||
empty($nsPodcast->location->attributes()['osm'])
|
||||
? null
|
||||
: $nsPodcast->location->attributes()['osm'],
|
||||
'created_by' => user(),
|
||||
'updated_by' => user(),
|
||||
: (string) $nsPodcast->location->attributes()['osm'],
|
||||
'created_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
]);
|
||||
} catch (\ErrorException $ex) {
|
||||
return redirect()
|
||||
|
@ -204,7 +206,7 @@ class PodcastImport extends BaseController
|
|||
$podcastModel->addPodcastContributor(
|
||||
user()->id,
|
||||
$newPodcastId,
|
||||
$podcastAdminGroup->id
|
||||
$podcastAdminGroup->id,
|
||||
);
|
||||
|
||||
$podcastsPlatformsData = [];
|
||||
|
@ -218,34 +220,21 @@ class PodcastImport extends BaseController
|
|||
foreach ($platformType['elements'] as $platform) {
|
||||
$platformLabel = $platform->attributes()['platform'];
|
||||
$platformSlug = slugify($platformLabel);
|
||||
if (!$platformModel->getPlatform($platformSlug)) {
|
||||
if (
|
||||
!$platformModel->createPlatform(
|
||||
$platformSlug,
|
||||
$platformType['name'],
|
||||
$platformLabel,
|
||||
''
|
||||
)
|
||||
) {
|
||||
return redirect()
|
||||
->back()
|
||||
->withInput()
|
||||
->with('errors', $platformModel->errors());
|
||||
}
|
||||
if ($platformModel->getPlatform($platformSlug)) {
|
||||
array_push($podcastsPlatformsData, [
|
||||
'platform_slug' => $platformSlug,
|
||||
'podcast_id' => $newPodcastId,
|
||||
'link_url' => $platform->attributes()['url'],
|
||||
'link_content' => $platform->attributes()['id'],
|
||||
'is_visible' => false,
|
||||
]);
|
||||
}
|
||||
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) {
|
||||
$platformModel->createPodcastPlatforms(
|
||||
$newPodcastId,
|
||||
$podcastsPlatformsData
|
||||
$podcastsPlatformsData,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -259,7 +248,7 @@ class PodcastImport extends BaseController
|
|||
!($newPersonId = $personModel->createPerson(
|
||||
$podcastPerson,
|
||||
$podcastPerson->attributes()['href'],
|
||||
$podcastPerson->attributes()['img']
|
||||
$podcastPerson->attributes()['img'],
|
||||
))
|
||||
) {
|
||||
return redirect()
|
||||
|
@ -312,19 +301,19 @@ class PodcastImport extends BaseController
|
|||
$item = $feed->channel[0]->item[$numberItems - $itemNumber];
|
||||
|
||||
$nsItunes = $item->children(
|
||||
'http://www.itunes.com/dtds/podcast-1.0.dtd'
|
||||
'http://www.itunes.com/dtds/podcast-1.0.dtd',
|
||||
);
|
||||
$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(
|
||||
'http://purl.org/rss/1.0/modules/content/'
|
||||
'http://purl.org/rss/1.0/modules/content/',
|
||||
);
|
||||
|
||||
$slug = slugify(
|
||||
$this->request->getPost('slug_field') === 'title'
|
||||
? $item->title
|
||||
: basename($item->link)
|
||||
: basename($item->link),
|
||||
);
|
||||
if (in_array($slug, $slugs)) {
|
||||
$slugNumber = 2;
|
||||
|
@ -358,13 +347,15 @@ class PodcastImport extends BaseController
|
|||
'slug' => $slug,
|
||||
'enclosure' => download_file($item->enclosure->attributes()),
|
||||
'description_markdown' => $converter->convert(
|
||||
$itemDescriptionHtml
|
||||
$itemDescriptionHtml,
|
||||
),
|
||||
'description_html' => $itemDescriptionHtml,
|
||||
'image' =>
|
||||
!$nsItunes->image || empty($nsItunes->image->attributes())
|
||||
? null
|
||||
: download_file($nsItunes->image->attributes()),
|
||||
: download_file(
|
||||
(string) $nsItunes->image->attributes(),
|
||||
),
|
||||
'parental_advisory' => empty($nsItunes->explicit)
|
||||
? null
|
||||
: (in_array($nsItunes->explicit, ['yes', 'true'])
|
||||
|
@ -404,8 +395,8 @@ class PodcastImport extends BaseController
|
|||
empty($nsPodcast->location->attributes()['osm'])
|
||||
? null
|
||||
: $nsPodcast->location->attributes()['osm'],
|
||||
'created_by' => user(),
|
||||
'updated_by' => user(),
|
||||
'created_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
'published_at' => strtotime($item->pubDate),
|
||||
]);
|
||||
|
||||
|
@ -429,7 +420,7 @@ class PodcastImport extends BaseController
|
|||
!($newPersonId = $personModel->createPerson(
|
||||
$episodePerson,
|
||||
$episodePerson->attributes()['href'],
|
||||
$episodePerson->attributes()['img']
|
||||
$episodePerson->attributes()['img'],
|
||||
))
|
||||
) {
|
||||
return redirect()
|
||||
|
@ -458,8 +449,8 @@ class PodcastImport extends BaseController
|
|||
'person_group' => $personGroup['slug'],
|
||||
'person_role' => $personRole['slug'],
|
||||
]);
|
||||
$episodePersonModel = new EpisodePersonModel();
|
||||
|
||||
$episodePersonModel = new EpisodePersonModel();
|
||||
if (!$episodePersonModel->insert($newEpisodePerson)) {
|
||||
return redirect()
|
||||
->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();
|
||||
|
||||
return redirect()->route('podcast-view', [$newPodcastId]);
|
||||
|
|
|
@ -55,7 +55,7 @@ class Auth extends \Myth\Auth\Controllers\AuthController
|
|||
$allowedPostFields = array_merge(
|
||||
['password'],
|
||||
$this->config->validFields,
|
||||
$this->config->personalFields
|
||||
$this->config->personalFields,
|
||||
);
|
||||
$user = new User($this->request->getPost($allowedPostFields));
|
||||
|
||||
|
@ -85,7 +85,7 @@ class Auth extends \Myth\Auth\Controllers\AuthController
|
|||
->withInput()
|
||||
->with(
|
||||
'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('token'),
|
||||
$this->request->getIPAddress(),
|
||||
(string) $this->request->getUserAgent()
|
||||
(string) $this->request->getUserAgent(),
|
||||
);
|
||||
|
||||
$rules = [
|
||||
|
@ -172,4 +172,24 @@ class Auth extends \Myth\Auth\Controllers\AuthController
|
|||
->route('login')
|
||||
->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
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class BaseController
|
||||
*
|
||||
|
@ -9,14 +16,7 @@
|
|||
* class Home extends BaseController
|
||||
*
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
|
@ -26,15 +26,19 @@ class BaseController extends Controller
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $helpers = ['analytics', 'svg', 'components', 'misc'];
|
||||
protected $helpers = ['auth', 'analytics', 'svg', 'components', 'misc'];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @param LoggerInterface $logger
|
||||
*/
|
||||
public function initController(
|
||||
\CodeIgniter\HTTP\RequestInterface $request,
|
||||
\CodeIgniter\HTTP\ResponseInterface $response,
|
||||
\Psr\Log\LoggerInterface $logger
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
// Do Not Edit This Line
|
||||
parent::initController($request, $response, $logger);
|
||||
|
@ -42,8 +46,7 @@ class BaseController extends Controller
|
|||
//--------------------------------------------------------------------
|
||||
// Preload any models, libraries, etc, here.
|
||||
//--------------------------------------------------------------------
|
||||
// E.g.:
|
||||
// $this->session = \Config\Services::session();
|
||||
// E.g.: $this->session = \Config\Services::session();
|
||||
|
||||
set_user_session_deny_list_ip();
|
||||
set_user_session_browser();
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace App\Controllers;
|
|||
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use SimpleXMLElement;
|
||||
|
||||
class Episode extends BaseController
|
||||
{
|
||||
|
@ -31,7 +32,7 @@ class Episode extends BaseController
|
|||
count($params) > 1 &&
|
||||
!($this->episode = (new EpisodeModel())->getEpisodeBySlug(
|
||||
$this->podcast->id,
|
||||
$params[1]
|
||||
$params[1],
|
||||
))
|
||||
) {
|
||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||
|
@ -43,44 +44,49 @@ class Episode extends BaseController
|
|||
|
||||
public function index()
|
||||
{
|
||||
self::triggerWebpageHit($this->episode->podcast_id);
|
||||
$episodeModel = new EpisodeModel();
|
||||
|
||||
self::triggerWebpageHit($this->podcast->id);
|
||||
|
||||
$locale = service('request')->getLocale();
|
||||
$cacheName = "page_podcast{$this->episode->podcast_id}_episode{$this->episode->id}_{$locale}";
|
||||
|
||||
if (!($cachedView = cache($cacheName))) {
|
||||
$episodeModel = new EpisodeModel();
|
||||
$previousNextEpisodes = $episodeModel->getPreviousNextEpisodes(
|
||||
$this->episode,
|
||||
$this->podcast->type
|
||||
);
|
||||
|
||||
helper(['persons']);
|
||||
$persons = [];
|
||||
construct_episode_person_array(
|
||||
$this->episode->episode_persons,
|
||||
$persons
|
||||
);
|
||||
helper('persons');
|
||||
$episodePersons = [];
|
||||
construct_person_array($this->episode->persons, $episodePersons);
|
||||
$podcastPersons = [];
|
||||
construct_person_array($this->podcast->persons, $podcastPersons);
|
||||
|
||||
$data = [
|
||||
'previousEpisode' => $previousNextEpisodes['previous'],
|
||||
'nextEpisode' => $previousNextEpisodes['next'],
|
||||
'podcast' => $this->podcast,
|
||||
'episode' => $this->episode,
|
||||
'persons' => $persons,
|
||||
'episodePersons' => $episodePersons,
|
||||
'persons' => $podcastPersons,
|
||||
];
|
||||
|
||||
$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
|
||||
return view('episode', $data, [
|
||||
'cache' => $secondsToNextUnpublishedEpisode
|
||||
? $secondsToNextUnpublishedEpisode
|
||||
: DECADE,
|
||||
'cache_name' => $cacheName,
|
||||
]);
|
||||
if (can_user_interact()) {
|
||||
helper('form');
|
||||
// The page cache is set to a decade so it is deleted manually upon podcast update
|
||||
return view('podcast/episode_authenticated', $data, [
|
||||
'cache' => $secondsToNextUnpublishedEpisode
|
||||
? $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;
|
||||
|
@ -97,7 +103,7 @@ class Episode extends BaseController
|
|||
if (isset($_SERVER['HTTP_REFERER'])) {
|
||||
$session->set(
|
||||
'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))) {
|
||||
$episodeModel = new EpisodeModel();
|
||||
$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 = [
|
||||
'podcast' => $this->podcast,
|
||||
'episode' => $this->episode,
|
||||
'persons' => $persons,
|
||||
'theme' => $theme,
|
||||
];
|
||||
|
||||
$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
|
||||
|
@ -141,4 +136,56 @@ class Episode extends BaseController
|
|||
|
||||
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
|
||||
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
|
||||
|
|
|
@ -257,6 +257,7 @@ class Install extends Controller
|
|||
$migrations = \Config\Services::migrations();
|
||||
|
||||
!$migrations->setNamespace('Myth\Auth')->latest();
|
||||
!$migrations->setNamespace('ActivityPub')->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,
|
||||
'is_in' => [
|
||||
[
|
||||
'link' => $credit->episode
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$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,
|
||||
],
|
||||
],
|
||||
|
@ -114,14 +123,21 @@ class Page extends BaseController
|
|||
'role_label' => $credit->role_label,
|
||||
'is_in' => [
|
||||
[
|
||||
'link' => $credit->episode
|
||||
'link' => $credit->episode_id
|
||||
? $credit->episode->link
|
||||
: $credit->podcast->link,
|
||||
'title' => $credit->episode
|
||||
'title' => $credit->episode_id
|
||||
? (count($allPodcasts) > 1
|
||||
? "{$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,
|
||||
],
|
||||
],
|
||||
|
@ -143,7 +159,13 @@ class Page extends BaseController
|
|||
? (count($allPodcasts) > 1
|
||||
? "{$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,
|
||||
],
|
||||
],
|
||||
|
@ -159,7 +181,13 @@ class Page extends BaseController
|
|||
? (count($allPodcasts) > 1
|
||||
? "{$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,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace App\Controllers;
|
|||
|
||||
use App\Models\EpisodeModel;
|
||||
use App\Models\PodcastModel;
|
||||
use App\Models\NoteModel;
|
||||
|
||||
class Podcast extends BaseController
|
||||
{
|
||||
|
@ -23,17 +24,41 @@ class Podcast extends BaseController
|
|||
if (count($params) > 0) {
|
||||
if (
|
||||
!($this->podcast = (new PodcastModel())->getPodcastByName(
|
||||
$params[0]
|
||||
$params[0],
|
||||
))
|
||||
) {
|
||||
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);
|
||||
|
||||
|
@ -42,7 +67,7 @@ class Podcast extends BaseController
|
|||
|
||||
if (!$yearQuery and !$seasonQuery) {
|
||||
$defaultQuery = (new EpisodeModel())->getDefaultQuery(
|
||||
$this->podcast->id
|
||||
$this->podcast->id,
|
||||
);
|
||||
if ($defaultQuery['type'] == 'season') {
|
||||
$seasonQuery = $defaultQuery['data']['season_number'];
|
||||
|
@ -59,7 +84,7 @@ class Podcast extends BaseController
|
|||
$yearQuery,
|
||||
$seasonQuery ? 'season' . $seasonQuery : null,
|
||||
service('request')->getLocale(),
|
||||
])
|
||||
]),
|
||||
);
|
||||
|
||||
if (!($found = cache($cacheName))) {
|
||||
|
@ -73,14 +98,19 @@ class Podcast extends BaseController
|
|||
foreach ($years as $year) {
|
||||
$isActive = $yearQuery == $year['year'];
|
||||
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, [
|
||||
'label' => $year['year'],
|
||||
'number_of_episodes' => $year['number_of_episodes'],
|
||||
'route' =>
|
||||
route_to('podcast', $this->podcast->name) .
|
||||
route_to('podcast-episodes', $this->podcast->name) .
|
||||
'?year=' .
|
||||
$year['year'],
|
||||
'is_active' => $isActive,
|
||||
|
@ -93,6 +123,10 @@ class Podcast extends BaseController
|
|||
$activeQuery = [
|
||||
'type' => 'season',
|
||||
'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'],
|
||||
'route' =>
|
||||
route_to('podcast', $this->podcast->name) .
|
||||
route_to('podcast-episodes', $this->podcast->name) .
|
||||
'?season=' .
|
||||
$season['season_number'],
|
||||
'is_active' => $isActive,
|
||||
]);
|
||||
}
|
||||
|
||||
helper(['persons']);
|
||||
helper('persons');
|
||||
$persons = [];
|
||||
constructs_podcast_person_array(
|
||||
$this->podcast->podcast_persons,
|
||||
$persons
|
||||
);
|
||||
construct_person_array($this->podcast->persons, $persons);
|
||||
|
||||
$data = [
|
||||
'podcast' => $this->podcast,
|
||||
|
@ -124,21 +155,31 @@ class Podcast extends BaseController
|
|||
$this->podcast->id,
|
||||
$this->podcast->type,
|
||||
$yearQuery,
|
||||
$seasonQuery
|
||||
$seasonQuery,
|
||||
),
|
||||
'personArray' => $persons,
|
||||
'persons' => $persons,
|
||||
];
|
||||
|
||||
$secondsToNextUnpublishedEpisode = $episodeModel->getSecondsToNextUnpublishedEpisode(
|
||||
$this->podcast->id
|
||||
$this->podcast->id,
|
||||
);
|
||||
|
||||
return view('podcast', $data, [
|
||||
'cache' => $secondsToNextUnpublishedEpisode
|
||||
? $secondsToNextUnpublishedEpisode
|
||||
: DECADE,
|
||||
'cache_name' => $cacheName,
|
||||
]);
|
||||
// if user is logged in then send to the authenticated episodes view
|
||||
if (can_user_interact()) {
|
||||
return view('podcast/episodes_authenticated', $data, [
|
||||
'cache' => $secondsToNextUnpublishedEpisode
|
||||
? $secondsToNextUnpublishedEpisode
|
||||
: DECADE,
|
||||
'cache_name' => $cacheName . '_authenticated',
|
||||
]);
|
||||
} else {
|
||||
return view('podcast/episodes', $data, [
|
||||
'cache' => $secondsToNextUnpublishedEpisode
|
||||
? $secondsToNextUnpublishedEpisode
|
||||
: DECADE,
|
||||
'cache_name' => $cacheName,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $found;
|
||||
|
|
|
@ -39,7 +39,7 @@ class AddCategories extends Migration
|
|||
'constraint' => 32,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$this->forge->addUniqueKey('code');
|
||||
$this->forge->addForeignKey('parent_id', 'categories', 'id');
|
||||
$this->forge->createTable('categories');
|
||||
|
|
|
@ -28,7 +28,7 @@ class AddLanguages extends Migration
|
|||
'constraint' => 128,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('code', true);
|
||||
$this->forge->addPrimaryKey('code');
|
||||
$this->forge->createTable('languages');
|
||||
}
|
||||
|
||||
|
|
|
@ -23,14 +23,17 @@ class AddPodcasts extends Migration
|
|||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'title' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 128,
|
||||
'actor_id' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
],
|
||||
'name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 32,
|
||||
'unique' => true,
|
||||
],
|
||||
'title' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 128,
|
||||
],
|
||||
'description_markdown' => [
|
||||
'type' => 'TEXT',
|
||||
|
@ -42,6 +45,12 @@ class AddPodcasts extends Migration
|
|||
'type' => 'VARCHAR',
|
||||
'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' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 2,
|
||||
|
@ -140,6 +149,7 @@ class AddPodcasts extends Migration
|
|||
],
|
||||
'custom_rss' => [
|
||||
'type' => 'JSON',
|
||||
'null' => true,
|
||||
],
|
||||
'partner_id' => [
|
||||
'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('language_code', 'languages', 'code');
|
||||
$this->forge->addForeignKey('created_by', 'users', 'id');
|
||||
|
|
|
@ -73,6 +73,13 @@ class AddEpisodes extends Migration
|
|||
'constraint' => 255,
|
||||
'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' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
|
@ -128,6 +135,21 @@ class AddEpisodes extends Migration
|
|||
'type' => 'JSON',
|
||||
'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' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
|
@ -151,9 +173,15 @@ class AddEpisodes extends Migration
|
|||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$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('updated_by', 'users', 'id');
|
||||
$this->forge->createTable('episodes');
|
||||
|
|
|
@ -63,8 +63,20 @@ class AddSoundbites extends Migration
|
|||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addUniqueKey(['episode_id', 'start_time', 'duration']);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||
$this->forge->addForeignKey('episode_id', 'episodes', 'id');
|
||||
$this->forge->addForeignKey(
|
||||
'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('updated_by', 'users', 'id');
|
||||
$this->forge->createTable('soundbites');
|
||||
|
|
|
@ -45,7 +45,7 @@ class AddPlatforms extends Migration
|
|||
$this->forge->addField(
|
||||
'`updated_at` timestamp NOT NULL DEFAULT NOW() ON UPDATE NOW()'
|
||||
);
|
||||
$this->forge->addKey('slug', true);
|
||||
$this->forge->addPrimaryKey('slug');
|
||||
$this->forge->createTable('platforms');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsPodcasts
|
||||
* Creates analytics_podcasts table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -45,12 +46,11 @@ class AddAnalyticsPodcasts extends Migration
|
|||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsPodcastsByEpisode
|
||||
* Creates analytics_episodes_by_episode table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -41,13 +42,11 @@ class AddAnalyticsPodcastsByEpisode extends Migration
|
|||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'episode_id']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsPodcastsByHour
|
||||
* Creates analytics_podcasts_by_hour table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -36,12 +37,11 @@ class AddAnalyticsPodcastsByHour extends Migration
|
|||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'hour']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsPodcastsByPlayer
|
||||
* Creates analytics_podcasts_by_player table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -61,12 +62,11 @@ class AddAnalyticsPodcastsByPlayer extends Migration
|
|||
'is_bot',
|
||||
]);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsPodcastsByCountry
|
||||
* Creates analytics_podcasts_by_country table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -37,12 +38,11 @@ class AddAnalyticsPodcastsByCountry extends Migration
|
|||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'country_code']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsPodcastsByRegion
|
||||
* Creates analytics_podcasts_by_region table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -55,12 +56,11 @@ class AddAnalyticsPodcastsByRegion extends Migration
|
|||
'region_code',
|
||||
]);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -48,8 +48,6 @@ class AddPodcastsPlatforms extends Migration
|
|||
]);
|
||||
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsWebsiteByBrowser
|
||||
* Creates analytics_website_by_browser table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -37,12 +38,11 @@ class AddAnalyticsWebsiteByBrowser extends Migration
|
|||
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'browser']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsWebsiteByReferer
|
||||
* Creates analytics_website_by_referer table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -46,12 +47,11 @@ class AddAnalyticsWebsiteByReferer extends Migration
|
|||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'referer_url']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsWebsiteByEntryPage
|
||||
* Creates analytics_website_by_entry_page table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -36,12 +37,11 @@ class AddAnalyticsWebsiteByEntryPage extends Migration
|
|||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'date', 'entry_page_url']);
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()',
|
||||
);
|
||||
$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');
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsUnknownUseragents
|
||||
* Creates analytics_unknown_useragents table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -33,7 +34,8 @@ class AddAnalyticsUnknownUseragents extends Migration
|
|||
'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)
|
||||
$this->forge->addField(
|
||||
'`created_at` timestamp NOT NULL DEFAULT current_timestamp()'
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsPodcastsProcedure
|
||||
* Creates analytics_podcasts procedure in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -21,58 +22,58 @@ class AddAnalyticsPodcastsProcedure extends Migration
|
|||
$prefix = $this->db->getPrefix();
|
||||
|
||||
$createQuery = <<<EOD
|
||||
CREATE PROCEDURE `{$prefix}analytics_podcasts` (
|
||||
IN `p_podcast_id` INT UNSIGNED,
|
||||
IN `p_episode_id` INT UNSIGNED,
|
||||
IN `p_country_code` VARCHAR(3) CHARSET utf8mb4,
|
||||
IN `p_region_code` VARCHAR(3) CHARSET utf8mb4,
|
||||
IN `p_latitude` FLOAT,
|
||||
IN `p_longitude` FLOAT,
|
||||
IN `p_service` VARCHAR(128) CHARSET utf8mb4,
|
||||
IN `p_app` VARCHAR(128) CHARSET utf8mb4,
|
||||
IN `p_device` VARCHAR(32) CHARSET utf8mb4,
|
||||
IN `p_os` VARCHAR(32) CHARSET utf8mb4,
|
||||
IN `p_bot` TINYINT(1) UNSIGNED,
|
||||
IN `p_filesize` INT UNSIGNED,
|
||||
IN `p_duration` INT UNSIGNED,
|
||||
IN `p_age` INT UNSIGNED,
|
||||
IN `p_new_listener` TINYINT(1) UNSIGNED
|
||||
) MODIFIES SQL DATA
|
||||
DETERMINISTIC
|
||||
SQL SECURITY INVOKER
|
||||
COMMENT 'Add one hit in podcast logs tables.'
|
||||
BEGIN
|
||||
CREATE PROCEDURE `{$prefix}analytics_podcasts` (
|
||||
IN `p_podcast_id` INT UNSIGNED,
|
||||
IN `p_episode_id` INT UNSIGNED,
|
||||
IN `p_country_code` VARCHAR(3) CHARSET utf8mb4,
|
||||
IN `p_region_code` VARCHAR(3) CHARSET utf8mb4,
|
||||
IN `p_latitude` FLOAT,
|
||||
IN `p_longitude` FLOAT,
|
||||
IN `p_service` VARCHAR(128) CHARSET utf8mb4,
|
||||
IN `p_app` VARCHAR(128) CHARSET utf8mb4,
|
||||
IN `p_device` VARCHAR(32) CHARSET utf8mb4,
|
||||
IN `p_os` VARCHAR(32) CHARSET utf8mb4,
|
||||
IN `p_bot` TINYINT(1) UNSIGNED,
|
||||
IN `p_filesize` INT UNSIGNED,
|
||||
IN `p_duration` INT UNSIGNED,
|
||||
IN `p_age` INT UNSIGNED,
|
||||
IN `p_new_listener` TINYINT(1) UNSIGNED
|
||||
) MODIFIES SQL DATA
|
||||
DETERMINISTIC
|
||||
SQL SECURITY INVOKER
|
||||
COMMENT 'Add one hit in podcast logs tables.'
|
||||
BEGIN
|
||||
|
||||
SET @current_datetime = NOW();
|
||||
SET @current_date = DATE(@current_datetime);
|
||||
SET @current_hour = HOUR(@current_datetime);
|
||||
SET @current_datetime = NOW();
|
||||
SET @current_date = DATE(@current_datetime);
|
||||
SET @current_hour = HOUR(@current_datetime);
|
||||
|
||||
IF NOT `p_bot` THEN
|
||||
INSERT INTO `{$prefix}analytics_podcasts`(`podcast_id`, `date`)
|
||||
VALUES (p_podcast_id, @current_date)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`duration`=`duration`+`p_duration`,
|
||||
`bandwidth`=`bandwidth`+`p_filesize`,
|
||||
`hits`=`hits`+1,
|
||||
`unique_listeners`=`unique_listeners`+`p_new_listener`;
|
||||
INSERT INTO `{$prefix}analytics_podcasts_by_hour`(`podcast_id`, `date`, `hour`)
|
||||
VALUES (p_podcast_id, @current_date, @current_hour)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
INSERT INTO `{$prefix}analytics_podcasts_by_episode`(`podcast_id`, `episode_id`, `date`, `age`)
|
||||
VALUES (p_podcast_id, p_episode_id, @current_date, p_age)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
INSERT INTO `{$prefix}analytics_podcasts_by_country`(`podcast_id`, `country_code`, `date`)
|
||||
VALUES (p_podcast_id, p_country_code, @current_date)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
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)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
END IF;
|
||||
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)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
END
|
||||
EOD;
|
||||
IF NOT `p_bot` THEN
|
||||
INSERT INTO `{$prefix}analytics_podcasts`(`podcast_id`, `date`)
|
||||
VALUES (p_podcast_id, @current_date)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`duration`=`duration`+`p_duration`,
|
||||
`bandwidth`=`bandwidth`+`p_filesize`,
|
||||
`hits`=`hits`+1,
|
||||
`unique_listeners`=`unique_listeners`+`p_new_listener`;
|
||||
INSERT INTO `{$prefix}analytics_podcasts_by_hour`(`podcast_id`, `date`, `hour`)
|
||||
VALUES (p_podcast_id, @current_date, @current_hour)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
INSERT INTO `{$prefix}analytics_podcasts_by_episode`(`podcast_id`, `episode_id`, `date`, `age`)
|
||||
VALUES (p_podcast_id, p_episode_id, @current_date, p_age)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
INSERT INTO `{$prefix}analytics_podcasts_by_country`(`podcast_id`, `country_code`, `date`)
|
||||
VALUES (p_podcast_id, p_country_code, @current_date)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
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)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
END IF;
|
||||
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)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
END
|
||||
EOD;
|
||||
$this->db->query($createQuery);
|
||||
}
|
||||
|
||||
|
@ -80,7 +81,7 @@ EOD;
|
|||
{
|
||||
$prefix = $this->db->getPrefix();
|
||||
$this->db->query(
|
||||
"DROP PROCEDURE IF EXISTS `{$prefix}analytics_podcasts`"
|
||||
"DROP PROCEDURE IF EXISTS `{$prefix}analytics_podcasts`",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsUnknownUseragentsProcedure
|
||||
* Creates analytics_unknown_useragents procedure in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @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');
|
||||
$procedureName = $this->db->prefixTable('analytics_unknown_useragents');
|
||||
$createQuery = <<<EOD
|
||||
CREATE PROCEDURE `$procedureName` (IN `p_useragent` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
|
||||
DETERMINISTIC
|
||||
SQL SECURITY INVOKER
|
||||
COMMENT 'Add an unknown useragent to table $procedureName.'
|
||||
INSERT INTO `$procedureName`(`useragent`)
|
||||
VALUES (p_useragent)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1
|
||||
EOD;
|
||||
CREATE PROCEDURE `$procedureName` (IN `p_useragent` VARCHAR(191) CHARSET utf8mb4) MODIFIES SQL DATA
|
||||
DETERMINISTIC
|
||||
SQL SECURITY INVOKER
|
||||
COMMENT 'Add an unknown useragent to table $procedureName.'
|
||||
INSERT INTO `$procedureName`(`useragent`)
|
||||
VALUES (p_useragent)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1
|
||||
EOD;
|
||||
$this->db->query($createQuery);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
/**
|
||||
* Class AddAnalyticsWebsiteProcedure
|
||||
* Creates analytics_website stored procedure in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
* @link https://castopod.org/
|
||||
|
@ -20,25 +21,25 @@ class AddAnalyticsWebsiteProcedure extends Migration
|
|||
// Example: CALL analytics_website(1,'FR','Firefox');
|
||||
$procedureName = $this->db->prefixTable('analytics_website');
|
||||
$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
|
||||
DETERMINISTIC
|
||||
SQL SECURITY INVOKER
|
||||
COMMENT 'Add one hit in website logs tables.'
|
||||
BEGIN
|
||||
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
|
||||
SQL SECURITY INVOKER
|
||||
COMMENT 'Add one hit in website logs tables.'
|
||||
BEGIN
|
||||
|
||||
SET @current_date = DATE(NOW());
|
||||
SET @current_date = DATE(NOW());
|
||||
|
||||
INSERT INTO {$procedureName}_by_browser(`podcast_id`, `browser`, `date`)
|
||||
VALUES (p_podcast_id, p_browser, @current_date)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
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)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
INSERT INTO {$procedureName}_by_entry_page(`podcast_id`, `entry_page_url`, `date`)
|
||||
VALUES (p_podcast_id, p_entry_page, @current_date)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
END
|
||||
EOD;
|
||||
INSERT INTO {$procedureName}_by_browser(`podcast_id`, `browser`, `date`)
|
||||
VALUES (p_podcast_id, p_browser, @current_date)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
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)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
INSERT INTO {$procedureName}_by_entry_page(`podcast_id`, `entry_page_url`, `date`)
|
||||
VALUES (p_podcast_id, p_entry_page, @current_date)
|
||||
ON DUPLICATE KEY UPDATE `hits`=`hits`+1;
|
||||
END
|
||||
EOD;
|
||||
$this->db->query($createQuery);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddLanguages
|
||||
* Creates languages table in database
|
||||
* Class AddPodcastUsers
|
||||
* Creates podcast_users table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @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->addForeignKey('user_id', 'users', 'id');
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||
$this->forge->addForeignKey('group_id', 'auth_groups', 'id');
|
||||
$this->forge->addForeignKey('user_id', 'users', 'id', false, 'CASCADE');
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
false,
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'group_id',
|
||||
'auth_groups',
|
||||
'id',
|
||||
false,
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('podcasts_users');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class AddLanguages
|
||||
* Creates languages table in database
|
||||
* Class AddPages
|
||||
* Creates pages table in database
|
||||
*
|
||||
* @copyright 2020 Podlibre
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
||||
|
@ -46,7 +46,7 @@ class AddPages extends Migration
|
|||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addPrimaryKey('id');
|
||||
$this->forge->createTable('pages');
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,20 @@ class AddPodcastsCategories extends Migration
|
|||
],
|
||||
]);
|
||||
$this->forge->addPrimaryKey(['podcast_id', 'category_id']);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||
$this->forge->addForeignKey('category_id', 'categories', 'id');
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
false,
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'category_id',
|
||||
'categories',
|
||||
'id',
|
||||
false,
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('podcasts_categories');
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,12 @@ class AddPersons extends Migration
|
|||
'type' => 'VARCHAR',
|
||||
'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' => [
|
||||
'type' => 'INT',
|
||||
'unsigned' => true,
|
||||
|
|
|
@ -47,8 +47,20 @@ class AddPodcastsPersons extends Migration
|
|||
'person_group',
|
||||
'person_role',
|
||||
]);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||
$this->forge->addForeignKey('person_id', 'persons', 'id');
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_id',
|
||||
'podcasts',
|
||||
'id',
|
||||
false,
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->addForeignKey(
|
||||
'person_id',
|
||||
'persons',
|
||||
'id',
|
||||
false,
|
||||
'CASCADE',
|
||||
);
|
||||
$this->forge->createTable('podcasts_persons');
|
||||
}
|
||||
|
||||
|
|
|
@ -52,9 +52,27 @@ class AddEpisodesPersons extends Migration
|
|||
'person_group',
|
||||
'person_role',
|
||||
]);
|
||||
$this->forge->addForeignKey('podcast_id', 'podcasts', 'id');
|
||||
$this->forge->addForeignKey('episode_id', 'episodes', 'id');
|
||||
$this->forge->addForeignKey('person_id', 'persons', 'id');
|
||||
$this->forge->addForeignKey(
|
||||
'podcast_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');
|
||||
}
|
||||
|
||||
|
|
|
@ -22,16 +22,16 @@ class AddCreditView extends Migration
|
|||
$podcastPersonTable = $this->db->prefixTable('podcasts_persons');
|
||||
$episodePersonTable = $this->db->prefixTable('episodes_persons');
|
||||
$createQuery = <<<EOD
|
||||
CREATE VIEW `$viewName` AS
|
||||
SELECT `person_group`, `person_id`, `full_name`, `person_role`, `podcast_id`, NULL AS `episode_id` FROM `$podcastPersonTable`
|
||||
INNER JOIN `$personTable`
|
||||
ON (`person_id`=`$personTable`.`id`)
|
||||
UNION
|
||||
SELECT `person_group`, `person_id`, `full_name`, `person_role`, `podcast_id`, `episode_id` FROM `$episodePersonTable`
|
||||
INNER JOIN `$personTable`
|
||||
ON (`person_id`=`$personTable`.`id`)
|
||||
ORDER BY `person_group`, `full_name`, `person_role`, `podcast_id`, `episode_id`;
|
||||
EOD;
|
||||
CREATE VIEW `$viewName` AS
|
||||
SELECT `person_group`, `person_id`, `full_name`, `person_role`, `podcast_id`, NULL AS `episode_id` FROM `$podcastPersonTable`
|
||||
INNER JOIN `$personTable`
|
||||
ON (`person_id`=`$personTable`.`id`)
|
||||
UNION
|
||||
SELECT `person_group`, `person_id`, `full_name`, `person_role`, `podcast_id`, `episode_id` FROM `$episodePersonTable`
|
||||
INNER JOIN `$personTable`
|
||||
ON (`person_id`=`$personTable`.`id`)
|
||||
ORDER BY `person_group`, `full_name`, `person_role`, `podcast_id`, `episode_id`;
|
||||
EOD;
|
||||
$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',
|
||||
'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' => [
|
||||
[
|
||||
|
@ -192,11 +204,6 @@ class AuthSeeder extends Seeder
|
|||
'Delete all occurrences of an episode of a podcast from the database',
|
||||
'has_permission' => ['podcast_admin'],
|
||||
],
|
||||
[
|
||||
'name' => 'manage_publications',
|
||||
'description' => 'Publish / unpublish episodes of a podcast',
|
||||
'has_permission' => ['podcast_admin'],
|
||||
],
|
||||
],
|
||||
'person' => [
|
||||
[
|
||||
|
@ -220,8 +227,23 @@ class AuthSeeder extends Seeder
|
|||
'has_permission' => ['superadmin'],
|
||||
],
|
||||
[
|
||||
'name' => 'delete_permanently',
|
||||
'description' => 'Delete any person from the database',
|
||||
'name' => 'delete',
|
||||
'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'],
|
||||
],
|
||||
],
|
||||
|
@ -266,7 +288,7 @@ class AuthSeeder extends Seeder
|
|||
array_push($dataGroupsPermissions, [
|
||||
'group_id' => $this->getGroupIdByName(
|
||||
$role,
|
||||
$dataGroups
|
||||
$dataGroups,
|
||||
),
|
||||
'permission_id' => $permissionId,
|
||||
]);
|
||||
|
|
|
@ -98,7 +98,6 @@ class PlatformSeeder extends Seeder
|
|||
'home_url' => 'https://fyyd.de/',
|
||||
'submit_url' => 'https://fyyd.de/add-feed',
|
||||
],
|
||||
|
||||
[
|
||||
'slug' => 'google',
|
||||
'type' => 'podcasting',
|
||||
|
@ -249,7 +248,6 @@ class PlatformSeeder extends Seeder
|
|||
'submit_url' =>
|
||||
'https://help.tunein.com/contact/add-podcast-S19TR3Sdf',
|
||||
],
|
||||
|
||||
[
|
||||
'slug' => 'paypal',
|
||||
'type' => 'funding',
|
||||
|
@ -257,7 +255,6 @@ class PlatformSeeder extends Seeder
|
|||
'home_url' => 'https://www.paypal.com/',
|
||||
'submit_url' => 'https://www.paypal.com/paypalme/my/grab',
|
||||
],
|
||||
|
||||
[
|
||||
'slug' => 'gofundme',
|
||||
'type' => 'funding',
|
||||
|
@ -322,7 +319,6 @@ class PlatformSeeder extends Seeder
|
|||
'home_url' => 'https://www.ulule.com/',
|
||||
'submit_url' => 'https://www.ulule.com/projects/create/#/',
|
||||
],
|
||||
|
||||
[
|
||||
'slug' => 'discord',
|
||||
'type' => 'social',
|
||||
|
@ -431,6 +427,7 @@ class PlatformSeeder extends Seeder
|
|||
'submit_url' => 'https://creatoracademy.youtube.com/page/home',
|
||||
],
|
||||
];
|
||||
|
||||
$this->db
|
||||
->table('platforms')
|
||||
->ignore(true)
|
||||
|
|
|
@ -27,7 +27,7 @@ class Credit extends Entity
|
|||
protected $podcast;
|
||||
|
||||
/**
|
||||
* @var \App\Entities\Episode
|
||||
* @var \App\Entities\Episode|null
|
||||
*/
|
||||
protected $episode;
|
||||
|
||||
|
@ -44,50 +44,61 @@ class Credit extends Entity
|
|||
public function getPodcast()
|
||||
{
|
||||
return (new PodcastModel())->getPodcastById(
|
||||
$this->attributes['podcast_id']
|
||||
$this->attributes['podcast_id'],
|
||||
);
|
||||
}
|
||||
|
||||
public function getEpisode()
|
||||
{
|
||||
if (empty($this->attributes['episode_id'])) {
|
||||
return null;
|
||||
} else {
|
||||
return (new EpisodeModel())->getEpisodeById(
|
||||
$this->attributes['podcast_id'],
|
||||
$this->attributes['episode_id']
|
||||
if (empty($this->episode_id)) {
|
||||
throw new \RuntimeException(
|
||||
'Credit must have episode_id before getting episode.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->episode)) {
|
||||
$this->episode = (new EpisodeModel())->getPublishedEpisodeById(
|
||||
$this->episode_id,
|
||||
$this->podcast_id,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->episode;
|
||||
}
|
||||
|
||||
public function getPerson()
|
||||
{
|
||||
return (new PersonModel())->getPersonById(
|
||||
$this->attributes['person_id']
|
||||
);
|
||||
if (empty($this->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()
|
||||
{
|
||||
if (empty($this->attributes['person_group'])) {
|
||||
if (empty($this->person_group)) {
|
||||
return null;
|
||||
} else {
|
||||
return lang(
|
||||
"PersonsTaxonomy.persons.{$this->attributes['person_group']}.label"
|
||||
);
|
||||
return lang("PersonsTaxonomy.persons.{$this->person_group}.label");
|
||||
}
|
||||
}
|
||||
|
||||
public function getRoleLabel()
|
||||
{
|
||||
if (
|
||||
empty($this->attributes['person_group']) ||
|
||||
empty($this->attributes['person_role'])
|
||||
) {
|
||||
if (empty($this->person_group) || empty($this->person_role)) {
|
||||
return null;
|
||||
} else {
|
||||
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\SoundbiteModel;
|
||||
use App\Models\EpisodePersonModel;
|
||||
use App\Models\NoteModel;
|
||||
use CodeIgniter\Entity;
|
||||
use CodeIgniter\I18n\Time;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
|
@ -28,7 +29,7 @@ class Episode extends Entity
|
|||
protected $link;
|
||||
|
||||
/**
|
||||
* @var \App\Entities\Image
|
||||
* @var \App\Libraries\Image
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
|
@ -80,13 +81,18 @@ class Episode extends Entity
|
|||
/**
|
||||
* @var \App\Entities\EpisodePerson[]
|
||||
*/
|
||||
protected $episode_persons;
|
||||
protected $persons;
|
||||
|
||||
/**
|
||||
* @var \App\Entities\Soundbite[]
|
||||
*/
|
||||
protected $soundbites;
|
||||
|
||||
/**
|
||||
* @var \App\Entities\Note[]
|
||||
*/
|
||||
protected $notes;
|
||||
|
||||
/**
|
||||
* Holds text only description, striped of any markdown or html special characters
|
||||
*
|
||||
|
@ -122,6 +128,7 @@ class Episode extends Entity
|
|||
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'podcast_id' => 'integer',
|
||||
'guid' => 'string',
|
||||
'slug' => 'string',
|
||||
'title' => 'string',
|
||||
|
@ -133,6 +140,7 @@ class Episode extends Entity
|
|||
'description_markdown' => 'string',
|
||||
'description_html' => 'string',
|
||||
'image_uri' => '?string',
|
||||
'image_mimetype' => '?string',
|
||||
'transcript_uri' => '?string',
|
||||
'chapters_uri' => '?string',
|
||||
'parental_advisory' => '?string',
|
||||
|
@ -144,6 +152,9 @@ class Episode extends Entity
|
|||
'location_geo' => '?string',
|
||||
'location_osmid' => '?string',
|
||||
'custom_rss' => '?json-array',
|
||||
'favourites_total' => 'integer',
|
||||
'reblogs_total' => 'integer',
|
||||
'notes_total' => 'integer',
|
||||
'created_by' => 'integer',
|
||||
'updated_by' => 'integer',
|
||||
];
|
||||
|
@ -163,15 +174,16 @@ class Episode extends Entity
|
|||
) {
|
||||
helper('media');
|
||||
|
||||
// check whether the user has inputted an image and store it
|
||||
$this->attributes['image_uri'] = save_podcast_media(
|
||||
// check whether the user has inputted an image and store
|
||||
$this->attributes['image_mimetype'] = $image->getMimeType();
|
||||
$this->attributes['image_uri'] = save_media(
|
||||
$image,
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug']
|
||||
'podcasts/' . $this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
);
|
||||
|
||||
$this->image = new \App\Entities\Image(
|
||||
$this->attributes['image_uri']
|
||||
$this->image = new \App\Libraries\Image(
|
||||
$this->attributes['image_uri'],
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
$this->image->saveSizes();
|
||||
}
|
||||
|
@ -179,10 +191,13 @@ class Episode extends Entity
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getImage(): \App\Entities\Image
|
||||
public function getImage(): \App\Libraries\Image
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -204,13 +219,13 @@ class Episode extends Entity
|
|||
|
||||
$enclosure_metadata = get_file_tags($enclosure);
|
||||
|
||||
$this->attributes['enclosure_uri'] = save_podcast_media(
|
||||
$this->attributes['enclosure_uri'] = save_media(
|
||||
$enclosure,
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug']
|
||||
'podcasts/' . $this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
);
|
||||
$this->attributes['enclosure_duration'] = round(
|
||||
$enclosure_metadata['playtime_seconds']
|
||||
$enclosure_metadata['playtime_seconds'],
|
||||
);
|
||||
$this->attributes['enclosure_mimetype'] =
|
||||
$enclosure_metadata['mime_type'];
|
||||
|
@ -238,10 +253,10 @@ class Episode extends Entity
|
|||
) {
|
||||
helper('media');
|
||||
|
||||
$this->attributes['transcript_uri'] = save_podcast_media(
|
||||
$this->attributes['transcript_uri'] = save_media(
|
||||
$transcript,
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug'] . '-transcript'
|
||||
$this->attributes['slug'] . '-transcript',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -263,10 +278,10 @@ class Episode extends Entity
|
|||
) {
|
||||
helper('media');
|
||||
|
||||
$this->attributes['chapters_uri'] = save_podcast_media(
|
||||
$this->attributes['chapters_uri'] = save_media(
|
||||
$chapters,
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug'] . '-chapters'
|
||||
$this->attributes['slug'] . '-chapters',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -343,15 +358,15 @@ class Episode extends Entity
|
|||
$this->attributes[
|
||||
'enclosure_duration'
|
||||
]) *
|
||||
60
|
||||
60,
|
||||
),
|
||||
$this->attributes['enclosure_filesize'],
|
||||
$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[]
|
||||
*/
|
||||
public function getEpisodePersons()
|
||||
public function getPersons()
|
||||
{
|
||||
if (empty($this->id)) {
|
||||
throw new \RuntimeException(
|
||||
'Episode must be created before getting persons.'
|
||||
'Episode must be created before getting persons.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->episode_persons)) {
|
||||
$this->episode_persons = (new EpisodePersonModel())->getPersonsByEpisodeId(
|
||||
if (empty($this->persons)) {
|
||||
$this->persons = (new EpisodePersonModel())->getPersonsByEpisodeId(
|
||||
$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)) {
|
||||
throw new \RuntimeException(
|
||||
'Episode must be created before getting soundbites.'
|
||||
'Episode must be created before getting soundbites.',
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->soundbites)) {
|
||||
$this->soundbites = (new SoundbiteModel())->getEpisodeSoundbites(
|
||||
$this->getPodcast()->id,
|
||||
$this->id
|
||||
$this->id,
|
||||
);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
return base_url(
|
||||
route_to(
|
||||
'episode',
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug']
|
||||
)
|
||||
$this->attributes['slug'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -444,13 +474,13 @@ class Episode extends Entity
|
|||
'embeddable-player-theme',
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug'],
|
||||
$theme
|
||||
$theme,
|
||||
)
|
||||
: route_to(
|
||||
'embeddable-player',
|
||||
$this->getPodcast()->name,
|
||||
$this->attributes['slug']
|
||||
)
|
||||
$this->attributes['slug'],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -464,7 +494,7 @@ class Episode extends Entity
|
|||
public function getPodcast()
|
||||
{
|
||||
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_html'] = $converter->convertToHtml(
|
||||
$descriptionMarkdown
|
||||
$descriptionMarkdown,
|
||||
);
|
||||
|
||||
return $this;
|
||||
|
@ -510,25 +540,11 @@ class Episode extends Entity
|
|||
preg_replace(
|
||||
'/\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()
|
||||
{
|
||||
if ($this->publication_status) {
|
||||
|
@ -588,7 +604,7 @@ class Episode extends Entity
|
|||
return '';
|
||||
} else {
|
||||
$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('item');
|
||||
|
@ -596,7 +612,7 @@ class Episode extends Entity
|
|||
[
|
||||
'elements' => $this->custom_rss,
|
||||
],
|
||||
$xmlNode
|
||||
$xmlNode,
|
||||
);
|
||||
return str_replace(['<item>', '</item>'], '', $xmlNode->asXML());
|
||||
}
|
||||
|
@ -615,12 +631,12 @@ class Episode extends Entity
|
|||
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>' .
|
||||
$customRssString .
|
||||
'</item></channel></rss>'
|
||||
)
|
||||
'</item></channel></rss>',
|
||||
),
|
||||
)['elements'][0]['elements'][0];
|
||||
if (array_key_exists('elements', $customRssArray)) {
|
||||
$this->attributes['custom_rss'] = json_encode(
|
||||
$customRssArray['elements']
|
||||
$customRssArray['elements'],
|
||||
);
|
||||
} else {
|
||||
$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
|
||||
{
|
||||
/**
|
||||
* @var \App\Entities\Image
|
||||
* @var \App\Libraries\Image
|
||||
*/
|
||||
protected $image;
|
||||
|
||||
|
@ -23,12 +23,13 @@ class Person extends Entity
|
|||
'unique_name' => 'string',
|
||||
'information_url' => '?string',
|
||||
'image_uri' => 'string',
|
||||
'image_mimetype' => 'string',
|
||||
'created_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
|
||||
*
|
||||
|
@ -38,13 +39,15 @@ class Person extends Entity
|
|||
if ($image) {
|
||||
helper('media');
|
||||
|
||||
$this->attributes['image_uri'] = save_podcast_media(
|
||||
$this->attributes['image_mimetype'] = $image->getMimeType();
|
||||
$this->attributes['image_uri'] = save_media(
|
||||
$image,
|
||||
'~person',
|
||||
$this->attributes['unique_name']
|
||||
'persons',
|
||||
$this->attributes['unique_name'],
|
||||
);
|
||||
$this->image = new \App\Entities\Image(
|
||||
$this->attributes['image_uri']
|
||||
$this->image = new \App\Libraries\Image(
|
||||
$this->attributes['image_uri'],
|
||||
$this->attributes['image_mimetype'],
|
||||
);
|
||||
$this->image->saveSizes();
|
||||
}
|
||||
|
@ -54,6 +57,9 @@ class Person extends Entity
|
|||
|
||||
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