initial import
commit
ef25c5b3af
|
@ -0,0 +1,3 @@
|
||||||
|
composer.lock
|
||||||
|
vendor
|
||||||
|
php/version.php
|
|
@ -0,0 +1,369 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Phan\Issue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This configuration file was automatically generated by 'phan --init --init-level=1'
|
||||||
|
*
|
||||||
|
* TODOs (added by 'phan --init'):
|
||||||
|
*
|
||||||
|
* - Go through this file and verify that there are no missing/unnecessary files/directories.
|
||||||
|
* (E.g. this only includes direct composer dependencies - You may have to manually add indirect composer dependencies to 'directory_list')
|
||||||
|
* - Look at 'plugins' and add or remove plugins if appropriate (see https://github.com/phan/phan/tree/v5/.phan/plugins#plugins)
|
||||||
|
* - Add global suppressions for pre-existing issues to suppress_issue_types (https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base)
|
||||||
|
* - Consider setting up a baseline if there are a large number of pre-existing issues (see `phan --extended-help`)
|
||||||
|
*
|
||||||
|
* This configuration will be read and overlaid on top of the
|
||||||
|
* default configuration. Command line arguments will be applied
|
||||||
|
* after this file is read.
|
||||||
|
*
|
||||||
|
* @see https://github.com/phan/phan/wiki/Phan-Config-Settings for all configurable options
|
||||||
|
* @see https://github.com/phan/phan/tree/v5/src/Phan/Config.php
|
||||||
|
*
|
||||||
|
* A Note About Paths
|
||||||
|
* ==================
|
||||||
|
*
|
||||||
|
* Files referenced from this file should be defined as
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* Config::projectPath('relative_path/to/file')
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* where the relative path is relative to the root of the
|
||||||
|
* project which is defined as either the working directory
|
||||||
|
* of the phan executable or a path passed in via the CLI
|
||||||
|
* '-d' flag.
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
|
||||||
|
// The PHP version that the codebase will be checked for compatibility against.
|
||||||
|
// For best results, the PHP binary used to run Phan should have the same PHP version.
|
||||||
|
// (Phan relies on Reflection for some types, param counts,
|
||||||
|
// and checks for undefined classes/methods/functions)
|
||||||
|
//
|
||||||
|
// Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`, `'7.4'`,
|
||||||
|
// `'8.0'`, `'8.1'`, `'8.2'`, `'8.3'`, `null`.
|
||||||
|
// If this is set to `null`,
|
||||||
|
// then Phan assumes the PHP version which is closest to the minor version
|
||||||
|
// of the php executable used to execute Phan.
|
||||||
|
//
|
||||||
|
// Note that the **only** effect of choosing `'5.6'` is to infer that functions removed in php 7.0 exist.
|
||||||
|
// (See `backward_compatibility_checks` for additional options)
|
||||||
|
// TODO: Choose a target_php_version for this project, or leave as null and remove this comment
|
||||||
|
'target_php_version' => '8.3',
|
||||||
|
|
||||||
|
// If enabled, missing properties will be created when
|
||||||
|
// they are first seen. If false, we'll report an
|
||||||
|
// error message if there is an attempt to write
|
||||||
|
// to a class property that wasn't explicitly
|
||||||
|
// defined.
|
||||||
|
'allow_missing_properties' => false,
|
||||||
|
|
||||||
|
// If enabled, null can be cast to any type and any
|
||||||
|
// type can be cast to null. Setting this to true
|
||||||
|
// will cut down on false positives.
|
||||||
|
'null_casts_as_any_type' => false,
|
||||||
|
|
||||||
|
// If enabled, allow null to be cast as any array-like type.
|
||||||
|
//
|
||||||
|
// This is an incremental step in migrating away from `null_casts_as_any_type`.
|
||||||
|
// If `null_casts_as_any_type` is true, this has no effect.
|
||||||
|
'null_casts_as_array' => false,
|
||||||
|
|
||||||
|
// If enabled, allow any array-like type to be cast to null.
|
||||||
|
// This is an incremental step in migrating away from `null_casts_as_any_type`.
|
||||||
|
// If `null_casts_as_any_type` is true, this has no effect.
|
||||||
|
'array_casts_as_null' => false,
|
||||||
|
|
||||||
|
// If enabled, scalars (int, float, bool, string, null)
|
||||||
|
// are treated as if they can cast to each other.
|
||||||
|
// This does not affect checks of array keys. See `scalar_array_key_cast`.
|
||||||
|
'scalar_implicit_cast' => false,
|
||||||
|
|
||||||
|
// If enabled, any scalar array keys (int, string)
|
||||||
|
// are treated as if they can cast to each other.
|
||||||
|
// E.g. `array<int,stdClass>` can cast to `array<string,stdClass>` and vice versa.
|
||||||
|
// Normally, a scalar type such as int could only cast to/from int and mixed.
|
||||||
|
'scalar_array_key_cast' => false,
|
||||||
|
|
||||||
|
// If this has entries, scalars (int, float, bool, string, null)
|
||||||
|
// are allowed to perform the casts listed.
|
||||||
|
//
|
||||||
|
// E.g. `['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']]`
|
||||||
|
// allows casting null to a string, but not vice versa.
|
||||||
|
// (subset of `scalar_implicit_cast`)
|
||||||
|
'scalar_implicit_partial' => [],
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type in a method invocation's object
|
||||||
|
// is definitely not an object,
|
||||||
|
// or if **any** type in an invoked expression is not a callable.
|
||||||
|
// Setting this to true will introduce numerous false positives
|
||||||
|
// (and reveal some bugs).
|
||||||
|
'strict_method_checking' => true,
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type of the object expression for a property access
|
||||||
|
// does not contain that property.
|
||||||
|
'strict_object_checking' => true,
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type in the argument's union type
|
||||||
|
// cannot be cast to a type in the parameter's expected union type.
|
||||||
|
// Setting this to true will introduce numerous false positives
|
||||||
|
// (and reveal some bugs).
|
||||||
|
'strict_param_checking' => true,
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type in a property assignment's union type
|
||||||
|
// cannot be cast to a type in the property's declared union type.
|
||||||
|
// Setting this to true will introduce numerous false positives
|
||||||
|
// (and reveal some bugs).
|
||||||
|
'strict_property_checking' => true,
|
||||||
|
|
||||||
|
// If enabled, Phan will warn if **any** type in a returned value's union type
|
||||||
|
// cannot be cast to the declared return type.
|
||||||
|
// Setting this to true will introduce numerous false positives
|
||||||
|
// (and reveal some bugs).
|
||||||
|
'strict_return_checking' => true,
|
||||||
|
|
||||||
|
// If true, seemingly undeclared variables in the global
|
||||||
|
// scope will be ignored.
|
||||||
|
//
|
||||||
|
// This is useful for projects with complicated cross-file
|
||||||
|
// globals that you have no hope of fixing.
|
||||||
|
'ignore_undeclared_variables_in_global_scope' => false,
|
||||||
|
|
||||||
|
// Set this to false to emit `PhanUndeclaredFunction` issues for internal functions that Phan has signatures for,
|
||||||
|
// but aren't available in the codebase, or from Reflection.
|
||||||
|
// (may lead to false positives if an extension isn't loaded)
|
||||||
|
//
|
||||||
|
// If this is true(default), then Phan will not warn.
|
||||||
|
//
|
||||||
|
// Even when this is false, Phan will still infer return values and check parameters of internal functions
|
||||||
|
// if Phan has the signatures.
|
||||||
|
'ignore_undeclared_functions_with_known_signatures' => false,
|
||||||
|
|
||||||
|
// Backwards Compatibility Checking. This is slow
|
||||||
|
// and expensive, but you should consider running
|
||||||
|
// it before upgrading your version of PHP to a
|
||||||
|
// new version that has backward compatibility
|
||||||
|
// breaks.
|
||||||
|
//
|
||||||
|
// If you are migrating from PHP 5 to PHP 7,
|
||||||
|
// you should also look into using
|
||||||
|
// [php7cc (no longer maintained)](https://github.com/sstalle/php7cc)
|
||||||
|
// and [php7mar](https://github.com/Alexia/php7mar),
|
||||||
|
// which have different backwards compatibility checks.
|
||||||
|
//
|
||||||
|
// If you are still using versions of php older than 5.6,
|
||||||
|
// `PHP53CompatibilityPlugin` may be worth looking into if you are not running
|
||||||
|
// syntax checks for php 5.3 through another method such as
|
||||||
|
// `InvokePHPNativeSyntaxCheckPlugin` (see .phan/plugins/README.md).
|
||||||
|
'backward_compatibility_checks' => false,
|
||||||
|
|
||||||
|
// If true, check to make sure the return type declared
|
||||||
|
// in the doc-block (if any) matches the return type
|
||||||
|
// declared in the method signature.
|
||||||
|
'check_docblock_signature_return_type_match' => true,
|
||||||
|
|
||||||
|
// This setting maps case-insensitive strings to union types.
|
||||||
|
//
|
||||||
|
// This is useful if a project uses phpdoc that differs from the phpdoc2 standard.
|
||||||
|
//
|
||||||
|
// If the corresponding value is the empty string,
|
||||||
|
// then Phan will ignore that union type (E.g. can ignore 'the' in `@return the value`)
|
||||||
|
//
|
||||||
|
// If the corresponding value is not empty,
|
||||||
|
// then Phan will act as though it saw the corresponding UnionTypes(s)
|
||||||
|
// when the keys show up in a UnionType of `@param`, `@return`, `@var`, `@property`, etc.
|
||||||
|
//
|
||||||
|
// This matches the **entire string**, not parts of the string.
|
||||||
|
// (E.g. `@return the|null` will still look for a class with the name `the`, but `@return the` will be ignored with the below setting)
|
||||||
|
//
|
||||||
|
// (These are not aliases, this setting is ignored outside of doc comments).
|
||||||
|
// (Phan does not check if classes with these names exist)
|
||||||
|
//
|
||||||
|
// Example setting: `['unknown' => '', 'number' => 'int|float', 'char' => 'string', 'long' => 'int', 'the' => '']`
|
||||||
|
'phpdoc_type_mapping' => [],
|
||||||
|
|
||||||
|
// Set to true in order to attempt to detect dead
|
||||||
|
// (unreferenced) code. Keep in mind that the
|
||||||
|
// results will only be a guess given that classes,
|
||||||
|
// properties, constants and methods can be referenced
|
||||||
|
// as variables (like `$class->$property` or
|
||||||
|
// `$class->$method()`) in ways that we're unable
|
||||||
|
// to make sense of.
|
||||||
|
//
|
||||||
|
// To more aggressively detect dead code,
|
||||||
|
// you may want to set `dead_code_detection_prefer_false_negative` to `false`.
|
||||||
|
'dead_code_detection' => false,
|
||||||
|
|
||||||
|
// Set to true in order to attempt to detect unused variables.
|
||||||
|
// `dead_code_detection` will also enable unused variable detection.
|
||||||
|
//
|
||||||
|
// This has a few known false positives, e.g. for loops or branches.
|
||||||
|
'unused_variable_detection' => true,
|
||||||
|
|
||||||
|
// Set to true in order to attempt to detect redundant and impossible conditions.
|
||||||
|
//
|
||||||
|
// This has some false positives involving loops,
|
||||||
|
// variables set in branches of loops, and global variables.
|
||||||
|
'redundant_condition_detection' => true,
|
||||||
|
|
||||||
|
// If enabled, Phan will act as though it's certain of real return types of a subset of internal functions,
|
||||||
|
// even if those return types aren't available in reflection (real types were taken from php 7.3 or 8.0-dev, depending on target_php_version).
|
||||||
|
//
|
||||||
|
// Note that with php 7 and earlier, php would return null or false for many internal functions if the argument types or counts were incorrect.
|
||||||
|
// As a result, enabling this setting with target_php_version 8.0 may result in false positives for `--redundant-condition-detection` when codebases also support php 7.x.
|
||||||
|
'assume_real_types_for_internal_functions' => true,
|
||||||
|
|
||||||
|
// If true, this runs a quick version of checks that takes less
|
||||||
|
// time at the cost of not running as thorough
|
||||||
|
// of an analysis. You should consider setting this
|
||||||
|
// to true only when you wish you had more **undiagnosed** issues
|
||||||
|
// to fix in your code base.
|
||||||
|
//
|
||||||
|
// In quick-mode the scanner doesn't rescan a function
|
||||||
|
// or a method's code block every time a call is seen.
|
||||||
|
// This means that the problem here won't be detected:
|
||||||
|
//
|
||||||
|
// ```php
|
||||||
|
// <?php
|
||||||
|
// function test($arg):int {
|
||||||
|
// return $arg;
|
||||||
|
// }
|
||||||
|
// test("abc");
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// This would normally generate:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// test.php:3 PhanTypeMismatchReturn Returning type string but test() is declared to return int
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// The initial scan of the function's code block has no
|
||||||
|
// type information for `$arg`. It isn't until we see
|
||||||
|
// the call and rescan `test()`'s code block that we can
|
||||||
|
// detect that it is actually returning the passed in
|
||||||
|
// `string` instead of an `int` as declared.
|
||||||
|
'quick_mode' => false,
|
||||||
|
|
||||||
|
// Override to hardcode existence and types of (non-builtin) globals in the global scope.
|
||||||
|
// Class names should be prefixed with `\`.
|
||||||
|
//
|
||||||
|
// (E.g. `['_FOO' => '\FooClass', 'page' => '\PageClass', 'userId' => 'int']`)
|
||||||
|
'globals_type_map' => [],
|
||||||
|
|
||||||
|
// The minimum severity level to report on. This can be
|
||||||
|
// set to `Issue::SEVERITY_LOW`, `Issue::SEVERITY_NORMAL` or
|
||||||
|
// `Issue::SEVERITY_CRITICAL`. Setting it to only
|
||||||
|
// critical issues is a good place to start on a big
|
||||||
|
// sloppy mature code base.
|
||||||
|
'minimum_severity' => Issue::SEVERITY_LOW,
|
||||||
|
|
||||||
|
// Add any issue types (such as `'PhanUndeclaredMethod'`)
|
||||||
|
// to this list to inhibit them from being reported.
|
||||||
|
'suppress_issue_types' => [],
|
||||||
|
|
||||||
|
// A regular expression to match files to be excluded
|
||||||
|
// from parsing and analysis and will not be read at all.
|
||||||
|
//
|
||||||
|
// This is useful for excluding groups of test or example
|
||||||
|
// directories/files, unanalyzable files, or files that
|
||||||
|
// can't be removed for whatever reason.
|
||||||
|
// (e.g. `'@Test\.php$@'`, or `'@vendor/.*/(tests|Tests)/@'`)
|
||||||
|
'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@',
|
||||||
|
|
||||||
|
// A list of files that will be excluded from parsing and analysis
|
||||||
|
// and will not be read at all.
|
||||||
|
//
|
||||||
|
// This is useful for excluding hopelessly unanalyzable
|
||||||
|
// files that can't be removed for whatever reason.
|
||||||
|
'exclude_file_list' => [],
|
||||||
|
|
||||||
|
// A directory list that defines files that will be excluded
|
||||||
|
// from static analysis, but whose class and method
|
||||||
|
// information should be included.
|
||||||
|
//
|
||||||
|
// Generally, you'll want to include the directories for
|
||||||
|
// third-party code (such as "vendor/") in this list.
|
||||||
|
//
|
||||||
|
// n.b.: If you'd like to parse but not analyze 3rd
|
||||||
|
// party code, directories containing that code
|
||||||
|
// should be added to the `directory_list` as well as
|
||||||
|
// to `exclude_analysis_directory_list`.
|
||||||
|
'exclude_analysis_directory_list' => [
|
||||||
|
'vendor/',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Enable this to enable checks of require/include statements referring to valid paths.
|
||||||
|
// The settings `include_paths` and `warn_about_relative_include_statement` affect the checks.
|
||||||
|
'enable_include_path_checks' => true,
|
||||||
|
|
||||||
|
// The number of processes to fork off during the analysis
|
||||||
|
// phase.
|
||||||
|
'processes' => 1,
|
||||||
|
|
||||||
|
// List of case-insensitive file extensions supported by Phan.
|
||||||
|
// (e.g. `['php', 'html', 'htm']`)
|
||||||
|
'analyzed_file_extensions' => [
|
||||||
|
'php',
|
||||||
|
],
|
||||||
|
|
||||||
|
// You can put paths to stubs of internal extensions in this config option.
|
||||||
|
// If the corresponding extension is **not** loaded, then Phan will use the stubs instead.
|
||||||
|
// Phan will continue using its detailed type annotations,
|
||||||
|
// but load the constants, classes, functions, and classes (and their Reflection types)
|
||||||
|
// from these stub files (doubling as valid php files).
|
||||||
|
// Use a different extension from php to avoid accidentally loading these.
|
||||||
|
// The `tools/make_stubs` script can be used to generate your own stubs (compatible with php 7.0+ right now)
|
||||||
|
//
|
||||||
|
// (e.g. `['xdebug' => '.phan/internal_stubs/xdebug.phan_php']`)
|
||||||
|
'autoload_internal_extension_signatures' => [],
|
||||||
|
|
||||||
|
// A list of plugin files to execute.
|
||||||
|
//
|
||||||
|
// Plugins which are bundled with Phan can be added here by providing their name (e.g. `'AlwaysReturnPlugin'`)
|
||||||
|
//
|
||||||
|
// Documentation about available bundled plugins can be found [here](https://github.com/phan/phan/tree/v5/.phan/plugins).
|
||||||
|
//
|
||||||
|
// Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. `'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'`)
|
||||||
|
'plugins' => [
|
||||||
|
'AlwaysReturnPlugin',
|
||||||
|
'DollarDollarPlugin',
|
||||||
|
'DuplicateArrayKeyPlugin',
|
||||||
|
'DuplicateExpressionPlugin',
|
||||||
|
'PregRegexCheckerPlugin',
|
||||||
|
'PrintfCheckerPlugin',
|
||||||
|
'SleepCheckerPlugin',
|
||||||
|
'UnreachableCodePlugin',
|
||||||
|
'NonBoolBranchPlugin',
|
||||||
|
'NonBoolInLogicalArithPlugin',
|
||||||
|
'InvalidVariableIssetPlugin',
|
||||||
|
'NumericalComparisonPlugin',
|
||||||
|
'PHPUnitNotDeadCodePlugin',
|
||||||
|
'UnusedSuppressionPlugin',
|
||||||
|
'UnknownElementTypePlugin',
|
||||||
|
'UseReturnValuePlugin',
|
||||||
|
'EmptyStatementListPlugin',
|
||||||
|
'StrictComparisonPlugin',
|
||||||
|
'LoopVariableReusePlugin',
|
||||||
|
'WhitespacePlugin',
|
||||||
|
'PossiblyStaticMethodPlugin',
|
||||||
|
'PHPDocRedundantPlugin',
|
||||||
|
],
|
||||||
|
|
||||||
|
// A list of directories that should be parsed for class and
|
||||||
|
// method information. After excluding the directories
|
||||||
|
// defined in `exclude_analysis_directory_list`, the remaining
|
||||||
|
// files will be statically analyzed for errors.
|
||||||
|
//
|
||||||
|
// Thus, both first-party and third-party code being used by
|
||||||
|
// your application should be included in this list.
|
||||||
|
'directory_list' => [
|
||||||
|
'vendor/phan/phan/src/Phan',
|
||||||
|
'vendor/smarty/smarty/src',
|
||||||
|
],
|
||||||
|
|
||||||
|
// A list of individual files to include in analysis
|
||||||
|
// with a path relative to the root directory of the
|
||||||
|
// project.
|
||||||
|
'file_list' => [],
|
||||||
|
];
|
|
@ -0,0 +1,41 @@
|
||||||
|
# A system to connect non-federated system to federation (ActivityPub)
|
||||||
|
NOTE: this is work in progress, it is nowhere near completion nor function
|
||||||
|
|
||||||
|
## installation
|
||||||
|
install dependencies by using
|
||||||
|
|
||||||
|
> composer install
|
||||||
|
|
||||||
|
Upload/copy the files to a directory where php can be run from.
|
||||||
|
The files in the htdocs should be the only reachable, the others should not be served via the web server.
|
||||||
|
Structure:
|
||||||
|
- htdocs <= reachable
|
||||||
|
- php <= implementation
|
||||||
|
- plugins <= plugin directory for well - plugins
|
||||||
|
- config.ini <= the configuration
|
||||||
|
|
||||||
|
The default config includes a dummy plugin to connect to a non-exisitng server. It accepts any session id and profile name.
|
||||||
|
The database is not used yet, but it must be created and the user with given account data must be able to reach it.
|
||||||
|
|
||||||
|
Needed SQL commands:
|
||||||
|
|
||||||
|
create database federator;
|
||||||
|
create user if not exists 'federator'@'localhost' identified by '*change*me*';
|
||||||
|
grant select,insert,update,delete on federator.* to 'federator'@'localhost';
|
||||||
|
|
||||||
|
This will be changed, but works for the current develop verison.
|
||||||
|
|
||||||
|
To configure an apache server, add the following rewrite rules:
|
||||||
|
|
||||||
|
<Directory /where/ever/you/put/it>
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteBase /
|
||||||
|
RewriteRule ^api/(.+)$ api.php?_call=$1 [L]
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
With the dummy plugin and everything installed correctly a
|
||||||
|
|
||||||
|
> curl -v http://localhost/api/v1/dummy/moo -H "X-Session: somethingvalid" -H "X-Profile: ihaveone"
|
||||||
|
|
||||||
|
should return a piece of ascii art.
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "contentnation/federator",
|
||||||
|
"description": "A federation service",
|
||||||
|
"type": "project",
|
||||||
|
"require": {
|
||||||
|
"smarty/smarty": "^5.3"
|
||||||
|
},
|
||||||
|
"license": "GPL-3.0-or-later",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Sascha Nitsch",
|
||||||
|
"email": "grumpydevelop@contentnation.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require-dev": {
|
||||||
|
"phan/phan": "^5.4"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
[database]
|
||||||
|
host = '127.0.0.1'
|
||||||
|
username = 'federator'
|
||||||
|
password = '*change*me*'
|
||||||
|
database = 'federator'
|
||||||
|
|
||||||
|
[templates]
|
||||||
|
path = '../templates/'
|
||||||
|
compiledir = '../cache'
|
||||||
|
|
||||||
|
[plugins]
|
||||||
|
rediscache = '../plugins/rediscache.php'
|
||||||
|
dummy = '../plugins/dummyconnector.php'
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
if (! array_key_exists('_call', $_REQUEST)) {
|
||||||
|
http_response_code(404);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
date_default_timezone_set("Europe/Berlin");
|
||||||
|
spl_autoload_register(function ($className) {
|
||||||
|
// strip Federator from class path
|
||||||
|
$className = str_replace('Federator\\', '', $className);
|
||||||
|
include '../php/' . str_replace("\\", "/", strtolower($className)) . '.php';
|
||||||
|
});
|
||||||
|
|
||||||
|
/// main instance
|
||||||
|
$contentnation = new \Federator\Api();
|
||||||
|
$contentnation->run();
|
|
@ -0,0 +1,252 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main API class
|
||||||
|
*/
|
||||||
|
class Api extends Main
|
||||||
|
{
|
||||||
|
/** @var string called path */
|
||||||
|
private $path;
|
||||||
|
|
||||||
|
/** @var array<string> path elements for the API call */
|
||||||
|
private $paths;
|
||||||
|
|
||||||
|
/** @var Data\User current user */
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
/** @var int cache time default to 0 */
|
||||||
|
private $cacheTime = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->smarty = null;
|
||||||
|
$this->contentType = "application/json";
|
||||||
|
Main::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set path
|
||||||
|
*
|
||||||
|
* @param string $call
|
||||||
|
* path of called function
|
||||||
|
*/
|
||||||
|
public function setPath(string $call) : void
|
||||||
|
{
|
||||||
|
$this->path = $call;
|
||||||
|
while ($this->path[0] === '/') {
|
||||||
|
$this->path = substr($this->path, 1);
|
||||||
|
}
|
||||||
|
$this->paths = explode("/", $this->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main API function
|
||||||
|
*/
|
||||||
|
public function run() : void
|
||||||
|
{
|
||||||
|
$this->setPath($_REQUEST["_call"]);
|
||||||
|
$this->openDatabase();
|
||||||
|
$this->loadPlugins();
|
||||||
|
$retval = "";
|
||||||
|
/** @var \Api\Api */
|
||||||
|
$handler = null;
|
||||||
|
if (!array_key_exists('HTTP_X_SESSION', $_SERVER) || !array_key_exists('HTTP_X_PROFILE', $_SERVER)) {
|
||||||
|
http_response_code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($this->connector === null) {
|
||||||
|
http_response_code(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->user = DIO\User::getUserBySession(
|
||||||
|
$this->dbh,
|
||||||
|
$_SERVER['HTTP_X_SESSION'],
|
||||||
|
$_SERVER['HTTP_X_PROFILE'],
|
||||||
|
$this->connector,
|
||||||
|
$this->cache
|
||||||
|
);
|
||||||
|
if ($this->user === false) {
|
||||||
|
http_response_code(403);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch ($this->path[0]) {
|
||||||
|
case 'v':
|
||||||
|
if ($this->paths[0] === "v1") {
|
||||||
|
switch ($this->paths[1]) {
|
||||||
|
case 'dummy':
|
||||||
|
$handler = new Api\V1\Dummy($this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$printresponse = true;
|
||||||
|
if ($handler !== null) {
|
||||||
|
try {
|
||||||
|
$printresponse = $handler->exec($this->paths);
|
||||||
|
if ($printresponse) {
|
||||||
|
$retval = $handler->toJson();
|
||||||
|
}
|
||||||
|
} catch (Exceptions\Exception $e) {
|
||||||
|
$this->setResponseCode($e->getRetCode());
|
||||||
|
$retval = json_encode(array(
|
||||||
|
"error" => $e->getMessage()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->responseCode = 404;
|
||||||
|
}
|
||||||
|
if (sizeof($this->headers) != 0) {
|
||||||
|
foreach ($this->headers as $name => $value) {
|
||||||
|
header($name . ': ' . $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($printresponse) {
|
||||||
|
if ($this->redirect !== null) {
|
||||||
|
header("Location: $this->redirect");
|
||||||
|
}
|
||||||
|
if ($this->responseCode != 200) {
|
||||||
|
http_response_code($this->responseCode);
|
||||||
|
}
|
||||||
|
if ($this->responseCode != 404) {
|
||||||
|
header("Content-type: " . $this->contentType);
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
}
|
||||||
|
if ($this->cacheTime == 0) {
|
||||||
|
header("Cache-Control: no-cache, no-store, must-revalidate");
|
||||||
|
header("Pragma: no-cache");
|
||||||
|
header("Expires: 0");
|
||||||
|
} else {
|
||||||
|
$ts = gmdate("D, d M Y H:i:s", time() + $this->cacheTime) . " GMT";
|
||||||
|
header("Expires: $ts");
|
||||||
|
header("Pragma: cache");
|
||||||
|
header("Cache-Control: max-age=" . $this->cacheTime);
|
||||||
|
}
|
||||||
|
echo $retval;
|
||||||
|
} else {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header("Content-type: " . $this->contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if the current user has the given permission
|
||||||
|
*
|
||||||
|
* @param string|string[] $permission
|
||||||
|
* permission(s) to check for
|
||||||
|
* @param string $exception Exception Type
|
||||||
|
* @param string $message optional message
|
||||||
|
* @throws \Exceptions\PermissionDenied
|
||||||
|
*/
|
||||||
|
public function checkPermission($permission, $exception = "\Exceptions\PermissionDenied", $message = null) : void
|
||||||
|
{
|
||||||
|
// generic check first
|
||||||
|
if ($this->user->id == 0) {
|
||||||
|
throw new Exceptions\PermissionDenied();
|
||||||
|
}
|
||||||
|
if (!is_array($permission)) {
|
||||||
|
$permission = array(
|
||||||
|
$permission
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// LoggedIn is handled above
|
||||||
|
foreach ($permission as $p) {
|
||||||
|
if ($this->user->hasPermission($p)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new $exception($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove unwanted elements from html input
|
||||||
|
*
|
||||||
|
* @param string $_input
|
||||||
|
* input to strip
|
||||||
|
* @return string stripped input
|
||||||
|
*/
|
||||||
|
public static function stripHTML(string $_input) : string
|
||||||
|
{
|
||||||
|
$out = preg_replace('/<(script[^>]*)>/i', '<${1}>', $_input);
|
||||||
|
$out = preg_replace('/<\/(script)>/i', '</${1};>', $out);
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is given parameter in POST data
|
||||||
|
*
|
||||||
|
* @param string $_key
|
||||||
|
* parameter to check
|
||||||
|
* @return bool true if in
|
||||||
|
*/
|
||||||
|
public static function hasPost(string $_key) : bool
|
||||||
|
{
|
||||||
|
return array_key_exists($_key, $_POST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQL escape given POST parameter
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* key to escape
|
||||||
|
* @param boolean $int
|
||||||
|
* is parameter an int
|
||||||
|
* @return int|string
|
||||||
|
*/
|
||||||
|
public function escapePost(string $key, $int = false)
|
||||||
|
{
|
||||||
|
if (! array_key_exists($key, $_POST)) {
|
||||||
|
return $int ? 0 : "";
|
||||||
|
}
|
||||||
|
if ($int === true) {
|
||||||
|
return intval($_POST[$key]);
|
||||||
|
}
|
||||||
|
$ret = $this->dbh->escape_string($this->stripHTML($_POST[$key]));
|
||||||
|
if ($ret === false) {
|
||||||
|
return $int ? 0 : "";
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update $data with POST info using optional alias $altName
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* parameter name
|
||||||
|
* @param array<string,mixed> $data
|
||||||
|
* array to update
|
||||||
|
* @param bool $int
|
||||||
|
* is data an integer
|
||||||
|
* @param string $altName
|
||||||
|
* optional alternative name in POST
|
||||||
|
*/
|
||||||
|
public function updateString(string $name, array &$data, bool $int = false, string $altName = "") : void
|
||||||
|
{
|
||||||
|
if ($this->hasPost($altName ?: $name)) {
|
||||||
|
$content = $this->escapePost($altName ?: $name, $int);
|
||||||
|
$data[$name] = $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set cache time
|
||||||
|
*
|
||||||
|
* @param int $time time in seconds
|
||||||
|
*/
|
||||||
|
public function setCacheTime(int $time) : void
|
||||||
|
{
|
||||||
|
$this->cacheTime = $time;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API interface
|
||||||
|
*/
|
||||||
|
interface V1
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* run given url path
|
||||||
|
* @param string[] $paths path array split by /
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function exec($paths) : bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get internal represenation as json string
|
||||||
|
* @return string json string or html
|
||||||
|
*/
|
||||||
|
public function toJson() : string;
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Api\V1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dummy api class for functional poc
|
||||||
|
*/
|
||||||
|
class Dummy implements \Federator\Api\V1
|
||||||
|
{
|
||||||
|
/** @var \Main $main main instance */
|
||||||
|
private $main;
|
||||||
|
|
||||||
|
/** @var Array<string, string> $message internal message to output */
|
||||||
|
private $message = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
* @param \Main $main main instance
|
||||||
|
*/
|
||||||
|
public function __construct(\Federator\Main $main)
|
||||||
|
{
|
||||||
|
$this->main = $main;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* run given url path
|
||||||
|
* @param string[] $paths path array split by /
|
||||||
|
* @return bool true on success
|
||||||
|
*/
|
||||||
|
public function exec($paths) : bool
|
||||||
|
{
|
||||||
|
$method = $_SERVER["REQUEST_METHOD"];
|
||||||
|
switch ($method) {
|
||||||
|
case 'GET':
|
||||||
|
switch (sizeof($paths)) {
|
||||||
|
case 3:
|
||||||
|
if ($paths[2] === 'moo') {
|
||||||
|
return $this->getDummy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'POST':
|
||||||
|
switch (sizeof($paths)) {
|
||||||
|
case 3:
|
||||||
|
if ($paths[2] === 'moo') {
|
||||||
|
return $this->postDummy();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->main->setResponseCode(404);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get function for "/v1/dummy/moo"
|
||||||
|
*/
|
||||||
|
public function getDummy(): bool
|
||||||
|
{
|
||||||
|
$this->message = [
|
||||||
|
'r1' => ' (__) ',
|
||||||
|
'r2' => ' `------(oo) ',
|
||||||
|
'r3' => ' || __ (__) ',
|
||||||
|
'r4' => ' ||w || ',
|
||||||
|
'r5' => ' '
|
||||||
|
];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* post function for /v1/dummy/moo"
|
||||||
|
*/
|
||||||
|
public function postDummy() : bool
|
||||||
|
{
|
||||||
|
return $this->getDummy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get internal represenation as json string
|
||||||
|
* @return string json string
|
||||||
|
*/
|
||||||
|
public function toJson() : string
|
||||||
|
{
|
||||||
|
return json_encode($this->message, JSON_PRETTY_PRINT) . "\n";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Connector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base class for remote authentication
|
||||||
|
*/
|
||||||
|
interface Connector
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* get remote user by given session
|
||||||
|
* @param string $_session session id
|
||||||
|
* @param string $_user user/profile name
|
||||||
|
* @return \Federator\Data\User | null
|
||||||
|
*/
|
||||||
|
public function getRemoteUserBySession(string $_session, string $_user);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* storage class for user attributes
|
||||||
|
*/
|
||||||
|
class User
|
||||||
|
{
|
||||||
|
/** @var string user id */
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/* @var string user language */
|
||||||
|
//public $lang;
|
||||||
|
|
||||||
|
/** @var array<string> user permissions */
|
||||||
|
public $permissions = [];
|
||||||
|
|
||||||
|
/** @var string session id */
|
||||||
|
public $session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if use has asked permission
|
||||||
|
* @param string $p @unused-param
|
||||||
|
* permission to check
|
||||||
|
*
|
||||||
|
* @return bool true if user has permission, false if not
|
||||||
|
*/
|
||||||
|
public function hasPermission(string $p)
|
||||||
|
{
|
||||||
|
return in_array($p, $this->permissions);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator\DIO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IO functions related to users
|
||||||
|
*/
|
||||||
|
class User
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* extend the given user with internal data
|
||||||
|
* @param \mysqli $dbh database handle @unused-param
|
||||||
|
* @param \Federator\Data\User $user user to extend @unused-param
|
||||||
|
*/
|
||||||
|
protected static function extendUser(\mysqli $dbh, \Federator\Data\User $user) : void
|
||||||
|
{
|
||||||
|
// do nothing for now
|
||||||
|
// TODO: if a new user, create own database entry with additionally needed info
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get User by session id
|
||||||
|
*
|
||||||
|
* @param \mysqli $dbh
|
||||||
|
* database handle
|
||||||
|
* @param string $_session
|
||||||
|
* session
|
||||||
|
* @param string $_user
|
||||||
|
* user/profile name
|
||||||
|
* @param \Connector\Connector? $connector @unused-param
|
||||||
|
* connector to fetch use with
|
||||||
|
* @param \Cache\Cache? $cache
|
||||||
|
* optional caching service
|
||||||
|
* @return \Data\User|bool
|
||||||
|
*/
|
||||||
|
public static function getUserBySession($dbh, $_session, $_user, $connector, $cache)
|
||||||
|
{
|
||||||
|
$user = false;
|
||||||
|
if ($cache) {
|
||||||
|
$user = $cache->getRemoteUserBySession($_session, $_user);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ask connector for user-id
|
||||||
|
$user = $connector->getRemoteUserBySession($_session, $_user);
|
||||||
|
if ($user === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($cache) {
|
||||||
|
$cache->saveRemoteUserBySession($_session, $_user, $user);
|
||||||
|
}
|
||||||
|
self::extendUser($dbh, $user);
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Federator\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base class for our Exceptions
|
||||||
|
*/
|
||||||
|
class Exception extends \Error
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* get matching HTTP response code
|
||||||
|
*
|
||||||
|
* @return int number HTTP response code
|
||||||
|
*/
|
||||||
|
public function getRetCode() : int
|
||||||
|
{
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Federator\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File not found exceptions
|
||||||
|
*/
|
||||||
|
class FileNotFound extends Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
* @param ?string $message optional error message
|
||||||
|
*/
|
||||||
|
public function __construct($message = null)
|
||||||
|
{
|
||||||
|
$this->message = ($message === null) ? "filenotfound" : $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see \Exceptions\Exception::getRetCode()
|
||||||
|
*/
|
||||||
|
public function getRetCode() : int
|
||||||
|
{
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Federator\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalid Argument Exception
|
||||||
|
*/
|
||||||
|
class InvalidArgument extends Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
* @param ?string $message optional error message
|
||||||
|
*/
|
||||||
|
public function __construct($message = null)
|
||||||
|
{
|
||||||
|
$this->message = ($message === null) ? "invalidargument" : $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see \Exceptions\Exception::getRetCode()
|
||||||
|
*/
|
||||||
|
public function getRetCode() : int
|
||||||
|
{
|
||||||
|
return 400;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Federator\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permission denied exception
|
||||||
|
*/
|
||||||
|
class PermissionDenied extends Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* @param ?string $message
|
||||||
|
* error message
|
||||||
|
*/
|
||||||
|
public function __construct($message = null)
|
||||||
|
{
|
||||||
|
$this->message = ($message === null) ? "permissiondenied" : $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* {@inheritdoc}
|
||||||
|
* @see \Exceptions\Exception::getRetCode()
|
||||||
|
*/
|
||||||
|
public function getRetCode() : int
|
||||||
|
{
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Federator\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server Error Exception
|
||||||
|
*/
|
||||||
|
class ServerError extends Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
* @param ?string $message optional error message
|
||||||
|
*/
|
||||||
|
public function __construct($message = null)
|
||||||
|
{
|
||||||
|
$this->message = ($message === null) ? "servererror" : $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see \Exceptions\Exception::getRetCode()
|
||||||
|
*/
|
||||||
|
public function getRetCode() : int
|
||||||
|
{
|
||||||
|
return 500;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* @author Sascha Nitsch (grumpydeveloper)
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Federator\Exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unauthorized Exception
|
||||||
|
*/
|
||||||
|
class Unauthorized extends Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see \Exceptions\Exception::getRetCode()
|
||||||
|
*/
|
||||||
|
public function getRetCode() : int
|
||||||
|
{
|
||||||
|
return 401;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,296 @@
|
||||||
|
-<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* @author Author: Sascha Nitsch (grumpydeveloper)
|
||||||
|
*/
|
||||||
|
require_once '../vendor/autoload.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Language abstraction class
|
||||||
|
* @author Sascha Nitsch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Language {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list of valid languages
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $validLanguages = array(
|
||||||
|
"de" => true,
|
||||||
|
"en" => true,
|
||||||
|
"xy" => true
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* language to use
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $uselang;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* actual language data
|
||||||
|
* @var array<string,array<string,string>>
|
||||||
|
*/
|
||||||
|
private $lang = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor that tries to autodetect language
|
||||||
|
*
|
||||||
|
* @param ?string $uselang
|
||||||
|
* use this language instead of autodetection, set to null if no preference
|
||||||
|
*/
|
||||||
|
function __construct($uselang = null) {
|
||||||
|
$this->lang = Array();
|
||||||
|
if ($uselang !== null) {
|
||||||
|
if (! array_key_exists($uselang, $this->validLanguages)) {
|
||||||
|
$uselang = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($uselang === null && array_key_exists('_lang', $_REQUEST)) {
|
||||||
|
$language = $_REQUEST['_lang'];
|
||||||
|
if (array_key_exists($language, $this->validLanguages)) {
|
||||||
|
$uselang = $language;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($uselang === null && array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
|
||||||
|
$matches = array();
|
||||||
|
if (preg_match("/^(\S\S)\-/",$_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches) == 1) {
|
||||||
|
$language = $matches[1];
|
||||||
|
if (array_key_exists($language, $this->validLanguages)) {
|
||||||
|
$uselang = $language;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($uselang === null) {
|
||||||
|
$uselang = 'de';
|
||||||
|
}
|
||||||
|
$this->uselang = $uselang;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* print translation of given group and id, optionally using variables
|
||||||
|
*
|
||||||
|
* @param string $group
|
||||||
|
* group name
|
||||||
|
* @param string $key
|
||||||
|
* string name
|
||||||
|
* @param array<mixed> $values
|
||||||
|
* optional values to replace
|
||||||
|
* @return string translated string
|
||||||
|
*/
|
||||||
|
function printlang($group, $key, array $values = array()) {
|
||||||
|
if ($this->uselang === 'xy') {
|
||||||
|
return "$group:$key";
|
||||||
|
}
|
||||||
|
if (! isset($this->lang[$group])) {
|
||||||
|
$l = [];
|
||||||
|
$root = $_SERVER['DOCUMENT_ROOT'];
|
||||||
|
if ($root === '') $root = '.';
|
||||||
|
if (@file_exists($root . '/../lang/' . $this->uselang . "/$group.inc")) {
|
||||||
|
require ($root . '/../lang/' . $this->uselang . "/$group.inc");
|
||||||
|
$this->lang[$group] = $l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists($group, $this->lang) && array_key_exists($key, $this->lang[$group])) {
|
||||||
|
$string = $this->lang[$group][$key];
|
||||||
|
for ($i = 0; $i < 9; $i ++) {
|
||||||
|
if (isset($values[$i])) {
|
||||||
|
$string = str_replace("\$$i", $values[$i], $string);
|
||||||
|
} else {
|
||||||
|
$string = str_replace("\$$i", "", $string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
$basedir = $_SERVER['DOCUMENT_ROOT'] . '/../';
|
||||||
|
$fh = @fopen("$basedir/logs/missingtrans.txt", 'a');
|
||||||
|
if ($fh !== false) {
|
||||||
|
fwrite($fh, $this->uselang.":$group:$key\n");
|
||||||
|
fclose($fh);
|
||||||
|
}
|
||||||
|
return ">>$group:$key<<";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get keys (valid ids) of a named group
|
||||||
|
*
|
||||||
|
* @param string $group
|
||||||
|
* group name to fetch keys
|
||||||
|
* @return array<string> list of keys
|
||||||
|
*/
|
||||||
|
function getKeys(string $group) {
|
||||||
|
if (! isset($this->lang[$group])) {
|
||||||
|
$l = [];
|
||||||
|
require_once ($_SERVER['DOCUMENT_ROOT'] . '/../lang/' . $this->uselang . "/$group.inc");
|
||||||
|
$this->lang[$group] = $l;
|
||||||
|
}
|
||||||
|
return array_keys($this->lang[$group]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return current used language
|
||||||
|
*
|
||||||
|
* @return string current language
|
||||||
|
*/
|
||||||
|
function getLang() {
|
||||||
|
return $this->uselang;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* guess langauge of text
|
||||||
|
* @param string $text
|
||||||
|
* @param string $default
|
||||||
|
* @return string detected language
|
||||||
|
*/
|
||||||
|
static function guessLanguage(string $text, string $default, bool $debug = false) {
|
||||||
|
$supported_languages = array(
|
||||||
|
'en',
|
||||||
|
'de',
|
||||||
|
);
|
||||||
|
$wordList = [];
|
||||||
|
// German word list
|
||||||
|
// from http://wortschatz.uni-leipzig.de/Papers/top100de.txt
|
||||||
|
$wordList['de'] = array (
|
||||||
|
'die', 'der', 'und', /*'in',*/ 'zu', 'den', 'das', 'nicht', 'von', 'sie',
|
||||||
|
'ist', 'des', 'sich', 'mit', 'dem', 'dass', 'er', 'es', 'ein', 'ich',
|
||||||
|
'auf', 'so', 'eine', 'auch', 'als', 'an', 'nach', 'wie', 'im', 'für',
|
||||||
|
'man', 'aber', 'aus', 'durch', 'wenn', 'nur', 'war', 'noch', 'werden',
|
||||||
|
'bei', 'hat', 'wir', 'was', 'wird', 'sein', 'einen', 'welche', 'sind',
|
||||||
|
'oder', 'zur', 'um', 'haben', 'einer', 'mir', 'über', 'ihm', 'diese',
|
||||||
|
'einem', 'ihr', 'uns', 'da', 'zum', 'kann', 'doch', 'vor', 'dieser',
|
||||||
|
'mich', 'ihn', 'du', 'hatte', 'seine', 'mehr', 'am', 'denn', 'nun',
|
||||||
|
'unter', 'sehr', 'selbst', 'schon', 'hier', 'bis', 'habe', 'ihre',
|
||||||
|
'dann', 'ihnen', 'seiner', 'alle', 'wieder', 'meine', 'Zeit', 'gegen',
|
||||||
|
'vom', 'ganz', 'einzelnen', 'wo', 'muss', 'ohne', 'eines', 'können',
|
||||||
|
'sei', 'geschrieben', 'instanzen', 'deutsch','aktualisierung', 'registrierung'
|
||||||
|
);
|
||||||
|
|
||||||
|
// English word list
|
||||||
|
// from http://en.wikipedia.org/wiki/Most_common_words_in_English
|
||||||
|
$wordList['en'] = array ('the', 'be', 'to', 'of', 'and', 'a', /*'in',*/
|
||||||
|
'that', 'have', 'I', 'it', 'for', 'not', 'on', 'with', 'he',
|
||||||
|
'as', 'you', 'do', 'at', 'this', 'but', 'his', 'by', 'from', 'they',
|
||||||
|
'we', 'say', 'her', 'she', 'or', 'an', 'will', 'my', 'one', 'all',
|
||||||
|
'would', 'there', 'their', 'what', 'so', 'up', 'out', 'if', 'about'
|
||||||
|
);
|
||||||
|
// French word list
|
||||||
|
// from https://1000mostcommonwords.com/1000-most-common-french-words/
|
||||||
|
/*$wordList['fr'] = array ('comme', 'que', 'tait', 'pour', 'sur', 'sont', 'avec',
|
||||||
|
'tre', 'un', 'ce', 'par', 'mais', 'que', 'est',
|
||||||
|
'il', 'eu', 'la', 'et', 'dans');*/
|
||||||
|
|
||||||
|
// Spanish word list
|
||||||
|
// from https://spanishforyourjob.com/commonwords/
|
||||||
|
/*$wordList['es'] = array ('que', 'no', 'a', 'la', 'el', 'es', 'y',
|
||||||
|
'en', 'lo', 'un', 'por', 'qu', 'si', 'una',
|
||||||
|
'los', 'con', 'para', 'est', 'eso', 'las');*/
|
||||||
|
|
||||||
|
// clean out the input string - note we don't have any non-ASCII
|
||||||
|
// characters in the word lists... change this if it is not the
|
||||||
|
// case in your language wordlists!
|
||||||
|
$txt = strip_tags($text);
|
||||||
|
$txt = preg_replace("/[^A-Za-z:\\/\\.]+/", ' ', $txt);
|
||||||
|
if ($debug) echo "text: '$txt'\n";
|
||||||
|
$counter = [];
|
||||||
|
// count the occurrences of the most frequent words
|
||||||
|
foreach ($supported_languages as $language) {
|
||||||
|
$counter[$language]=0;
|
||||||
|
}
|
||||||
|
foreach ($supported_languages as $language) {
|
||||||
|
for ($i = 0; $i < sizeof($wordList[$language]); ++$i) {
|
||||||
|
$count = substr_count($txt, ' ' .$wordList[$language][$i] . ' ');
|
||||||
|
if ($debug && $count > 0) {
|
||||||
|
echo $language . " " . $wordList[$language][$i] . " => $count\n";
|
||||||
|
}
|
||||||
|
$counter[$language] += $count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($debug)
|
||||||
|
print_r($counter);
|
||||||
|
// get max counter value
|
||||||
|
$max = max($counter);
|
||||||
|
$maxs = array_keys($counter, $max);
|
||||||
|
// if there are two winners - fall back to default!
|
||||||
|
if (count($maxs) == 1) {
|
||||||
|
$winner = $maxs[0];
|
||||||
|
$second = 0;
|
||||||
|
// get runner-up (second place)
|
||||||
|
foreach ($supported_languages as $language) {
|
||||||
|
if ($language !== $winner) {
|
||||||
|
if ($counter[$language]>$second) {
|
||||||
|
$second = $counter[$language];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// apply arbitrary threshold of 50%
|
||||||
|
if (($second / $max) < 0.5) {
|
||||||
|
return $winner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function called from smarty templates to print language translation
|
||||||
|
*
|
||||||
|
* @param array<string,mixed> $params
|
||||||
|
* smarty params, used are 'group', 'txt' and optionally 'var'
|
||||||
|
* @param \Smarty\Template $template
|
||||||
|
* template instance
|
||||||
|
* @return string translated text
|
||||||
|
*/
|
||||||
|
function smarty_function_printlang($params, $template) : string {
|
||||||
|
$lang = $template->getTemplateVars("language");
|
||||||
|
<<<'PHAN'
|
||||||
|
@phan-var \Language $lang
|
||||||
|
PHAN;
|
||||||
|
$forcelang = array_key_exists('lang', $params) ? $params['lang'] : null;
|
||||||
|
if ($forcelang !== null) {
|
||||||
|
$lang = new \Language($forcelang);
|
||||||
|
}
|
||||||
|
if (isset($params['var'])) {
|
||||||
|
return $lang->printlang($params['group'], $params['key'], $params['var']);
|
||||||
|
} else {
|
||||||
|
return $lang->printlang($params['group'], $params['key']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function called from smarty templates to set language translation as JS string
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $params
|
||||||
|
* smarty params, used are 'group', 'txt' and optionally 'var'
|
||||||
|
* @param \Smarty\Template $template
|
||||||
|
* template instance
|
||||||
|
* @return string translated text as JS line
|
||||||
|
*/
|
||||||
|
function smarty_function_printjslang($params, $template) : string {
|
||||||
|
$lang = $template->getTemplateVars("language");
|
||||||
|
$prefix = 'window.translations.' . $params['group'] . '.' . $params['key'] . ' = \'';
|
||||||
|
$postfix = '\';';
|
||||||
|
if (isset($params['var']))
|
||||||
|
return $prefix . $lang->printlang($params['group'], $params['key'], $params['var']) . $postfix;
|
||||||
|
else
|
||||||
|
return $prefix . $lang->printlang($params['group'], $params['key']) . $postfix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* print translation of given group and id, optionally using variables
|
||||||
|
*
|
||||||
|
* @param string $group
|
||||||
|
* group name
|
||||||
|
* @param string $key
|
||||||
|
* string name
|
||||||
|
* @param array<mixed> $values
|
||||||
|
* optional values to replace
|
||||||
|
* @return string translated string
|
||||||
|
*/
|
||||||
|
function printlang(string $group, string $key, array $values=array()) {
|
||||||
|
global $contentnation;
|
||||||
|
return $contentnation->translate(null, $group, $key, $values);
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* @author Author: Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for ContentNation and Api
|
||||||
|
* @author Sascha Nitsch
|
||||||
|
*/
|
||||||
|
class Main
|
||||||
|
{
|
||||||
|
/** @var Cache\Cache cache instance */
|
||||||
|
protected $cache;
|
||||||
|
/** @var array<string,mixed> current config */
|
||||||
|
protected $config;
|
||||||
|
/** @var Connector\Connector remote connector */
|
||||||
|
protected $connector = null;
|
||||||
|
/** @var string response content type */
|
||||||
|
protected $contentType = "text/html";
|
||||||
|
/** @var \Mysqli database instance */
|
||||||
|
protected $dbh;
|
||||||
|
/** @var array<string,string> extra headers */
|
||||||
|
protected $headers = [];
|
||||||
|
/** @var \Language languange instance */
|
||||||
|
protected $lang = null;
|
||||||
|
/** @var ?string redirect URL */
|
||||||
|
protected $redirect = null;
|
||||||
|
/** @var int response code */
|
||||||
|
protected $responseCode = 200;
|
||||||
|
/** @var \Smarty\Smarty|null smarty instance */
|
||||||
|
protected $smarty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->config = parse_ini_file('../config.ini', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do a remote call and return results
|
||||||
|
* @param string $remoteURL remote URL
|
||||||
|
* @param string[]|null $headers optional headers to send
|
||||||
|
* @return array{string, mixed} response and status information
|
||||||
|
*/
|
||||||
|
public static function getFromRemote(string $remoteURL, $headers)
|
||||||
|
{
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $remoteURL);
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
if ($headers !== null) {
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
}
|
||||||
|
curl_setopt($ch, CURLOPT_VERBOSE, true);
|
||||||
|
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
|
||||||
|
$ret = curl_exec($ch);
|
||||||
|
$info = curl_getinfo($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
return [$ret, $info];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get config
|
||||||
|
* @return Array<String, Mixed>
|
||||||
|
*/
|
||||||
|
public function getConfig()
|
||||||
|
{
|
||||||
|
return $this->config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load plugins
|
||||||
|
*/
|
||||||
|
public function loadPlugins() : void
|
||||||
|
{
|
||||||
|
if (array_key_exists('plugins', $this->config)) {
|
||||||
|
$plugins = $this->config['plugins'];
|
||||||
|
foreach ($plugins as $name => $file) {
|
||||||
|
require_once($file);
|
||||||
|
$fktn = 'Federator\\' . $name . '_load';
|
||||||
|
if (function_exists($fktn)) {
|
||||||
|
$fktn($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* open database
|
||||||
|
*/
|
||||||
|
public function openDatabase() : void
|
||||||
|
{
|
||||||
|
$dbconf = $this->config["database"];
|
||||||
|
$this->dbh = new \mysqli($dbconf['host'], $dbconf['username'], $dbconf['password'], $dbconf['database']);
|
||||||
|
if ($this->dbh->connect_error !== null) {
|
||||||
|
http_response_code(500);
|
||||||
|
die('Database Connect Error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set cache
|
||||||
|
*/
|
||||||
|
public function setCache(Cache\Cache $cache) : void
|
||||||
|
{
|
||||||
|
$this->cache = $cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set connector
|
||||||
|
*/
|
||||||
|
public function setConnector(Connector\Connector $connector) : void
|
||||||
|
{
|
||||||
|
$this->connector = $connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set response code
|
||||||
|
*
|
||||||
|
* @param int $code
|
||||||
|
* new response code
|
||||||
|
*/
|
||||||
|
public function setResponseCode(int $code) : void
|
||||||
|
{
|
||||||
|
$this->responseCode = $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* translate given group and key using given language
|
||||||
|
*
|
||||||
|
* @param ?string $lang
|
||||||
|
* language to use
|
||||||
|
* @param string $group
|
||||||
|
* language group to use
|
||||||
|
* @param string $key
|
||||||
|
* language key to use
|
||||||
|
* @param mixed[] $parameters
|
||||||
|
* optional parameters
|
||||||
|
* @return string translation
|
||||||
|
*/
|
||||||
|
public function translate(?string $lang, string $group, string $key, array $parameters = array()) : string
|
||||||
|
{
|
||||||
|
if ($this->lang === null) {
|
||||||
|
$this->validLanguage($lang);
|
||||||
|
}
|
||||||
|
if ($this->lang !== null) {
|
||||||
|
if ($this->lang->getLang() !== $lang) {
|
||||||
|
$l = new \Language($lang);
|
||||||
|
return $l->printlang($group, $key, $parameters);
|
||||||
|
}
|
||||||
|
return $this->lang->printlang($group, $key, $parameters);
|
||||||
|
} else {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if language is valid by loading it
|
||||||
|
*
|
||||||
|
* @param ?string $lang
|
||||||
|
*/
|
||||||
|
public function validLanguage(?string $lang) : bool
|
||||||
|
{
|
||||||
|
$language = new \Language($lang);
|
||||||
|
if ($language->getLang() === $lang) {
|
||||||
|
$this->lang = $language;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
* @author Author: Sascha Nitsch (grumpydeveloper)
|
||||||
|
**/
|
||||||
|
|
||||||
|
namespace Federator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dummy connector that always return the same permission
|
||||||
|
*/
|
||||||
|
class DummyConnector implements Connector\Connector
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get remote user by given session
|
||||||
|
* @param string $_session session id
|
||||||
|
* @param string $_user user or profile name
|
||||||
|
* @return Data\User | false
|
||||||
|
*/
|
||||||
|
public function getRemoteUserBySession(string $_session, string $_user)
|
||||||
|
{
|
||||||
|
// validate $_session and $user
|
||||||
|
$user = new Data\User();
|
||||||
|
$user->id = $_user;
|
||||||
|
$user->permissions = ['PUBLISH'];
|
||||||
|
$user->session = $_session;
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dummy_load(Main $main)
|
||||||
|
{
|
||||||
|
$dummy = new DummyConnector();
|
||||||
|
$main->setConnector($dummy);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
# progress tracker
|
||||||
|
## done
|
||||||
|
|
||||||
|
## goals v1.0
|
||||||
|
primary goal is to connect ContentNation via ActivityPub again.
|
||||||
|
|
||||||
|
- [ ] browse the fediverse as a logged in user
|
||||||
|
- [ ] reply to posts
|
||||||
|
- [ ] like posts
|
||||||
|
- [ ] share posts
|
||||||
|
- [ ] comment on CN article via AP
|
||||||
|
- [ ] get notifications on AP if someone interacts with comment
|
||||||
|
|
||||||
|
## roadmap to v1.0
|
||||||
|
- [X] API framework
|
||||||
|
- [X] interfact to connect to existing service
|
||||||
|
- [ ] overlay to extend with needed info like private keys, urls, ...
|
||||||
|
- [ ] cache layer for users
|
||||||
|
- [ ] webfinger
|
||||||
|
- [ ] discovery endpoints
|
||||||
|
- [ ] ap outbox
|
||||||
|
- [ ] ap inbox
|
||||||
|
- [ ] support for AP profile in service
|
||||||
|
- [ ] support for article
|
||||||
|
- [ ] support for comment
|
||||||
|
- [ ] posting comments from ap to service
|
||||||
|
- [ ] callback from service to add new input
|
|
@ -0,0 +1 @@
|
||||||
|
git log | head -n1 | awk '{print "<?php\nglobal $version;\n$version=\"" $2 "\";\n"}' > php/version.php
|
Loading…
Reference in New Issue