forked from GNUsocial/gnu-social
Compare commits
No commits in common. "v3" and "1.1.x" have entirely different histories.
|
@ -1,3 +0,0 @@
|
|||
((nil . ((php-project-root . auto)
|
||||
(phpstan-executable . (root . "bin/phpstan"))
|
||||
)
|
43
.env
43
.env
|
@ -1,43 +0,0 @@
|
|||
# In all environments, the following files are loaded if they exist,
|
||||
# the latter taking precedence over the former:
|
||||
#
|
||||
# * .env contains default values for the environment variables needed by the app
|
||||
# * .env.local uncommitted file with local overrides
|
||||
# * .env.$APP_ENV committed environment-specific defaults
|
||||
# * .env.$APP_ENV.local uncommitted environment-specific overrides
|
||||
#
|
||||
# Real environment variables win over .env files.
|
||||
#
|
||||
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
|
||||
#
|
||||
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
|
||||
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
|
||||
|
||||
###> symfony/framework-bundle ###
|
||||
APP_ENV=dev
|
||||
APP_SECRET=6a9ac3a09c73230107373e8e0b71e0a3
|
||||
#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||
#TRUSTED_HOSTS='^(localhost|example\.com)$'
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/mailer ###
|
||||
# MAILER_DSN=smtp://localhost
|
||||
###< symfony/mailer ###
|
||||
|
||||
###> doctrine/doctrine-bundle ###
|
||||
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
|
||||
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
|
||||
# For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8"
|
||||
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
|
||||
DATABASE_URL=postgresql://postgres:foobar@postgres:5432/social
|
||||
#?serverVersion=11&charset=utf8
|
||||
###< doctrine/doctrine-bundle ###
|
||||
|
||||
SHELL_VERBOSITY=3
|
||||
###> symfony/messenger ###
|
||||
# Choose one of the transports below
|
||||
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
|
||||
MESSENGER_TRANSPORT_DSN_HIGH=doctrine://default?queue_name=high
|
||||
MESSENGER_TRANSPORT_DSN_LOW=doctrine://default?queue_name=low
|
||||
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
|
||||
###< symfony/messenger ###
|
|
@ -1,6 +0,0 @@
|
|||
# define your env variables for the test env here
|
||||
KERNEL_CLASS='App\Kernel'
|
||||
APP_SECRET='$ecretf0rt3st'
|
||||
SYMFONY_DEPRECATIONS_HELPER=999999
|
||||
PANTHER_APP_ENV=panther
|
||||
DATABASE_URL=postgresql://postgres:password@db:5432/social
|
|
@ -1,64 +1,32 @@
|
|||
|
||||
###> symfony/framework-bundle ###
|
||||
/.env.local
|
||||
/.env.local.php
|
||||
/.env.*.local
|
||||
/config/secrets/prod/prod.decrypt.private.php
|
||||
/public/bundles/
|
||||
/var/
|
||||
/vendor/
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/phpunit-bridge ###
|
||||
.phpunit
|
||||
.phpunit.result.cache
|
||||
/phpunit.xml
|
||||
###< symfony/phpunit-bridge ###
|
||||
|
||||
###> friendsofphp/php-cs-fixer ###
|
||||
!.php-cs-fixer.php
|
||||
/.php_cs.cache
|
||||
/.php-cs-fixer.cache
|
||||
###< friendsofphp/php-cs-fixer ###
|
||||
|
||||
###> phpunit/phpunit ###
|
||||
/phpunit.xml
|
||||
.phpunit.result.cache
|
||||
###< phpunit/phpunit ###
|
||||
|
||||
|
||||
DOCUMENTATION/database/*
|
||||
!DOCUMENTATION/database/database.pdf
|
||||
|
||||
docker/certbot/.files
|
||||
docker/certbot/www
|
||||
docker/*/*.env
|
||||
|
||||
docker/mail/etc/hostname
|
||||
docker/mail/etc/hosts
|
||||
docker/mail/etc/resolv.conf
|
||||
docker/mail/config/aliases.db
|
||||
docker/mail/config/domains.db
|
||||
docker/mail/config/mailboxes.db
|
||||
docker/mail/config/passwd.db
|
||||
docker/mail/etc/service/*
|
||||
!docker/mail/etc/service/*/run
|
||||
|
||||
!docker/testing/*
|
||||
!docker/testing/docker-compose.yaml
|
||||
docker/testing/*~
|
||||
|
||||
docker-compose.yaml
|
||||
composer.local.json
|
||||
|
||||
social.local.yaml
|
||||
|
||||
# V2
|
||||
avatar/*
|
||||
background/*
|
||||
files/*
|
||||
file/*
|
||||
local/*
|
||||
_darcs/*
|
||||
logs/*
|
||||
log/*
|
||||
run/*
|
||||
config.php
|
||||
/file
|
||||
.htaccess
|
||||
httpd.conf
|
||||
*.tmproj
|
||||
dataobject.ini
|
||||
*~
|
||||
*.bak
|
||||
*.orig
|
||||
*.rej
|
||||
.#*
|
||||
*.swp
|
||||
.buildpath
|
||||
.project
|
||||
.settings
|
||||
TODO.rym
|
||||
config-*.php
|
||||
good-config.php
|
||||
lac08.log
|
||||
php.log
|
||||
.DS_Store
|
||||
nbproject
|
||||
*.mo
|
||||
|
||||
notes
|
||||
|
||||
|
||||
.test_coverage_report
|
||||
.phpunit_cache
|
|
@ -1,378 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
/*
|
||||
* This document has been generated with
|
||||
* https://mlocati.github.io/php-cs-fixer-configurator/#version:3.2.1|configurator
|
||||
* you can change this configuration by importing this file.
|
||||
*/
|
||||
$config = new PhpCsFixer\Config();
|
||||
return $config
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
// Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one.
|
||||
'align_multiline_comment' => ['comment_type' => 'phpdocs_like'],
|
||||
// Each element of an array must be indented exactly once.
|
||||
'array_indentation' => true,
|
||||
// Converts simple usages of `array_push($x, $y);` to `$x[] = $y;`.
|
||||
'array_push' => true,
|
||||
// PHP arrays should be declared using the configured syntax.
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
// Use the null coalescing assignment operator `??=` where possible.
|
||||
'assign_null_coalescing_to_coalesce_equal' => true,
|
||||
// Binary operators should be surrounded by space as configured.
|
||||
'binary_operator_spaces' => ['default' => 'align_single_space_minimal', 'operators' => ['??' => 'align']],
|
||||
// There MUST be one blank line after the namespace declaration.
|
||||
'blank_line_after_namespace' => true,
|
||||
// Ensure there is no code on the same line as the PHP open tag and it is followed by a blank line.
|
||||
'blank_line_after_opening_tag' => true,
|
||||
// The body of each structure MUST be enclosed by braces. Braces should be properly placed. Body of braces should be properly indented.
|
||||
'braces' => ['allow_single_line_anonymous_class_with_empty_body' => true, 'allow_single_line_closure' => true, 'position_after_functions_and_oop_constructs' => 'next'],
|
||||
// A single space or none should be between cast and variable.
|
||||
'cast_spaces' => true,
|
||||
// Whitespace around the keywords of a class, trait or interfaces definition should be one space.
|
||||
'class_definition' => ['single_item_single_line' => true, 'single_line' => true],
|
||||
// Using `isset($var) &&` multiple times should be done in one call.
|
||||
'combine_consecutive_issets' => true,
|
||||
// Calling `unset` on multiple items should be done in one call.
|
||||
'combine_consecutive_unsets' => true,
|
||||
// Replace multiple nested calls of `dirname` by only one call with second `$level` parameter. Requires PHP >= 7.0.
|
||||
'combine_nested_dirname' => true,
|
||||
// Comments with annotation should be docblock when used on structural elements.
|
||||
'comment_to_phpdoc' => false,
|
||||
// Remove extra spaces in a nullable typehint.
|
||||
'compact_nullable_typehint' => true,
|
||||
// Concatenation should be spaced according configuration.
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
// The PHP constants `true`, `false`, and `null` MUST be written using the correct casing.
|
||||
'constant_case' => true,
|
||||
// Equal sign in declare statement should be surrounded by spaces or not following configuration.
|
||||
'declare_equal_normalize' => ['space' => 'single'],
|
||||
// There must not be spaces around `declare` statement parentheses.
|
||||
'declare_parentheses' => true,
|
||||
// Force strict types declaration in all files. Requires PHP >= 7.0.
|
||||
'declare_strict_types' => true,
|
||||
// Replaces `dirname(__FILE__)` expression with equivalent `__DIR__` constant.
|
||||
'dir_constant' => true,
|
||||
// Replaces short-echo `<?=` with long format `<?php echo`/`<?php print` syntax, or vice-versa.
|
||||
'echo_tag_syntax' => true,
|
||||
// The keyword `elseif` should be used instead of `else if` so that all control keywords look like single words.
|
||||
'elseif' => true,
|
||||
// Empty loop-body must be in configured style.
|
||||
'empty_loop_body' => true,
|
||||
// Empty loop-condition must be in configured style.
|
||||
'empty_loop_condition' => true,
|
||||
// PHP code MUST use only UTF-8 without BOM (remove BOM).
|
||||
'encoding' => true,
|
||||
// Replace deprecated `ereg` regular expression functions with `preg`.
|
||||
'ereg_to_preg' => true,
|
||||
// Escape implicit backslashes in strings and heredocs to ease the understanding of which are special chars interpreted by PHP and which not.
|
||||
'escape_implicit_backslashes' => true,
|
||||
// Add curly braces to indirect variables to make them clear to understand. Requires PHP >= 7.0.
|
||||
'explicit_indirect_variable' => true,
|
||||
// Converts implicit variables into explicit ones in double-quoted strings or heredoc syntax.
|
||||
'explicit_string_variable' => true,
|
||||
// PHP code must use the long `<?php` tags or short-echo `<?=` tags and not other tag variations.
|
||||
'full_opening_tag' => true,
|
||||
// Transforms imported FQCN parameters and return types in function arguments to short version.
|
||||
'fully_qualified_strict_types' => true,
|
||||
// Spaces should be properly placed in a function declaration.
|
||||
'function_declaration' => ['closure_function_spacing' => 'one'],
|
||||
// Ensure single space between function's argument and its typehint.
|
||||
'function_typehint_space' => true,
|
||||
// Imports or fully qualifies global classes/functions/constants.
|
||||
'global_namespace_import' => true,
|
||||
// Heredoc/nowdoc content must be properly indented. Requires PHP >= 7.3.
|
||||
'heredoc_indentation' => true,
|
||||
// Convert `heredoc` to `nowdoc` where possible.
|
||||
'heredoc_to_nowdoc' => true,
|
||||
// Function `implode` must be called with 2 arguments in the documented order.
|
||||
'implode_call' => true,
|
||||
// Pre- or post-increment and decrement operators should be used if possible.
|
||||
'increment_style' => true,
|
||||
// Code MUST use configured indentation type.
|
||||
'indentation_type' => true,
|
||||
// Lambda must not import variables it doesn't use.
|
||||
'lambda_not_used_import' => true,
|
||||
// All PHP files must use same line ending.
|
||||
'line_ending' => true,
|
||||
// Ensure there is no code on the same line as the PHP open tag.
|
||||
'linebreak_after_opening_tag' => true,
|
||||
// List (`array` destructuring) assignment should be declared using the configured syntax. Requires PHP >= 7.1.
|
||||
'list_syntax' => ['syntax' => 'short'],
|
||||
// Use `&&` and `||` logical operators instead of `and` and `or`.
|
||||
'logical_operators' => true,
|
||||
// Cast should be written in lower case.
|
||||
'lowercase_cast' => true,
|
||||
// PHP keywords MUST be in lower case.
|
||||
'lowercase_keywords' => true,
|
||||
// Class static references `self`, `static` and `parent` MUST be in lower case.
|
||||
'lowercase_static_reference' => true,
|
||||
// Magic constants should be referred to using the correct casing.
|
||||
'magic_constant_casing' => true,
|
||||
// Magic method definitions and calls must be using the correct casing.
|
||||
'magic_method_casing' => true,
|
||||
// Replace non multibyte-safe functions with corresponding mb function.
|
||||
'mb_str_functions' => true,
|
||||
// In method arguments and method call, there MUST NOT be a space before each comma and there MUST be one space after each comma. Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line.
|
||||
'method_argument_space' => ['after_heredoc' => true, 'on_multiline' => 'ensure_fully_multiline'],
|
||||
// Method chaining MUST be properly indented. Method chaining with different levels of indentation is not supported.
|
||||
'method_chaining_indentation' => true,
|
||||
// Replace `strpos()` calls with `str_starts_with()` or `str_contains()` if possible.
|
||||
'modernize_strpos' => true,
|
||||
// Replaces `intval`, `floatval`, `doubleval`, `strval` and `boolval` function calls with according type casting operator.
|
||||
'modernize_types_casting' => true,
|
||||
// DocBlocks must start with two asterisks, multiline comments must start with a single asterisk, after the opening slash. Both must end with a single asterisk before the closing slash.
|
||||
'multiline_comment_opening_closing' => true,
|
||||
// Forbid multi-line whitespace before the closing semicolon or move the semicolon to the new line for chained calls.
|
||||
'multiline_whitespace_before_semicolons' => true,
|
||||
// Add leading `\` before constant invocation of internal constant to speed up resolving. Constant name match is case-sensitive, except for `null`, `false` and `true`.
|
||||
'native_constant_invocation' => true,
|
||||
// Function defined by PHP should be called using the correct casing.
|
||||
'native_function_casing' => true,
|
||||
// Add leading `\` before function invocation to speed up resolving.
|
||||
'native_function_invocation' => true,
|
||||
// Native type hints for functions should use the correct case.
|
||||
'native_function_type_declaration_casing' => true,
|
||||
// Master language constructs shall be used instead of aliases.
|
||||
'no_alias_language_construct_call' => true,
|
||||
// Replace control structure alternative syntax to use braces.
|
||||
'no_alternative_syntax' => true,
|
||||
// There should be no empty lines after class opening brace.
|
||||
'no_blank_lines_after_class_opening' => true,
|
||||
// There should not be blank lines between docblock and the documented element.
|
||||
'no_blank_lines_after_phpdoc' => true,
|
||||
// There must be a comment when fall-through is intentional in a non-empty case body.
|
||||
'no_break_comment' => true,
|
||||
// The closing `? >` tag MUST be omitted from files containing only PHP.
|
||||
'no_closing_tag' => true,
|
||||
// There should not be any empty comments.
|
||||
'no_empty_comment' => true,
|
||||
// There should not be empty PHPDoc blocks.
|
||||
'no_empty_phpdoc' => true,
|
||||
// Remove useless (semicolon) statements.
|
||||
'no_empty_statement' => true,
|
||||
// Removes extra blank lines and/or blank lines following configuration.
|
||||
'no_extra_blank_lines' => true,
|
||||
// Remove leading slashes in `use` clauses.
|
||||
'no_leading_import_slash' => true,
|
||||
// The namespace declaration line shouldn't contain leading whitespace.
|
||||
'no_leading_namespace_whitespace' => true,
|
||||
// Either language construct `print` or `echo` should be used.
|
||||
'no_mixed_echo_print' => true,
|
||||
// Operator `=>` should not be surrounded by multi-line whitespaces.
|
||||
'no_multiline_whitespace_around_double_arrow' => true,
|
||||
// Properties MUST not be explicitly initialized with `null` except when they have a type declaration (PHP 7.4).
|
||||
'no_null_property_initialization' => true,
|
||||
// Short cast `bool` using double exclamation mark should not be used.
|
||||
'no_short_bool_cast' => true,
|
||||
// Single-line whitespace before closing semicolon are prohibited.
|
||||
'no_singleline_whitespace_before_semicolons' => true,
|
||||
// There must be no space around double colons (also called Scope Resolution Operator or Paamayim Nekudotayim).
|
||||
'no_space_around_double_colon' => true,
|
||||
// When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis.
|
||||
'no_spaces_after_function_name' => true,
|
||||
// There MUST NOT be spaces around offset braces.
|
||||
'no_spaces_around_offset' => true,
|
||||
// There MUST NOT be a space after the opening parenthesis. There MUST NOT be a space before the closing parenthesis.
|
||||
'no_spaces_inside_parenthesis' => true,
|
||||
// Removes `@param`, `@return` and `@var` tags that don't provide any useful information.
|
||||
'no_superfluous_phpdoc_tags' => true,
|
||||
// Remove trailing commas in list function calls.
|
||||
'no_trailing_comma_in_list_call' => true,
|
||||
// PHP single-line arrays should not have trailing comma.
|
||||
'no_trailing_comma_in_singleline_array' => true,
|
||||
// Remove trailing whitespace at the end of non-blank lines.
|
||||
'no_trailing_whitespace' => true,
|
||||
// There MUST be no trailing spaces inside comment or PHPDoc.
|
||||
'no_trailing_whitespace_in_comment' => true,
|
||||
// Removes unneeded parentheses around control statements.
|
||||
'no_unneeded_control_parentheses' => true,
|
||||
// Removes unneeded curly braces that are superfluous and aren't part of a control structure's body.
|
||||
'no_unneeded_curly_braces' => true,
|
||||
// In function arguments there must not be arguments with default values before non-default ones.
|
||||
'no_unreachable_default_argument_value' => true,
|
||||
// Variables must be set `null` instead of using `(unset)` casting.
|
||||
'no_unset_cast' => true,
|
||||
// Unused `use` statements must be removed.
|
||||
'no_unused_imports' => true,
|
||||
// There should not be an empty `return` statement at the end of a function.
|
||||
'no_useless_return' => true,
|
||||
// In array declaration, there MUST NOT be a whitespace before each comma.
|
||||
'no_whitespace_before_comma_in_array' => true,
|
||||
// Remove trailing whitespace at the end of blank lines.
|
||||
'no_whitespace_in_blank_line' => true,
|
||||
// Remove Zero-width space (ZWSP), Non-breaking space (NBSP) and other invisible unicode symbols.
|
||||
'non_printable_character' => true,
|
||||
// Array index should always be written by using square braces.
|
||||
'normalize_index_brace' => true,
|
||||
// Adds or removes `?` before type declarations for parameters with a default `null` value.
|
||||
'nullable_type_declaration_for_default_null_value' => true,
|
||||
// There should not be space before or after object operators `->` and `?->`.
|
||||
'object_operator_without_whitespace' => true,
|
||||
// Operators - when multiline - must always be at the beginning or at the end of the line.
|
||||
'operator_linebreak' => true,
|
||||
// Ordering `use` statements.
|
||||
'ordered_imports' => true,
|
||||
// PHPUnit assertion method calls like `->assertSame(true, $foo)` should be written with dedicated method like `->assertTrue($foo)`.
|
||||
'php_unit_construct' => true,
|
||||
// PHPUnit assertions like `assertInternalType`, `assertFileExists`, should be used over `assertTrue`.
|
||||
'php_unit_dedicate_assert' => true,
|
||||
// PHPUnit assertions like `assertIsArray` should be used over `assertInternalType`.
|
||||
'php_unit_dedicate_assert_internal_type' => true,
|
||||
// Usages of `->setExpectedException*` methods MUST be replaced by `->expectException*` methods.
|
||||
'php_unit_expectation' => true,
|
||||
// PHPUnit annotations should be a FQCNs including a root namespace.
|
||||
'php_unit_fqcn_annotation' => true,
|
||||
// Enforce camel (or snake) case for PHPUnit test methods, following configuration.
|
||||
'php_unit_method_casing' => true,
|
||||
// Usage of PHPUnit's mock e.g. `->will($this->returnValue(..))` must be replaced by its shorter equivalent such as `->willReturn(...)`.
|
||||
'php_unit_mock_short_will_return' => true,
|
||||
// PHPUnit classes MUST be used in namespaced version, e.g. `\PHPUnit\Framework\TestCase` instead of `\PHPUnit_Framework_TestCase`.
|
||||
'php_unit_namespaced' => true,
|
||||
// Usages of `@expectedException*` annotations MUST be replaced by `->setExpectedException*` methods.
|
||||
'php_unit_no_expectation_annotation' => true,
|
||||
// Changes the visibility of the `setUp()` and `tearDown()` functions of PHPUnit to `protected`, to match the PHPUnit TestCase.
|
||||
'php_unit_set_up_tear_down_visibility' => true,
|
||||
// PHPUnit methods like `assertSame` should be used instead of `assertEquals`.
|
||||
'php_unit_strict' => true,
|
||||
// Calls to `PHPUnit\Framework\TestCase` static methods must all be of the same type, either `$this->`, `self::` or `static::`.
|
||||
'php_unit_test_case_static_method_calls' => true,
|
||||
// PHPDoc should contain `@param` for all params.
|
||||
'phpdoc_add_missing_param_annotation' => true,
|
||||
// All items of the given phpdoc tags must be either left-aligned or (by default) aligned vertically.
|
||||
'phpdoc_align' => true,
|
||||
// PHPDoc annotation descriptions should not be a sentence.
|
||||
'phpdoc_annotation_without_dot' => true,
|
||||
// Docblocks should have the same indentation as the documented subject.
|
||||
'phpdoc_indent' => true,
|
||||
// Fixes PHPDoc inline tags.
|
||||
'phpdoc_inline_tag_normalizer' => true,
|
||||
// Changes doc blocks from single to multi line, or reversed. Works for class constants, properties and methods only.
|
||||
'phpdoc_line_span' => true,
|
||||
// `@access` annotations should be omitted from PHPDoc.
|
||||
'phpdoc_no_access' => true,
|
||||
// No alias PHPDoc tags should be used.
|
||||
'phpdoc_no_alias_tag' => true,
|
||||
// `@return void` and `@return null` annotations should be omitted from PHPDoc.
|
||||
'phpdoc_no_empty_return' => true,
|
||||
// Classy that does not inherit must not have `@inheritdoc` tags.
|
||||
'phpdoc_no_useless_inheritdoc' => true,
|
||||
// Annotations in PHPDoc should be ordered so that `@param` annotations come first, then `@throws` annotations, then `@return` annotations.
|
||||
'phpdoc_order' => true,
|
||||
// Order phpdoc tags by value.
|
||||
'phpdoc_order_by_value' => ['annotations' => ['covers', 'throws']],
|
||||
// The type of `@return` annotations of methods returning a reference to itself must the configured one.
|
||||
'phpdoc_return_self_reference' => true,
|
||||
// Scalar types should always be written in the same form. `int` not `integer`, `bool` not `boolean`, `float` not `real` or `double`.
|
||||
'phpdoc_scalar' => true,
|
||||
// Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other, and annotations of a different type are separated by a single blank line.
|
||||
'phpdoc_separation' => true,
|
||||
// Single line `@var` PHPDoc should have proper spacing.
|
||||
'phpdoc_single_line_var_spacing' => true,
|
||||
// Fixes casing of PHPDoc tags.
|
||||
'phpdoc_tag_casing' => true,
|
||||
// Would be neat, but breaks cases where the parents don't have annotations
|
||||
// // EXPERIMENTAL: Takes `@param` annotations of non-mixed types and adjusts accordingly the function signature. Requires PHP >= 7.0.
|
||||
// 'phpdoc_to_param_type' => true,
|
||||
// // EXPERIMENTAL: Takes `@var` annotation of non-mixed types and adjusts accordingly the property signature. Requires PHP >= 7.4.
|
||||
// 'phpdoc_to_property_type' => true,
|
||||
// // EXPERIMENTAL: Takes `@return` annotation of non-mixed types and adjusts accordingly the function signature. Requires PHP >= 7.0.
|
||||
// 'phpdoc_to_return_type' => true,
|
||||
// PHPDoc should start and end with content, excluding the very first and last line of the docblocks.
|
||||
'phpdoc_trim' => true,
|
||||
// Removes extra blank lines after summary and after description in PHPDoc.
|
||||
'phpdoc_trim_consecutive_blank_line_separation' => true,
|
||||
// The correct case must be used for standard PHP types in PHPDoc.
|
||||
'phpdoc_types' => true,
|
||||
// Sorts PHPDoc types.
|
||||
'phpdoc_types_order' => true,
|
||||
// `@var` and `@type` annotations must have type and name in the correct order.
|
||||
'phpdoc_var_annotation_correct_order' => true,
|
||||
// Converts `pow` to the `**` operator.
|
||||
'pow_to_exponentiation' => true,
|
||||
// Replaces `rand`, `srand`, `getrandmax` functions calls with their `mt_*` analogs or `random_int`.
|
||||
'random_api_migration' => true,
|
||||
// Callables must be called without using `call_user_func*` when possible.
|
||||
'regular_callable_call' => true,
|
||||
// Local, dynamic and directly referenced variables should not be assigned and directly returned by a function or method.
|
||||
'return_assignment' => true,
|
||||
// There should be one or no space before colon, and one space after it in return type declarations, according to configuration.
|
||||
'return_type_declaration' => true,
|
||||
// Inside class or interface element `self` should be preferred to the class name itself.
|
||||
'self_accessor' => true,
|
||||
// Instructions must be terminated with a semicolon.
|
||||
'semicolon_after_instruction' => true,
|
||||
// Cast shall be used, not `settype`.
|
||||
'set_type_to_cast' => true,
|
||||
// Cast `(boolean)` and `(integer)` should be written as `(bool)` and `(int)`, `(double)` and `(real)` as `(float)`, `(binary)` as `(string)`.
|
||||
'short_scalar_cast' => true,
|
||||
// Converts explicit variables in double-quoted strings and heredoc syntax from simple to complex format (`${` to `{$`).
|
||||
'simple_to_complex_string_variable' => true,
|
||||
// Simplify `if` control structures that return the boolean result of their condition.
|
||||
'simplified_if_return' => true,
|
||||
// A return statement wishing to return `void` should not return `null`.
|
||||
'simplified_null_return' => true,
|
||||
// A PHP file without end tag must always end with a single empty line feed.
|
||||
'single_blank_line_at_eof' => true,
|
||||
// There should be exactly one blank line before a namespace declaration.
|
||||
'single_blank_line_before_namespace' => true,
|
||||
// There MUST NOT be more than one property or constant declared per statement.
|
||||
'single_class_element_per_statement' => true,
|
||||
// There MUST be one use keyword per declaration.
|
||||
'single_import_per_statement' => true,
|
||||
// Each namespace use MUST go on its own line and there MUST be one blank line after the use statements block.
|
||||
'single_line_after_imports' => true,
|
||||
// Single-line comments and multi-line comments with only one line of actual content should use the `//` syntax.
|
||||
'single_line_comment_style' => true,
|
||||
// Convert double quotes to single quotes for simple strings.
|
||||
'single_quote' => true,
|
||||
// Ensures a single space after language constructs.
|
||||
'single_space_after_construct' => true,
|
||||
// Each trait `use` must be done as single statement.
|
||||
'single_trait_insert_per_statement' => true,
|
||||
// Fix whitespace after a semicolon.
|
||||
'space_after_semicolon' => true,
|
||||
// Increment and decrement operators should be used if possible.
|
||||
'standardize_increment' => true,
|
||||
// Replace all `<>` with `!=`.
|
||||
'standardize_not_equals' => true,
|
||||
// String tests for empty must be done against `''`, not with `strlen`.
|
||||
'string_length_to_empty' => true,
|
||||
// A case should be followed by a colon and not a semicolon.
|
||||
'switch_case_semicolon_to_colon' => true,
|
||||
// Removes extra spaces between colon and case value.
|
||||
'switch_case_space' => true,
|
||||
// Switch case must not be ended with `continue` but with `break`.
|
||||
'switch_continue_to_break' => true,
|
||||
// Standardize spaces around ternary operator.
|
||||
'ternary_operator_spaces' => true,
|
||||
// Use the Elvis operator `?:` where possible.
|
||||
'ternary_to_elvis_operator' => true,
|
||||
// Use `null` coalescing operator `??` where possible. Requires PHP >= 7.0.
|
||||
'ternary_to_null_coalescing' => true,
|
||||
// Multi-line arrays, arguments list and parameters list must have a trailing comma.
|
||||
'trailing_comma_in_multiline' => ['after_heredoc' => true, 'elements' => ['arguments', 'arrays', 'parameters']],
|
||||
// Arrays should be formatted like function/method arguments, without leading or trailing single line space.
|
||||
'trim_array_spaces' => true,
|
||||
// A single space or none should be around union type operator.
|
||||
'types_spaces' => true,
|
||||
// Unary operators should be placed adjacent to their operands.
|
||||
'unary_operator_spaces' => true,
|
||||
// Anonymous functions with one-liner return statement must use arrow functions.
|
||||
'use_arrow_functions' => true,
|
||||
// Visibility MUST be declared on all properties and methods; `abstract` and `final` MUST be declared before the visibility; `static` MUST be declared after the visibility.
|
||||
'visibility_required' => true,
|
||||
// In array declaration, there MUST be a whitespace after each comma.
|
||||
'whitespace_after_comma_in_array' => true,
|
||||
])
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->exclude('var')
|
||||
->exclude('docker')
|
||||
->exclude('src/Entity')
|
||||
->notPath('src/Core/DB/DefaultSettings.php')
|
||||
->in(__DIR__),
|
||||
);
|
|
@ -0,0 +1,806 @@
|
|||
Configuration options
|
||||
=====================
|
||||
|
||||
The main configuration file for StatusNet (excepting configurations for
|
||||
dependency software) is config.php in your StatusNet directory. If you
|
||||
edit any other file in the directory, like lib/default.php (where most
|
||||
of the defaults are defined), you will lose your configuration options
|
||||
in any upgrade, and you will wish that you had been more careful.
|
||||
|
||||
Starting with version 0.9.0, a Web based configuration panel has been
|
||||
added to StatusNet. The preferred method for changing config options is
|
||||
to use this panel.
|
||||
|
||||
A command-line script, setconfig.php, can be used to set individual
|
||||
configuration options. It's in the scripts/ directory.
|
||||
|
||||
Starting with version 0.7.1, you can put config files in the
|
||||
/etc/statusnet/ directory on your server, if it exists. Config files
|
||||
will be included in this order:
|
||||
|
||||
* /etc/statusnet/statusnet.php - server-wide config
|
||||
* /etc/statusnet/<servername>.php - for a virtual host
|
||||
* /etc/statusnet/<servername>_<pathname>.php - for a path
|
||||
* INSTALLDIR/config.php - for a particular implementation
|
||||
|
||||
Almost all configuration options are made through a two-dimensional
|
||||
associative array, cleverly named $config. A typical configuration
|
||||
line will be:
|
||||
|
||||
$config['section']['option'] = value;
|
||||
|
||||
For brevity, the following documentation describes each section and
|
||||
option.
|
||||
|
||||
site
|
||||
----
|
||||
|
||||
This section is a catch-all for site-wide variables.
|
||||
|
||||
name: the name of your site, like 'YourCompany Microblog'.
|
||||
server: the server part of your site's URLs, like 'example.net'.
|
||||
path: The path part of your site's URLs, like 'statusnet' or ''
|
||||
(installed in root).
|
||||
fancy: whether or not your site uses fancy URLs (see Fancy URLs
|
||||
section above). Default is false.
|
||||
logfile: full path to a file for StatusNet to save logging
|
||||
information to. You may want to use this if you don't have
|
||||
access to syslog.
|
||||
logdebug: whether to log additional debug info like backtraces on
|
||||
hard errors. Default false.
|
||||
locale_path: full path to the directory for locale data. Unless you
|
||||
store all your locale data in one place, you probably
|
||||
don't need to use this.
|
||||
language: default language for your site. Defaults to US English.
|
||||
Note that this is overridden if a user is logged in and has
|
||||
selected a different language. It is also overridden if the
|
||||
user is NOT logged in, but their browser requests a different
|
||||
langauge. Since pretty much everybody's browser requests a
|
||||
language, that means that changing this setting has little or
|
||||
no effect in practice.
|
||||
languages: A list of languages supported on your site. Typically you'd
|
||||
only change this if you wanted to disable support for one
|
||||
or another language:
|
||||
"unset($config['site']['languages']['de'])" will disable
|
||||
support for German.
|
||||
theme: Theme for your site (see Theme section). Two themes are
|
||||
provided by default: 'default' and 'stoica' (the one used by
|
||||
Identi.ca). It's appreciated if you don't use the 'stoica' theme
|
||||
except as the basis for your own.
|
||||
email: contact email address for your site. By default, it's extracted
|
||||
from your Web server environment; you may want to customize it.
|
||||
broughtbyurl: name of an organization or individual who provides the
|
||||
service. Each page will include a link to this name in the
|
||||
footer. A good way to link to the blog, forum, wiki,
|
||||
corporate portal, or whoever is making the service available.
|
||||
broughtby: text used for the "brought by" link.
|
||||
timezone: default timezone for message display. Users can set their
|
||||
own time zone. Defaults to 'UTC', which is a pretty good default.
|
||||
closed: If set to 'true', will disallow registration on your site.
|
||||
This is a cheap way to restrict accounts to only one
|
||||
individual or group; just register the accounts you want on
|
||||
the service, *then* set this variable to 'true'.
|
||||
inviteonly: If set to 'true', will only allow registration if the user
|
||||
was invited by an existing user.
|
||||
private: If set to 'true', anonymous users will be redirected to the
|
||||
'login' page. Also, API methods that normally require no
|
||||
authentication will require it. Note that this does not turn
|
||||
off registration; use 'closed' or 'inviteonly' for the
|
||||
behaviour you want.
|
||||
notice: A plain string that will appear on every page. A good place
|
||||
to put introductory information about your service, or info about
|
||||
upgrades and outages, or other community info. Any HTML will
|
||||
be escaped.
|
||||
logo: URL of an image file to use as the logo for the site. Overrides
|
||||
the logo in the theme, if any.
|
||||
ssllogo: URL of an image file to use as the logo on SSL pages. If unset,
|
||||
theme logo is used instead.
|
||||
ssl: Whether to use SSL and https:// URLs for some or all pages.
|
||||
Possible values are 'always' (use it for all pages), 'never'
|
||||
(don't use it for any pages), or 'sometimes' (use it for
|
||||
sensitive pages that include passwords like login and registration,
|
||||
but not for regular pages). Default to 'never'.
|
||||
sslserver: use an alternate server name for SSL URLs, like
|
||||
'secure.example.org'. You should be careful to set cookie
|
||||
parameters correctly so that both the SSL server and the
|
||||
"normal" server can access the session cookie and
|
||||
preferably other cookies as well.
|
||||
shorturllength: ignored. See 'url' section below.
|
||||
dupelimit: minimum time allowed for one person to say the same thing
|
||||
twice. Default 60s. Anything lower is considered a user
|
||||
or UI error.
|
||||
textlimit: default max size for texts in the site. Defaults to 0 (no limit).
|
||||
Can be fine-tuned for notices, messages, profile bios and group descriptions.
|
||||
|
||||
db
|
||||
--
|
||||
|
||||
This section is a reference to the configuration options for
|
||||
DB_DataObject (see <http://ur1.ca/7xp>). The ones that you may want to
|
||||
set are listed below for clarity.
|
||||
|
||||
database: a DSN (Data Source Name) for your StatusNet database. This is
|
||||
in the format 'protocol://username:password@hostname/databasename',
|
||||
where 'protocol' is 'mysql' or 'mysqli' (or possibly 'postgresql', if you
|
||||
really know what you're doing), 'username' is the username,
|
||||
'password' is the password, and etc.
|
||||
ini_yourdbname: if your database is not named 'statusnet', you'll need
|
||||
to set this to point to the location of the
|
||||
statusnet.ini file. Note that the real name of your database
|
||||
should go in there, not literally 'yourdbname'.
|
||||
db_driver: You can try changing this to 'MDB2' to use the other driver
|
||||
type for DB_DataObject, but note that it breaks the OpenID
|
||||
libraries, which only support PEAR::DB.
|
||||
debug: On a database error, you may get a message saying to set this
|
||||
value to 5 to see debug messages in the browser. This breaks
|
||||
just about all pages, and will also expose the username and
|
||||
password
|
||||
quote_identifiers: Set this to true if you're using postgresql.
|
||||
type: either 'mysql' or 'postgresql' (used for some bits of
|
||||
database-type-specific SQL in the code). Defaults to mysql.
|
||||
mirror: you can set this to an array of DSNs, like the above
|
||||
'database' value. If it's set, certain read-only actions will
|
||||
use a random value out of this array for the database, rather
|
||||
than the one in 'database' (actually, 'database' is overwritten).
|
||||
You can offload a busy DB server by setting up MySQL replication
|
||||
and adding the slaves to this array. Note that if you want some
|
||||
requests to go to the 'database' (master) server, you'll need
|
||||
to include it in this array, too.
|
||||
utf8: whether to talk to the database in UTF-8 mode. This is the default
|
||||
with new installations, but older sites may want to turn it off
|
||||
until they get their databases fixed up. See "UTF-8 database"
|
||||
above for details.
|
||||
schemacheck: when to let plugins check the database schema to add
|
||||
tables or update them. Values can be 'runtime' (default)
|
||||
or 'script'. 'runtime' can be costly (plugins check the
|
||||
schema on every hit, adding potentially several db
|
||||
queries, some quite long), but not everyone knows how to
|
||||
run a script. If you can, set this to 'script' and run
|
||||
scripts/checkschema.php whenever you install or upgrade a
|
||||
plugin.
|
||||
|
||||
syslog
|
||||
------
|
||||
|
||||
By default, StatusNet sites log error messages to the syslog facility.
|
||||
(You can override this using the 'logfile' parameter described above).
|
||||
|
||||
appname: The name that StatusNet uses to log messages. By default it's
|
||||
"statusnet", but if you have more than one installation on the
|
||||
server, you may want to change the name for each instance so
|
||||
you can track log messages more easily.
|
||||
priority: level to log at. Currently ignored.
|
||||
facility: what syslog facility to used. Defaults to LOG_USER, only
|
||||
reset if you know what syslog is and have a good reason
|
||||
to change it.
|
||||
|
||||
queue
|
||||
-----
|
||||
|
||||
You can configure the software to queue time-consuming tasks, like
|
||||
sending out SMS email or XMPP messages, for off-line processing. See
|
||||
'Queues and daemons' above for how to set this up.
|
||||
|
||||
enabled: Whether to uses queues. Defaults to false.
|
||||
daemon: Wather to use queuedaemon. Defaults to false, which means
|
||||
you'll use OpportunisticQM plugin.
|
||||
subsystem: Which kind of queueserver to use. Values include "db" for
|
||||
our hacked-together database queuing (no other server
|
||||
required) and "stomp" for a stomp server.
|
||||
stomp_server: "broker URI" for stomp server. Something like
|
||||
"tcp://hostname:61613". More complicated ones are
|
||||
possible; see your stomp server's documentation for
|
||||
details.
|
||||
queue_basename: a root name to use for queues (stomp only). Typically
|
||||
something like '/queue/sitename/' makes sense. If running
|
||||
multiple instances on the same server, make sure that
|
||||
either this setting or $config['site']['nickname'] are
|
||||
unique for each site to keep them separate.
|
||||
|
||||
stomp_username: username for connecting to the stomp server; defaults
|
||||
to null.
|
||||
stomp_password: password for connecting to the stomp server; defaults
|
||||
to null.
|
||||
|
||||
stomp_persistent: keep items across queue server restart, if enabled.
|
||||
Under ActiveMQ, the server configuration determines if and how
|
||||
persistent storage is actually saved.
|
||||
|
||||
If using a message queue server other than ActiveMQ, you may
|
||||
need to disable this if it does not support persistence.
|
||||
|
||||
stomp_transactions: use transactions to aid in error detection.
|
||||
A broken transaction will be seen quickly, allowing a message
|
||||
to be redelivered immediately if a daemon crashes.
|
||||
|
||||
If using a message queue server other than ActiveMQ, you may
|
||||
need to disable this if it does not support transactions.
|
||||
|
||||
stomp_acks: send acknowledgements to aid in flow control.
|
||||
An acknowledgement of successful processing tells the server
|
||||
we're ready for more and can help keep things moving smoothly.
|
||||
|
||||
This should *not* be turned off when running with ActiveMQ, but
|
||||
if using another message queue server that does not support
|
||||
acknowledgements you might need to disable this.
|
||||
|
||||
softlimit: an absolute or relative "soft memory limit"; daemons will
|
||||
restart themselves gracefully when they find they've hit
|
||||
this amount of memory usage. Defaults to 90% of PHP's global
|
||||
memory_limit setting.
|
||||
|
||||
inboxes: delivery of messages to receiver's inboxes can be delayed to
|
||||
queue time for best interactive performance on the sender.
|
||||
This may however be annoyingly slow when using the DB queues,
|
||||
so you can set this to false if it's causing trouble.
|
||||
|
||||
breakout: for stomp, individual queues are by default grouped up for
|
||||
best scalability. If some need to be run by separate daemons,
|
||||
etc they can be manually adjusted here.
|
||||
|
||||
Default will share all queues for all sites within each group.
|
||||
Specify as <group>/<queue> or <group>/<queue>/<site>,
|
||||
using nickname identifier as site.
|
||||
|
||||
'main/distrib' separate "distrib" queue covering all sites
|
||||
'xmpp/xmppout/mysite' separate "xmppout" queue covering just 'mysite'
|
||||
|
||||
max_retries: for stomp, drop messages after N failed attempts to process.
|
||||
Defaults to 10.
|
||||
|
||||
dead_letter_dir: for stomp, optional directory to dump data on failed
|
||||
queue processing events after discarding them.
|
||||
|
||||
stomp_no_transactions: for stomp, the server does not support transactions,
|
||||
so do not try to user them. This is needed for http://www.morbidq.com/.
|
||||
|
||||
stomp_no_acks: for stomp, the server does not support acknowledgements.
|
||||
so do not try to user them. This is needed for http://www.morbidq.com/.
|
||||
|
||||
license
|
||||
-------
|
||||
|
||||
The default license to use for your users notices. The default is the
|
||||
Creative Commons Attribution 3.0 license, which is probably the right
|
||||
choice for any public site. Note that some other servers will not
|
||||
accept notices if you apply a stricter license than this.
|
||||
|
||||
type: one of 'cc' (for Creative Commons licenses), 'allrightsreserved'
|
||||
(default copyright), or 'private' (for private and confidential
|
||||
information).
|
||||
owner: for 'allrightsreserved' or 'private', an assigned copyright
|
||||
holder (for example, an employer for a private site). If
|
||||
not specified, will be attributed to 'contributors'.
|
||||
url: URL of the license, used for links.
|
||||
title: Title for the license, like 'Creative Commons Attribution 3.0'.
|
||||
image: A button shown on each page for the license.
|
||||
|
||||
mail
|
||||
----
|
||||
|
||||
This is for configuring out-going email. We use PEAR's Mail module,
|
||||
see: http://pear.php.net/manual/en/package.mail.mail.factory.php
|
||||
|
||||
backend: the backend to use for mail, one of 'mail', 'sendmail', and
|
||||
'smtp'. Defaults to PEAR's default, 'mail'.
|
||||
params: if the mail backend requires any parameters, you can provide
|
||||
them in an associative array.
|
||||
|
||||
nickname
|
||||
--------
|
||||
|
||||
This is for configuring nicknames in the service.
|
||||
|
||||
blacklist: an array of strings for usernames that may not be
|
||||
registered. A default array exists for strings that are
|
||||
used by StatusNet (e.g. 'doc', 'main', 'avatar', 'theme')
|
||||
but you may want to add others if you have other software
|
||||
installed in a subdirectory of StatusNet or if you just
|
||||
don't want certain words used as usernames.
|
||||
featured: an array of nicknames of 'featured' users of the site.
|
||||
Can be useful to draw attention to well-known users, or
|
||||
interesting people, or whatever.
|
||||
|
||||
avatar
|
||||
------
|
||||
|
||||
For configuring avatar access.
|
||||
|
||||
dir: Directory to look for avatar files and to put them into.
|
||||
Defaults to avatar subdirectory of install directory; if
|
||||
you change it, make sure to change path, too.
|
||||
path: Path to avatars. Defaults to path for avatar subdirectory,
|
||||
but you can change it if you wish. Note that this will
|
||||
be included with the avatar server, too.
|
||||
server: If set, defines another server where avatars are stored in the
|
||||
root directory. Note that the 'avatar' subdir still has to be
|
||||
writeable. You'd typically use this to split HTTP requests on
|
||||
the client to speed up page loading, either with another
|
||||
virtual server or with an NFS or SAMBA share. Clients
|
||||
typically only make 2 connections to a single server at a
|
||||
time <http://ur1.ca/6ih>, so this can parallelize the job.
|
||||
Defaults to null.
|
||||
ssl: Whether to access avatars using HTTPS. Defaults to null, meaning
|
||||
to guess based on site-wide SSL settings.
|
||||
|
||||
public
|
||||
------
|
||||
|
||||
For configuring the public stream.
|
||||
|
||||
localonly: If set to true, only messages posted by users of this
|
||||
service (rather than other services, filtered through OStatus)
|
||||
are shown in the public stream. Default true.
|
||||
blacklist: An array of IDs of users to hide from the public stream.
|
||||
Useful if you have someone making excessive Twitterfeed posts
|
||||
to the site, other kinds of automated posts, testing bots, etc.
|
||||
autosource: Sources of notices that are from automatic posters, and thus
|
||||
should be kept off the public timeline. Default empty.
|
||||
|
||||
theme
|
||||
-----
|
||||
|
||||
server: Like avatars, you can speed up page loading by pointing the
|
||||
theme file lookup to another server (virtual or real).
|
||||
Defaults to NULL, meaning to use the site server.
|
||||
dir: Directory where theme files are stored. Used to determine
|
||||
whether to show parts of a theme file. Defaults to the theme
|
||||
subdirectory of the install directory.
|
||||
path: Path part of theme URLs, before the theme name. Relative to the
|
||||
theme server. It may make sense to change this path when upgrading,
|
||||
(using version numbers as the path) to make sure that all files are
|
||||
reloaded by caching clients or proxies. Defaults to null,
|
||||
which means to use the site path + '/theme'.
|
||||
ssl: Whether to use SSL for theme elements. Default is null, which means
|
||||
guess based on site SSL settings.
|
||||
sslserver: SSL server to use when page is HTTPS-encrypted. If
|
||||
unspecified, site ssl server and so on will be used.
|
||||
sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
|
||||
|
||||
javascript
|
||||
----------
|
||||
|
||||
server: You can speed up page loading by pointing the
|
||||
theme file lookup to another server (virtual or real).
|
||||
Defaults to NULL, meaning to use the site server.
|
||||
path: Path part of Javascript URLs. Defaults to null,
|
||||
which means to use the site path + '/js/'.
|
||||
ssl: Whether to use SSL for JavaScript files. Default is null, which means
|
||||
guess based on site SSL settings.
|
||||
sslserver: SSL server to use when page is HTTPS-encrypted. If
|
||||
unspecified, site ssl server and so on will be used.
|
||||
sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
|
||||
bustframes: If true, all web pages will break out of framesets. If false,
|
||||
can comfortably live in a frame or iframe... probably. Default
|
||||
to true.
|
||||
|
||||
xmpp
|
||||
----
|
||||
|
||||
For configuring the XMPP sub-system.
|
||||
|
||||
enabled: Whether to accept and send messages by XMPP. Default false.
|
||||
server: server part of XMPP ID for update user.
|
||||
port: connection port for clients. Default 5222, which you probably
|
||||
shouldn't need to change.
|
||||
user: username for the client connection. Users will receive messages
|
||||
from 'user'@'server'.
|
||||
resource: a unique identifier for the connection to the server. This
|
||||
is actually used as a prefix for each XMPP component in the system.
|
||||
password: password for the user account.
|
||||
host: some XMPP domains are served by machines with a different
|
||||
hostname. (For example, @gmail.com GTalk users connect to
|
||||
talk.google.com). Set this to the correct hostname if that's the
|
||||
case with your server.
|
||||
encryption: Whether to encrypt the connection between StatusNet and the
|
||||
XMPP server. Defaults to true, but you can get
|
||||
considerably better performance turning it off if you're
|
||||
connecting to a server on the same machine or on a
|
||||
protected network.
|
||||
debug: if turned on, this will make the XMPP library blurt out all of
|
||||
the incoming and outgoing messages as XML stanzas. Use as a
|
||||
last resort, and never turn it on if you don't have queues
|
||||
enabled, since it will spit out sensitive data to the browser.
|
||||
public: an array of JIDs to send _all_ notices to. This is useful for
|
||||
participating in third-party search and archiving services.
|
||||
|
||||
invite
|
||||
------
|
||||
|
||||
For configuring invites.
|
||||
|
||||
enabled: Whether to allow users to send invites. Default true.
|
||||
|
||||
tag
|
||||
---
|
||||
|
||||
Miscellaneous tagging stuff.
|
||||
|
||||
dropoff: Decay factor for tag listing, in seconds.
|
||||
Defaults to exponential decay over ten days; you can twiddle
|
||||
with it to try and get better results for your site.
|
||||
|
||||
popular
|
||||
-------
|
||||
|
||||
Settings for the "popular" section of the site.
|
||||
|
||||
dropoff: Decay factor for popularity listing, in seconds.
|
||||
Defaults to exponential decay over ten days; you can twiddle
|
||||
with it to try and get better results for your site.
|
||||
|
||||
daemon
|
||||
------
|
||||
|
||||
For daemon processes.
|
||||
|
||||
piddir: directory that daemon processes should write their PID file
|
||||
(process ID) to. Defaults to /var/run/, which is where this
|
||||
stuff should usually go on Unix-ish systems.
|
||||
user: If set, the daemons will try to change their effective user ID
|
||||
to this user before running. Probably a good idea, especially if
|
||||
you start the daemons as root. Note: user name, like 'daemon',
|
||||
not 1001.
|
||||
group: If set, the daemons will try to change their effective group ID
|
||||
to this named group. Again, a name, not a numerical ID.
|
||||
|
||||
emailpost
|
||||
---------
|
||||
|
||||
For post-by-email.
|
||||
|
||||
enabled: Whether to enable post-by-email. Defaults to true. You will
|
||||
also need to set up maildaemon.php.
|
||||
|
||||
sms
|
||||
---
|
||||
|
||||
For SMS integration.
|
||||
|
||||
enabled: Whether to enable SMS integration. Defaults to true. Queues
|
||||
should also be enabled.
|
||||
|
||||
integration
|
||||
-----------
|
||||
|
||||
A catch-all for integration with other systems.
|
||||
|
||||
taguri: base for tag:// URIs. Defaults to site-server + ',2009'.
|
||||
|
||||
inboxes
|
||||
-------
|
||||
|
||||
For notice inboxes.
|
||||
|
||||
enabled: No longer used. If you set this to something other than true,
|
||||
StatusNet will no longer run.
|
||||
|
||||
throttle
|
||||
--------
|
||||
|
||||
For notice-posting throttles.
|
||||
|
||||
enabled: Whether to throttle posting. Defaults to false.
|
||||
count: Each user can make this many posts in 'timespan' seconds. So, if count
|
||||
is 100 and timespan is 3600, then there can be only 100 posts
|
||||
from a user every hour.
|
||||
timespan: see 'count'.
|
||||
|
||||
profile
|
||||
-------
|
||||
|
||||
Profile management.
|
||||
|
||||
biolimit: max character length of bio; 0 means no limit; null means to use
|
||||
the site text limit default.
|
||||
backup: whether users can backup their own profiles. Defaults to true.
|
||||
restore: whether users can restore their profiles from backup files. Defaults
|
||||
to true.
|
||||
delete: whether users can delete their own accounts. Defaults to false.
|
||||
move: whether users can move their accounts to another server. Defaults
|
||||
to true.
|
||||
|
||||
newuser
|
||||
-------
|
||||
|
||||
Options with new users.
|
||||
|
||||
default: nickname of a user account to automatically subscribe new
|
||||
users to. Typically this would be system account for e.g.
|
||||
service updates or announcements. Users are able to unsub
|
||||
if they want. Default is null; no auto subscribe.
|
||||
welcome: nickname of a user account that sends welcome messages to new
|
||||
users. Can be the same as 'default' account, although on
|
||||
busy servers it may be a good idea to keep that one just for
|
||||
'urgent' messages. Default is null; no message.
|
||||
|
||||
If either of these special user accounts are specified, the users should
|
||||
be created before the configuration is updated.
|
||||
|
||||
attachments
|
||||
-----------
|
||||
|
||||
The software lets users upload files with their notices. You can configure
|
||||
the types of accepted files by mime types and a trio of quota options:
|
||||
per file, per user (total), per user per month.
|
||||
|
||||
We suggest the use of the pecl file_info extension to handle mime type
|
||||
detection.
|
||||
|
||||
supported: an array of mime types you accept to store and distribute,
|
||||
like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you
|
||||
setup your server to properly recognize the types you want to
|
||||
support.
|
||||
uploads: false to disable uploading files with notices (true by default).
|
||||
|
||||
For quotas, be sure you've set the upload_max_filesize and post_max_size
|
||||
in php.ini to be large enough to handle your upload. In httpd.conf
|
||||
(if you're using apache), check that the LimitRequestBody directive isn't
|
||||
set too low (it's optional, so it may not be there at all).
|
||||
|
||||
process_links: follow redirects and save all available file information
|
||||
(mimetype, date, size, oembed, etc.). Defaults to true.
|
||||
file_quota: maximum size for a single file upload in bytes. A user can send
|
||||
any amount of notices with attachments as long as each attachment
|
||||
is smaller than file_quota.
|
||||
user_quota: total size in bytes a user can store on this server. Each user
|
||||
can store any number of files as long as their total size does
|
||||
not exceed the user_quota.
|
||||
monthly_quota: total size permitted in the current month. This is the total
|
||||
size in bytes that a user can upload each month.
|
||||
dir: directory accessible to the Web process where uploads should go.
|
||||
Defaults to the 'file' subdirectory of the install directory, which
|
||||
should be writeable by the Web user.
|
||||
server: server name to use when creating URLs for uploaded files.
|
||||
Defaults to null, meaning to use the default Web server. Using
|
||||
a virtual server here can speed up Web performance.
|
||||
path: URL path, relative to the server, to find files. Defaults to
|
||||
main path + '/file/'.
|
||||
ssl: whether to use HTTPS for file URLs. Defaults to null, meaning to
|
||||
guess based on other SSL settings.
|
||||
sslserver: if specified, this server will be used when creating HTTPS
|
||||
URLs. Otherwise, the site SSL server will be used, with /file/ path.
|
||||
sslpath: if this and the sslserver are specified, this path will be used
|
||||
when creating HTTPS URLs. Otherwise, the attachments|path value
|
||||
will be used.
|
||||
|
||||
group
|
||||
-----
|
||||
|
||||
Options for group functionality.
|
||||
|
||||
maxaliases: maximum number of aliases a group can have. Default 3. Set
|
||||
to 0 or less to prevent aliases in a group.
|
||||
desclimit: maximum number of characters to allow in group descriptions.
|
||||
null (default) means to use the site-wide text limits. 0
|
||||
means no limit.
|
||||
addtag: Whether to add a tag for the group nickname for every group post
|
||||
(pre-1.0.x behaviour). Defaults to false.
|
||||
|
||||
search
|
||||
------
|
||||
|
||||
Some stuff for search.
|
||||
|
||||
type: type of search. Ignored if PostgreSQL or Sphinx are enabled. Can either
|
||||
be 'fulltext' or 'like' (default). The former is faster and more efficient
|
||||
but requires the lame old MyISAM engine for MySQL. The latter
|
||||
will work with InnoDB but could be miserably slow on large
|
||||
systems. We'll probably add another type sometime in the future,
|
||||
with our own indexing system (maybe like MediaWiki's).
|
||||
|
||||
sessions
|
||||
--------
|
||||
|
||||
Session handling.
|
||||
|
||||
handle: boolean. Whether we should register our own PHP session-handling
|
||||
code (using the database and cache layers if enabled). Defaults to false.
|
||||
Setting this to true makes some sense on large or multi-server
|
||||
sites, but it probably won't hurt for smaller ones, either.
|
||||
debug: whether to output debugging info for session storage. Can help
|
||||
with weird session bugs, sometimes. Default false.
|
||||
|
||||
background
|
||||
----------
|
||||
|
||||
Users can upload backgrounds for their pages; this section defines
|
||||
their use.
|
||||
|
||||
server: the server to use for background. Using a separate (even
|
||||
virtual) server for this can speed up load times. Default is
|
||||
null; same as site server.
|
||||
dir: directory to write backgrounds too. Default is '/background/'
|
||||
subdir of install dir.
|
||||
path: path to backgrounds. Default is sub-path of install path; note
|
||||
that you may need to change this if you change site-path too.
|
||||
sslserver: SSL server to use when page is HTTPS-encrypted. If
|
||||
unspecified, site ssl server and so on will be used.
|
||||
sslpath: If sslserver if defined, path to use when page is HTTPS-encrypted.
|
||||
|
||||
ping
|
||||
----
|
||||
|
||||
Using the "XML-RPC Ping" method initiated by weblogs.com, the site can
|
||||
notify third-party servers of updates.
|
||||
|
||||
notify: an array of URLs for ping endpoints. Default is the empty
|
||||
array (no notification).
|
||||
|
||||
design
|
||||
------
|
||||
|
||||
Default design (colors and background) for the site. Actual appearance
|
||||
depends on the theme. Null values mean to use the theme defaults.
|
||||
|
||||
backgroundcolor: Hex color of the site background.
|
||||
contentcolor: Hex color of the content area background.
|
||||
sidebarcolor: Hex color of the sidebar background.
|
||||
textcolor: Hex color of all non-link text.
|
||||
linkcolor: Hex color of all links.
|
||||
backgroundimage: Image to use for the background.
|
||||
disposition: Flags for whether or not to tile the background image.
|
||||
|
||||
notice
|
||||
------
|
||||
|
||||
Configuration options specific to notices.
|
||||
|
||||
contentlimit: max length of the plain-text content of a notice.
|
||||
Default is null, meaning to use the site-wide text limit.
|
||||
0 means no limit.
|
||||
defaultscope: default scope for notices. If null, the default
|
||||
scope depends on site/private. It's 1 if the site is private,
|
||||
0 otherwise. Set this value to override.
|
||||
|
||||
message
|
||||
-------
|
||||
|
||||
Configuration options specific to messages.
|
||||
|
||||
contentlimit: max length of the plain-text content of a message.
|
||||
Default is null, meaning to use the site-wide text limit.
|
||||
0 means no limit.
|
||||
|
||||
logincommand
|
||||
------------
|
||||
|
||||
Configuration options for the login command.
|
||||
|
||||
disabled: whether to enable this command. If enabled, users who send
|
||||
the text 'login' to the site through any channel will
|
||||
receive a link to login to the site automatically in return.
|
||||
Possibly useful for users who primarily use an XMPP or SMS
|
||||
interface and can't be bothered to remember their site
|
||||
password. Note that the security implications of this are
|
||||
pretty serious and have not been thoroughly tested. You
|
||||
should enable it only after you've convinced yourself that
|
||||
it is safe. Default is 'false'.
|
||||
|
||||
singleuser
|
||||
----------
|
||||
|
||||
If an installation has only one user, this can simplify a lot of the
|
||||
interface. It also makes the user's profile the root URL.
|
||||
|
||||
enabled: Whether to run in "single user mode". Default false.
|
||||
nickname: nickname of the single user. If no nickname is specified,
|
||||
the site owner account will be used (if present).
|
||||
|
||||
robotstxt
|
||||
---------
|
||||
|
||||
We put out a default robots.txt file to guide the processing of
|
||||
Web crawlers. See http://www.robotstxt.org/ for more information
|
||||
on the format of this file.
|
||||
|
||||
crawldelay: if non-empty, this value is provided as the Crawl-Delay:
|
||||
for the robots.txt file. see http://ur1.ca/l5a0
|
||||
for more information. Default is zero, no explicit delay.
|
||||
disallow: Array of (virtual) directories to disallow. Default is 'main',
|
||||
'search', 'message', 'settings', 'admin'. Ignored when site
|
||||
is private, in which case the entire site ('/') is disallowed.
|
||||
|
||||
api
|
||||
---
|
||||
|
||||
Options for the Twitter-like API.
|
||||
|
||||
realm: HTTP Basic Auth realm (see http://tools.ietf.org/html/rfc2617
|
||||
for details). Some third-party tools like ping.fm want this to be
|
||||
'Identi.ca API', so set it to that if you want to. default = null,
|
||||
meaning 'something based on the site name'.
|
||||
|
||||
nofollow
|
||||
--------
|
||||
|
||||
We optionally put 'rel="nofollow"' on some links in some pages. The
|
||||
following configuration settings let you fine-tune how or when things
|
||||
are nofollowed. See http://en.wikipedia.org/wiki/Nofollow for more
|
||||
information on what 'nofollow' means.
|
||||
|
||||
subscribers: whether to nofollow links to subscribers on the profile
|
||||
and personal pages. Default is true.
|
||||
members: links to members on the group page. Default true.
|
||||
peopletag: links to people listed in the peopletag page. Default true.
|
||||
external: external links in notices. One of three values: 'sometimes',
|
||||
'always', 'never'. If 'sometimes', then external links are not
|
||||
nofollowed on profile, notice, and favorites page. Default is
|
||||
'sometimes'.
|
||||
|
||||
url
|
||||
---
|
||||
|
||||
These are some options for fine-tuning how and when the server will
|
||||
shorten URLs.
|
||||
|
||||
shortener: URL shortening service to use by default. Users can override
|
||||
individually. 'internal' by default.
|
||||
maxurllength: If an URL is strictly longer than this limit, it will be
|
||||
shortened. Note that the URL shortener service may return an
|
||||
URL longer than this limit. Defaults to 100. Users can
|
||||
override. If set to 0, all URLs will be shortened.
|
||||
maxnoticelength: If a notice is strictly longer than this limit, all
|
||||
URLs in the notice will be shortened. Users can override.
|
||||
-1 means the text limit for notices.
|
||||
|
||||
router
|
||||
------
|
||||
|
||||
We use a router class for mapping URLs to code. This section controls
|
||||
how that router works.
|
||||
|
||||
cache: whether to cache the router in cache layers. Defaults to true,
|
||||
but may be set to false for developers (who might be actively
|
||||
adding pages, so won't want the router cached) or others who see
|
||||
strange behavior. You're unlikely to need this unless developing..
|
||||
|
||||
http
|
||||
----
|
||||
|
||||
Settings for the HTTP client.
|
||||
|
||||
ssl_cafile: location of the CA file for SSL. If not set, won't verify
|
||||
SSL peers. Default unset.
|
||||
curl: Use cURL <http://curl.haxx.se/> for doing HTTP calls. You must
|
||||
have the PHP curl extension installed for this to work.
|
||||
proxy_host: Host to use for proxying HTTP requests. If unset, doesn't
|
||||
do any HTTP proxy stuff. Default unset.
|
||||
proxy_port: Port to use to connect to HTTP proxy host. Default null.
|
||||
proxy_user: Username to use for authenticating to the HTTP proxy. Default null.
|
||||
proxy_password: Password to use for authenticating to the HTTP proxy. Default null.
|
||||
proxy_auth_scheme: Scheme to use for authenticating to the HTTP proxy. Default null.
|
||||
|
||||
plugins
|
||||
-------
|
||||
|
||||
default: associative array mapping plugin name to array of arguments. To disable
|
||||
a default plugin, unset its value in this array.
|
||||
locale_path: path for finding plugin locale files. In the plugin's directory
|
||||
by default.
|
||||
server: Server to find static files for a plugin when the page is plain old HTTP.
|
||||
Defaults to site/server (same as pages). Use this to move plugin CSS and
|
||||
JS files to a CDN.
|
||||
sslserver: Server to find static files for a plugin when the page is HTTPS. Defaults
|
||||
to site/server (same as pages). Use this to move plugin CSS and JS files
|
||||
to a CDN.
|
||||
path: Path to the plugin files. defaults to site/path + '/plugins/'. Expects that
|
||||
each plugin will have a subdirectory at plugins/NameOfPlugin. Change this
|
||||
if you're using a CDN.
|
||||
sslpath: Path to use on the SSL server. Same as plugins/path.
|
||||
|
||||
performance
|
||||
-----------
|
||||
|
||||
high: if you need high performance, or if you're seeing bad
|
||||
performance, set this to true. It will turn off some high-intensity code from
|
||||
the site.
|
||||
|
||||
oldschool
|
||||
---------
|
||||
|
||||
enabled: enable certain old-style user settings options, like stream-only mode,
|
||||
conversation trees, and nicknames in streams. Off by default, and
|
||||
may not be well supported in future versions.
|
||||
|
||||
|
|
@ -0,0 +1,661 @@
|
|||
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.
|
||||
|
||||
<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/>.
|
105
CREDITS.md
105
CREDITS.md
|
@ -1,105 +0,0 @@
|
|||
Credits for GNU social
|
||||
======================
|
||||
The following is an incomplete list of developers
|
||||
who've worked on GNU social, or its predecessors
|
||||
StatusNet and Free Social. Apologies for any
|
||||
oversight; please let mail@diogo.site know if
|
||||
anyone's been overlooked in error.
|
||||
|
||||
Current team
|
||||
------------
|
||||
* Alexei Sorokin
|
||||
* Diogo Cordeiro
|
||||
* Eliseu Amaro
|
||||
* Hugo Sales
|
||||
|
||||
V2 team
|
||||
-------
|
||||
* Diogo Cordeiro
|
||||
* Alexei Sorokin
|
||||
* Bruno Casteleiro
|
||||
|
||||
Additional Contributors
|
||||
-----------------------
|
||||
* Akio
|
||||
* Blaine Cook
|
||||
* Bob Mottram
|
||||
* Brenda Wallace
|
||||
* Brett Taylor
|
||||
* Brian Hendrickson
|
||||
* Brigitte Schuster
|
||||
* Ciaran Gultnieks
|
||||
* Craig Andrews
|
||||
* Daniel Supernault
|
||||
* Dan Moore
|
||||
* David Yip
|
||||
* Deb Nicholson
|
||||
* Donald Robertson
|
||||
* Eric Helgeson
|
||||
* Federico Marani
|
||||
* Fil
|
||||
* Garret Buell
|
||||
* Henry Story
|
||||
* Ian Denhart
|
||||
* Jeffery To
|
||||
* Jeff Mitchell
|
||||
* Ken Sedgwick
|
||||
* Leslie Michael Orchard
|
||||
* Maiyannah Bishop
|
||||
* Matthew Gregg
|
||||
* Matt Lee
|
||||
* mEDI
|
||||
* Melvin Carvalho
|
||||
* Michael Landers
|
||||
* Miguel Dantas
|
||||
* Mikael Nordfeldth
|
||||
* Mike Cochrane
|
||||
* Moonman
|
||||
* Neil E Hodges
|
||||
* Normandy
|
||||
* Ori Avtalion
|
||||
* Sean Murphy
|
||||
* Stéphane Bérubé
|
||||
* Steven DuBois
|
||||
* Tobias Diekershoff
|
||||
* Verius
|
||||
|
||||
Credits for StatusNet
|
||||
--------------
|
||||
Leads
|
||||
* Evan Prodromou
|
||||
* Zach Copley
|
||||
|
||||
Team
|
||||
* Adrian Lang
|
||||
* Brion Vibber
|
||||
* 'drry'
|
||||
* Earle Martin
|
||||
* Erik Stambaugh
|
||||
* Florian Biree
|
||||
* Gina Haeussge
|
||||
* James Walker
|
||||
* Joshua Judson Rosen (rozzin)
|
||||
* Ken Sheppardson
|
||||
* Marie-Claude Doyon
|
||||
* Meitar Moscovitz
|
||||
* Ori Avtalion
|
||||
* Robin Millette
|
||||
* Samantha Doherty
|
||||
* Sarven Capadisli
|
||||
* Simon Waters, Surevine
|
||||
* Tryggvi Björgvinsson
|
||||
|
||||
Translators
|
||||
-----------
|
||||
* Siebrand Mazeland
|
||||
* Tiago 'gouki' Faria
|
||||
* TranslateWiki.net
|
||||
|
||||
A special thanks to the thousands of people who
|
||||
have tried out GNU social, told their friends, and
|
||||
built the fediverse network to what it is today.
|
||||
|
||||
License help from
|
||||
-----------------
|
||||
* Bradley M. Kuhn
|
|
@ -1,3 +0,0 @@
|
|||
In the `dev` environment, the default values for the config table are reloaded on each HTTP request
|
||||
|
||||
In case you want to override this, add `SOCIAL_NO_RELOAD_DEFAULTS=1` to your .env.local file
|
|
@ -1 +0,0 @@
|
|||
../../INSTALL.md
|
|
@ -1,762 +0,0 @@
|
|||
Configuration options
|
||||
================================================================================
|
||||
|
||||
The configuration for GNU social is stored in the database table
|
||||
`config`.
|
||||
|
||||
A Web based configuration panel exists so the site admin can configure
|
||||
GNU social. The preferred method for changing config options is to use this
|
||||
panel.
|
||||
|
||||
A command-line script, `set_config.php`, can be used to set individual
|
||||
configuration options. It's in the `bin/` directory.
|
||||
|
||||
Almost all configuration options are made through a two-dimensional
|
||||
associative array, cleverly named `$config`. A typical configuration
|
||||
line will be:
|
||||
|
||||
$config['section']['setting] = value;
|
||||
|
||||
The following documentation describes each section and setting.
|
||||
|
||||
|
||||
site
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This section is a catch-all for site-wide variables.
|
||||
|
||||
* `name` (string, required, defaults to the value provided in the configre script,
|
||||
sitename): the name of your site, like 'YourCompany Microblog'.
|
||||
|
||||
* `server` (string, required, defaults to the value provided in the configre script,
|
||||
sitename): the server domain, like 'example.net'.
|
||||
|
||||
* `notice` (string, default null): A plain string that will appear on every page. A good
|
||||
place to put introductory information about your service, or info about upgrades and
|
||||
outages, or other community info. Any HTML will be escaped.
|
||||
|
||||
* `theme` (string, default 'default'): Theme for your site (see Theme section).
|
||||
|
||||
* `logo` (string, default null): URL of an image file to use as the logo for the site.
|
||||
Overrides the logo in the theme, if any.
|
||||
|
||||
* `language` (string, default "en"): default language for your site. Defaults to English.
|
||||
Note that this is overridden, if enabled in the following setting, if a user is logged
|
||||
in and has selected a different language or if the user is NOT logged in, but their
|
||||
browser requests a different langauge. Since pretty much everybody's browser requests
|
||||
a language, that means that changing this setting has little or no effect in practice.
|
||||
|
||||
* `detect_language` (boolean, default true): whether to use the most appropriate language
|
||||
depending on the requester's browser preferences.
|
||||
|
||||
* `languages` (array, default null): A list of languages supported on your site. Typically
|
||||
you'd only change this if you wanted to disable support for one or more languages:
|
||||
|
||||
`unset($config['site']['languages']['de'])` will disable support for German.
|
||||
|
||||
* `email` (string, required): contact email address for your site. By default, it's
|
||||
extracted from your Web server environment or the value provided in the configure
|
||||
script; you may want to customize it.
|
||||
|
||||
* `recovery_disclose` (boolean, default false): whether to confirm if the email exists
|
||||
when attempting to login. Recommended to keep it false, for some privacy.
|
||||
|
||||
* `timezone` (string, default 'UTC'): default timezone for message display. Users
|
||||
can set their own time zone. Defaults to 'UTC', which is a pretty good
|
||||
default.
|
||||
|
||||
* `brought_by` (string, default null): text used for the "brought by" link.
|
||||
|
||||
* `brought_by_url` (string, default null): name of an organization or individual who
|
||||
provides the service. Each page will include a link to this name in the footer or
|
||||
sidebar. A good way to link to the blog, forum, wiki, corporate portal, or whoever is
|
||||
making the service available.
|
||||
|
||||
* `closed` (boolean, default false): If set to 'true', will disallow registration on your
|
||||
site. This is a easy way to restrict accounts to only one individual or group; just
|
||||
register the accounts you want on the service, *then* set this variable to 'true'.
|
||||
|
||||
* `invite_only` (boolean, default false): If set to 'true', will only allow registration
|
||||
if the user was invited by an existing user.
|
||||
|
||||
* `private` (boolean, default false): If set to 'true', anonymous users will be redirected
|
||||
to the 'login' page. Also, API methods that normally require no authentication will
|
||||
require it. Note that this does not turn off registration; use 'closed' or
|
||||
'invite_only' for that behaviour.
|
||||
|
||||
* `ssl` (enum['always', 'sometimes', 'never'], default always'): Whether to use SSL and
|
||||
https:// URLs for some or all pages.
|
||||
|
||||
Possible values are 'always' (use it for all pages), 'never' (don't use it for any
|
||||
pages), or 'sometimes' (use it for sensitive pages that include passwords like login
|
||||
and registration, but not for regular pages).
|
||||
|
||||
* `ssl_proxy` (string|boolean, default false): Whether to force GNUsocial to think it is
|
||||
HTTPS when the server gives no such information. I.e. when you're using a reverse
|
||||
proxy that adds the encryption layer but the webserver that runs PHP isn't configured
|
||||
with a key and certificate. If a string is given, it will be used as the URL of the
|
||||
proxy server.
|
||||
|
||||
* `duplicate_time_limit` (integer, default 60): minimum time allowed for one person to say
|
||||
the same thing twice. Default 60s. If it happens faster than this, it's considered a
|
||||
user or UI error.
|
||||
|
||||
* `text_limit` (integer, default 1000): default max size for texts in the site. Can be
|
||||
fine-tuned for notices, messages, profile bios and group descriptions. Zero indicates
|
||||
no limit.
|
||||
|
||||
* `x-static-delivery` (string, default null): when a string, use this as the header with
|
||||
which to serve static files. Possible values are 'X-Sendfile' (for Apache and others)
|
||||
and 'X-Accel-Redirect' (for nginx).
|
||||
|
||||
|
||||
security
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `hash_algos` (array, default ['sha1', 'sha256', 'sha512']): set to null for anything
|
||||
that `hash_hmac()` can handle; can be any combination of the result of `hash_algos()`
|
||||
|
||||
|
||||
db
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `mirror` (array, default null): you can set this to an array of database connection
|
||||
URIs. If it's set, load will be split among these, and replication will be enabled.
|
||||
|
||||
|
||||
fix
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `fancy_urls` (boolean, default true): fix any non-facy url to the correct form, when
|
||||
possible.
|
||||
|
||||
* `http` (boolean, default true): fixe any http links to https.
|
||||
|
||||
|
||||
queue
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
You can configure the software to queue time-consuming tasks, like
|
||||
sending out SMS, email or XMPP messages, for off-line processing.
|
||||
|
||||
* `enabled` (boolean, default true): Whether to uses queues.
|
||||
|
||||
* `daemon` (boolean, default false): Whether to use queuedaemon. False means
|
||||
you'll use OpportunisticQM plugin.
|
||||
|
||||
* `threads` (int): How many queue processes to run. Defaults to number of cpu cores in
|
||||
unix-like systems or 1 on other OSes.
|
||||
|
||||
* `subsystem` (enum["db", "stomp", "redis"], default 'db'): Which kind of
|
||||
queueserver to use. Values include "db" for our database queuing (no other server
|
||||
required), "stomp" for a stomp server amd "redis" for a Redis server.
|
||||
|
||||
* `basename` (string, default '/queue/gnusocial/'): a root name to use for queues (stomp
|
||||
and redis only). Typically something like '/queue/sitename/' makes sense. If running
|
||||
multiple instances on the same server, make sure that either this setting or
|
||||
`$config['site']['nickname']` are unique for each site to keep them separate.
|
||||
|
||||
* `control_channel` (string, default '/topic/gnusocial/control'): the control channel used
|
||||
for different queue processes to communicate.
|
||||
|
||||
* `monitor` (string, default null): URL endpoint to monitor queue status
|
||||
|
||||
* `soft_limit` (string, default '90%'): an absolute or relative "soft memory limit";
|
||||
daemons will restart themselves gracefully when they find they've hit this amount of
|
||||
memory usage. Relative means a percentage of PHP's global `memory_limit` setting.
|
||||
|
||||
* `spawn_delay` (integer, default 1): seconds to wait between deamon restarts.
|
||||
|
||||
* `debug_memory` (boolean, default false): log daemon's memory usage.
|
||||
|
||||
* `stomp_server` (string, default null): URI for stomp server. Something like
|
||||
"tcp://hostname:61613". More complicated ones are possible; see your stomp server's
|
||||
documentation for details.
|
||||
|
||||
* `stomp_username` (string, default null): username for connecting to the stomp server.
|
||||
|
||||
* `stomp_password` (string, default null): password for connecting to the stomp server.
|
||||
|
||||
* `stomp_persistent` (boolean, default true): Keep items across queue server restart, if
|
||||
enabled. Note: Under ActiveMQ, the server configuration determines if and how
|
||||
persistent storage is actually saved. Not all stomp servers support persistence.
|
||||
|
||||
* `stomp_transactions` (boolean, default true): use transactions to aid in error
|
||||
detection. A broken transaction will be seen quickly, allowing a message to be
|
||||
redelivered immediately if a daemon crashes. Not all stop servers support
|
||||
transactions.
|
||||
|
||||
* `stomp_acks` (boolean, default true): send acknowledgements to aid in flow control. An
|
||||
acknowledgement of successful processing tells the server we're ready for more and can
|
||||
help keep things moving smoothly. This should *not* be turned off when running with
|
||||
ActiveMQ, (it breaks if you do), but if using another message queue server that does
|
||||
not support acknowledgements you might need to disable this.
|
||||
|
||||
* `stomp_manual_failover` (boolean, default true): if multiple servers are listed, treat
|
||||
them as separate (enqueue on one randomly, listen on all).
|
||||
|
||||
* `max_retries` (integer, default 10): for stomp, drop messages after N failed
|
||||
attempts to process.
|
||||
|
||||
* `dead_letter_dir` (string, default null): for stomp, optional directory to dump
|
||||
data on failed queue processing events after discarding them.
|
||||
|
||||
|
||||
avatar
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `server` (string, default null): If set, defines another server where avatars are
|
||||
stored. Note that the `dir` still has to be writeable. You'd typically use this to
|
||||
split HTTP requests on the client to speed up page loading, either with another
|
||||
virtual server or with an NFS or SAMBA share. Clients typically only make 2
|
||||
connections to a single server at a time
|
||||
<https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4>, so this can
|
||||
parallelize the job.
|
||||
|
||||
* `url_base` (string, 'default '/avatar/'): URL where avatars can be found.
|
||||
|
||||
* `ssl` (boolean, default null): Whether to access avatars using HTTPS. Defaults
|
||||
to null, meaning to guess based on site-wide SSL settings.
|
||||
|
||||
* `dir` (string, default 'file/avatar/'): Directory to save avatar files to.
|
||||
|
||||
* `max_size_px` (integer, default 300): Maximum width or height for user avatars, in pixels
|
||||
|
||||
|
||||
javascript
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `server` (string, default null): You can speed up page loading by pointing the
|
||||
javascript file lookup to another server (virtual or real). Defaults to NULL, meaning
|
||||
to use the site server.
|
||||
|
||||
* `url_base` (string default '/js/'): URL part for JavaScript files.
|
||||
|
||||
* `ssl` (boolean, default null): Whether to use SSL for JavaScript files. Default is null,
|
||||
which means guess based on site SSL settings.
|
||||
|
||||
* `bust_frames` (boolean, default true): If true, all web pages will break out of
|
||||
framesets. If false, can comfortably live in a frame or iframe... probably.
|
||||
|
||||
|
||||
attachments
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `server` (string, default null): Server name to use when creating URLs for uploaded
|
||||
files. Defaults to null, meaning to use the default Web server. Using a virtual server
|
||||
here can speed up Web performance.
|
||||
|
||||
* `url_base` (string, default '/file/'): URL path, relative to the server, to find
|
||||
files. Defaults to main path + '/file/'.
|
||||
|
||||
* `ssl` (boolean, default null): Whether to use HTTPS for file URLs. Defaults to null,
|
||||
meaning to use other SSL settings.
|
||||
|
||||
* `dir` (string, default '/file/uploads/'): Directory accessible to the Web process where
|
||||
uploads should go.
|
||||
|
||||
* `supported` (array): An associative array of mime types you accept to store and
|
||||
distribute, like 'image/gif', 'video/mpeg', 'audio/mpeg', to the corresponding file
|
||||
extension. Make sure you setup your server to properly recognize the types you want to
|
||||
support. It's important to use the result of calling `image_type_to_extension` for the
|
||||
appropriate image type, in the case of images. This is so all parts of the code see
|
||||
the same file extension for each image type (jpg vs jpeg). For example, to enable BMP
|
||||
uploads, add this to the config.php file:
|
||||
`image_type_to_mime_type(IMAGETYPE_BMP) => image_type_to_extension(IMAGETYPE_BMP);` See
|
||||
https://www.php.net/manual/en/function.image-type-to-mime-type.php for a list of such
|
||||
constants. If a filetype is not listed there, it's possible to add the mimetype and
|
||||
the extension by hand, but they need to match those returned by the file command.
|
||||
|
||||
For quotas, be sure you've set the `upload_max_filesize` and `post_max_size` in php.ini to
|
||||
be large enough to handle your upload. In httpd.conf (if you're using apache), check that
|
||||
the LimitRequestBody directive isn't set too low (it's optional, so it may not be there at
|
||||
all).
|
||||
|
||||
* `file_quota` (integer, defaults to minimum of `'post_max_size', 'upload_max_filesize',
|
||||
'memory_limit'`): Maximum size for a single file upload, in bytes. A user can send any
|
||||
amount of notices with attachments as long as each attachment is smaller than
|
||||
file_quota.
|
||||
|
||||
* `user_quota` (integer, default 200M): Total size, in bytes, a user can store on this
|
||||
server. Each user can store any number of files as long as their total size does not
|
||||
exceed the user_quota.
|
||||
|
||||
* `monthly_quota` (integer, default 20M): Total size in bytes that a user can upload each
|
||||
month.
|
||||
|
||||
* `uploads` (boolean, default true): Whether to allow uploading files with notices.
|
||||
|
||||
* `show_html` (boolean, default true): Whether to show (filtered) text/html attachments
|
||||
(and oEmbed HTML etc.). Doesn't affect AJAX calls.
|
||||
|
||||
* `show_thumbs` (boolean, default true): Whether to show thumbnails in notice lists for
|
||||
uploaded images, and photos and videos linked remotely that provide oEmbed info.
|
||||
|
||||
* `process_links` (boolean, default true): Whether to follow redirects and save all
|
||||
available file information (mimetype, date, size, oembed, etc.).
|
||||
|
||||
* `ext_blacklist` (array, default []): associative array to either deny certain extensions or
|
||||
change them to a different one. For example:
|
||||
|
||||
$config['attachments']['extblacklist']['php'] = 'phps'; // this turns .php into .phps
|
||||
$config['attachments']['extblacklist']['exe'] = false; // this would deny any uploads
|
||||
// of files with the "exe" extension
|
||||
|
||||
* `filename` (string, default hash): Name for new files, one of: 'upload', 'hash'.
|
||||
|
||||
* `memory_limit` (string, default '1024M'): PHP memory limit to use temporarily when
|
||||
handling images
|
||||
|
||||
|
||||
thumbnail
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `server` (string, default null): Server name from which to serve thumbnails. Defaults to
|
||||
null, meaning to use the default Web server. Using a virtual server here can speed up
|
||||
Web performance.
|
||||
|
||||
* `url_base` (string, default '/thumb/'): URL path, relative to the server, to find
|
||||
files.
|
||||
|
||||
* `ssl` (boolean, default null): Whether to use HTTPS for thumbnail URLs. Defaults to null,
|
||||
meaning to use other SSL settings.
|
||||
|
||||
* `dir` (string, default '/file/thumbnails/'): Path where to store thumbnails.
|
||||
|
||||
* `crop` (boolean, default false): Whether to crop thumbnails (or scale them down)
|
||||
|
||||
* `max_size_px` (integer, default 1000): Thumbnails with an edge greater than this will
|
||||
not be generated.
|
||||
|
||||
* `width` (integer, default 450): Width for generated thumbnails.
|
||||
|
||||
* `height` (integer, default 600): Heigth for generated thumbnails.
|
||||
|
||||
* `upscale` (boolean, default false): Whether to generate thumbnails bigger than the original.
|
||||
|
||||
* `animated` (boolean, default false): Whether to allow animated thumbnails.
|
||||
|
||||
|
||||
theme
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `server` (string, default null): Like avatars, you can speed up page loading
|
||||
by pointing the theme file lookup to another server (virtual or real).
|
||||
The default of null will use the same server as PA.
|
||||
|
||||
* `url_base` (string, default '/theme'): Path part of theme URLs, before the theme name.
|
||||
Relative to the theme server. It may make sense to change this path when upgrading,
|
||||
(using version numbers as the path) to make sure that all files are reloaded by
|
||||
caching clients or proxies.
|
||||
|
||||
* `ssl` (boolean, default null): Whether to use SSL for theme elements. Default
|
||||
is null, which means guess based on site SSL settings.
|
||||
|
||||
* `dir` (string, default "./themes"): Directory where theme files are stored.
|
||||
Used to determine whether to show parts of a theme file. Defaults to the
|
||||
theme subdirectory of the install directory.
|
||||
|
||||
|
||||
plugins
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `server` (string, default null): Server to find static files for a plugin when the page
|
||||
is plain old HTTP. Defaults to site/server (same as pages). You can use this to move
|
||||
plugin CSS and JS files to a CDN.
|
||||
|
||||
* `url_base` (string, default '/plugins/'): Path to the plugin files. Expects that each
|
||||
plugin will have a subdirectory at plugins/NameOfPlugin. Change this if you're using
|
||||
a CDN.
|
||||
|
||||
* `ssl` (boolean, default null) Whether to use ssl for files served by plugins.
|
||||
|
||||
* `core` (associative array, default TODO): Core GNU social modules, cannot be disabled.
|
||||
|
||||
* `default`: (associative array, default TODO): Mapping from plugin name to array of
|
||||
plugin arguments.
|
||||
|
||||
* `locale_path` (string, default null): Path for finding plugin locale files. In the
|
||||
plugin's directory by default.
|
||||
|
||||
|
||||
license
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
The default license to use for your users' notices. The default is the Creative Commons
|
||||
Attribution 4.0 license, which is probably the right choice for any public site. Note that
|
||||
some other servers will not accept notices if you apply a stricter license than this.
|
||||
|
||||
* `type` (enum["cc", "allrightsreserved", "private"], default 'cc'): One of 'cc' (for
|
||||
Creative Commons licenses), 'allrightsreserved' (default copyright), or 'private' (for
|
||||
private and confidential information).
|
||||
|
||||
* `owner` (string|boolean, default null): For 'allrightsreserved' or 'private', an
|
||||
assigned copyright holder (for example, an employer for a private site). Use true to
|
||||
attribute it to the poster.
|
||||
|
||||
* `url` (string, default 'https://creativecommons.org/licenses/by/4.0/'): URL of the
|
||||
license, used for links.
|
||||
|
||||
* `title` (string, default 'Creative Commons Attribution 4.0'): Title for the license.
|
||||
|
||||
* `image` (string, default '/theme/licenses/cc_by_4.0.png'): URL path for the license image.
|
||||
|
||||
|
||||
mail
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
This is for configuring out-going email.
|
||||
|
||||
* `backend` (enum["mail", "sendmail", "smtp"], default 'mail'): The backend to use for
|
||||
mail. We recommend SMTP where your setup supports it as it is of the three the more
|
||||
difficult one for script exploits to abuse (relatively speaking - they all have
|
||||
potential problems.).
|
||||
|
||||
* `params` (array, default null): If the mail backend requires any parameters, you can
|
||||
provide them in this array.
|
||||
|
||||
* `domain_check` (boolean, default true): Check email origin is valid.
|
||||
|
||||
|
||||
nickname
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `blacklist` (array, default ['doc', 'main', 'avatar', 'theme']): an array of strings for
|
||||
usernames that may not be registered. You may want to add others if you have other
|
||||
software installed in a subdirectory of GNU social or if you just don't want certain
|
||||
words used as usernames.
|
||||
|
||||
* `featured` (array, default null): an array of nicknames of 'featured' users of the site.
|
||||
Can be useful to draw attention to well-known users, or interesting people, or
|
||||
whatever.
|
||||
|
||||
|
||||
profile
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `banned` (array, defualt []): array of users to hell-ban
|
||||
|
||||
* `bio_text_limit` (integer, default null): Max character length of bio; 0 means no
|
||||
limit; null means to use the site text limit default.
|
||||
|
||||
* `allow_nick_change` (boolean, default false): Whether to allow users to change their
|
||||
nickname.
|
||||
|
||||
* `allow_private_stream` (boolean, default true): Whether users can set their streams to
|
||||
private, so only followers can see it.
|
||||
|
||||
* `backup` (boolean, default false): Whether users can backup their own profiles. Can
|
||||
cause DoS.
|
||||
|
||||
* `restore` (boolean, default false): Whether users can restore their profiles from backup
|
||||
files. Can cause DoS.
|
||||
|
||||
* `delete` (boolean, default false): Whether users can delete their own accounts.
|
||||
|
||||
* `move` (boolean, default false): Whether users can move their accounts to another
|
||||
server.
|
||||
|
||||
|
||||
image
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `jpegquality` {integer, default 85}: default quality to use when reencoding images as
|
||||
jpeg.
|
||||
|
||||
|
||||
theme_upload
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `enabled` (boolean, default true): Whether to allow users to upload themes
|
||||
|
||||
* `formats` (array, default ['zip', 'tar', 'gz', 'tar.gz']): Formats to allow
|
||||
|
||||
foaf
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `mbox_sha1sum` (boolean, default false): whether to include this box in the FOAF
|
||||
protocol page
|
||||
|
||||
|
||||
public
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
For configuring the public stream.
|
||||
|
||||
* `local_only` (boolean, default false): If set to true, only messages posted by users of
|
||||
this instance (rather than remote instances) are shown in the public stream.
|
||||
|
||||
* `blacklist` (array, default []): An array of IDs of users to hide from the public
|
||||
stream. Useful if you have someone making an excessive amount of posts to the site or
|
||||
some kind of automated poster, testing bots, etc.
|
||||
|
||||
* `exclude_sources` (array, default []): Sources of notices that should be kept off of
|
||||
the public feed (because they're from automatic posters, for instance).
|
||||
|
||||
|
||||
throttle
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
For notice-posting throttles.
|
||||
|
||||
* `enabled` (boolean, default true): Whether to throttle posting.
|
||||
|
||||
* `count` (integer, default 20): Each user can make this many posts in 'timespan' seconds.
|
||||
So, if count is 100 and timespan is 3600, then there can be only 100 posts from a user
|
||||
every hour.
|
||||
|
||||
* `timespan` (integer, default 600): See 'count'.
|
||||
|
||||
|
||||
invite
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `enabled` (boolean, default true): Whether to allow users to send invites.
|
||||
|
||||
|
||||
tag
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `dropoff` (integer, default 86400 * 10): Exponential decay factor for tag listing, in
|
||||
seconds. You can twiddle with this to try to get better results for your site.
|
||||
|
||||
* `cutoff` (integer, default 86400 * 90): Cutoff, in seconds, before which to not look for
|
||||
notices.
|
||||
|
||||
|
||||
popular
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `dropoff` (integer, default 86400 * 10): Exponential decay factor for popular notices, in
|
||||
seconds. You can twiddle with this to try to get better results for your site.
|
||||
|
||||
* `cutoff` (integer, default 86400 * 90): Cutoff, in seconds, before which to not look for
|
||||
notices.
|
||||
|
||||
|
||||
daemon
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `piddir` (string, default `sys_get_temp_dir()`): Directory that daemon processes should
|
||||
write their PID file (process ID) to.
|
||||
|
||||
* `user` (string|integer, default false): If set, the daemons will try to change their
|
||||
effective user ID to this user before running. Probably a good idea, especially if you
|
||||
start the daemons as root.
|
||||
|
||||
* `group` (string|integer, default false): If set, the daemons will try to change their
|
||||
effective group ID to this named group.
|
||||
|
||||
|
||||
ping
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Using the "XML-RPC Ping" method initiated by weblogs.com, the site can
|
||||
notify third-party servers of updates.
|
||||
|
||||
* `notify` (array, default []): An array of URLs for ping endpoints.
|
||||
|
||||
* `timeout` (integer, default 2): Interval in seconds between notifications.
|
||||
|
||||
|
||||
new_users
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `default_subscriptions` (array, default null): Nickname of user accounts to
|
||||
automatically subscribe new users to. Typically this would be a system account for e.g.
|
||||
service updates or announcements. Users are able to unsub if they want.
|
||||
|
||||
* `welcome_user` (string, default null): Nickname of a user account that sends welcome
|
||||
messages to new users.
|
||||
|
||||
N.B. If either of these special user accounts are specified, the users should be created
|
||||
before the configuration is updated.
|
||||
|
||||
|
||||
linkify
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `bare_domain` (boolean, default false): Prepend schema to any linked domains (a href,
|
||||
not display text).
|
||||
|
||||
* `linkify_ipv4` (boolean, default false): Convert IPv4 addresses into hyperlinks.
|
||||
|
||||
* `linkify_ipv6` (boolean, default false): Convert IPv6 addresses into hyperlinks.
|
||||
|
||||
|
||||
group
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `max_aliases` (integer, default 3): Maximum number of aliases a group can have.
|
||||
Set to 0 or less to prevent aliases in a group.
|
||||
|
||||
* `description_limit` (integer, default null): Maximum number of characters to allow in
|
||||
group descriptions. null means to use the site-wide text limits. 0 means no limit.
|
||||
|
||||
|
||||
people_tag
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `max_tags` (integer, default 100): Maximum number of people tags a user can create.
|
||||
|
||||
* `max_people` (integer, default 500): Maximum number of people with the same user people tag.
|
||||
|
||||
* `allow_tagging` (associative array, default ['local' => true, 'remote' => true])>: Which
|
||||
kind of user to allow tagging.
|
||||
|
||||
* `description_limit` (integer, default null): Maximum tag description lenght.
|
||||
|
||||
|
||||
search
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `type` (enum('fulltext', 'like'), default 'like'): type of search. Ignored if PostgreSQL
|
||||
is enabled. Can either be 'fulltext' or 'like'. The former is faster and more
|
||||
efficient but requires the lame old MyISAM engine for MySQL. The latter will work with
|
||||
InnoDB but could be miserably slow on large systems.
|
||||
|
||||
|
||||
html_filter
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `tags` (array, default ['img', 'video', 'audio', 'script']): Remove tags from
|
||||
user/remotely generated HTML.
|
||||
|
||||
|
||||
notice
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `content_limit` (integer, default null): Max length of the plain-text content of a
|
||||
notice. Null means to use the site-wide text limit. 0 means no limit.
|
||||
|
||||
* `allow_private` (boolean, default false): Whether to allow users to post notices visible
|
||||
only to their subscribers.
|
||||
|
||||
* `hide_banned` (boolean, default true): Whether to hide hell-banned users' notices.
|
||||
|
||||
|
||||
message
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `content_limit` (integer, default null): Max length of the plain-text content of a
|
||||
message. Null means to use the site-wide text limit. 0 means no limit.
|
||||
|
||||
|
||||
location
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `share` (enum('always', 'user', 'never'), default 'user'): Whether to share user
|
||||
location. 'user' means each user can choose.
|
||||
|
||||
|
||||
admin
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `panels` (array, default ['site', 'user', 'paths', 'access', 'sessions', 'sitenotice',
|
||||
'license', 'plugins']): Which panels to include in the admin tab.
|
||||
|
||||
|
||||
single_user
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
If an installation has only one user, this can simplify a lot of the
|
||||
interface. It also makes the user's profile the root URL.
|
||||
|
||||
* `enabled` (boolean, default value provided in configure): Whether to run in "single user mode".
|
||||
|
||||
* `nickname` (string, default null): nickname of the single user. If no nickname is
|
||||
specified, the site owner account will be used (if present).
|
||||
|
||||
|
||||
robots_txt
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `crawl_delay` (integer, default 0): if non-zero, this value is provided as the
|
||||
'Crawl-Delay:' for the robots.txt file. see
|
||||
<https://en.wikipedia.org/wiki/Robots_exclusion_standard#Crawl-delay_directive> for
|
||||
more information. Default is zero, no explicit delay.
|
||||
|
||||
* `disallow`(array, default ['main', 'settings', 'admin', 'search', 'message']): Array of
|
||||
paths to disallow. Ignored when site is private, in which case the entire site ('/')
|
||||
is disallowed.
|
||||
|
||||
|
||||
nofollow
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
We optionally put 'rel="nofollow"' on some links in some pages. The following
|
||||
configuration settings let you fine-tune how or when things are nofollowed. See
|
||||
http://en.wikipedia.org/wiki/Nofollow for more information on what 'nofollow' means.
|
||||
|
||||
* `subscribers` (boolean, default true): Whether to nofollow links to subscribers on the
|
||||
profile and personal pages.
|
||||
|
||||
* `members` (boolean, default true): Whether to nofollow links to members on the group
|
||||
page. Default true.
|
||||
|
||||
* `peopletag` (boolean, default true): Whether to nofollow links to people listed in the
|
||||
peopletag page. Default true.
|
||||
|
||||
* `external` (enum('always', 'sometimes', 'never'), default 'sometimes'): External links
|
||||
in notices. One of three values: 'always', 'sometimes', 'never'. If 'sometimes', then
|
||||
external links are not nofollowed on profile, notice, and favorites page. Default is
|
||||
'sometimes'.
|
||||
|
||||
|
||||
url_shortener
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `service` (string, default 'internal'): URL shortening service to use by default. Users
|
||||
can override individually.
|
||||
|
||||
* `max_url_length` (integer, default 100): If an URL is strictly longer than this limit,
|
||||
it will be shortened. Note that the URL shortener service may return an URL longer
|
||||
than this limit. Users can override. If set to 0, all URLs will be shortened.
|
||||
|
||||
* `max_notice_length` (integer, default null): If a notice is strictly longer than this
|
||||
limit, all URLs in the notice will be shortened. Users can override this.
|
||||
|
||||
|
||||
http
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `ssl_cafile` (string, default '/docker/certbot/files/live/'): location of the CA file
|
||||
for SSL connections. If not set, peers won't be able to verify our identity.
|
||||
|
||||
* `timeout` (integer, default `ini_get('default_socket_timeout')`): Timeout in seconds
|
||||
when to close a connection.
|
||||
|
||||
* `proxy_host` (string, default null): Host to use for proxying HTTP requests. If null,
|
||||
doesn't use an HTTP proxy.
|
||||
|
||||
* `proxy_port` (integer, default null): Port to use to connect to HTTP proxy host.
|
||||
|
||||
* `proxy_user` (string, default null): Username to use for authenticating to the HTTP proxy.
|
||||
|
||||
* `proxy_password` (string, default null): Password to use for authenticating to the HTTP proxy.
|
||||
|
||||
* `proxy_auth_scheme` (TODO): Scheme to use for authenticating to the HTTP proxy.
|
||||
|
||||
|
||||
discovery
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `CORS` (boolean, default false): Whether to allow Cross-Origin Resource Sharing for
|
||||
service discovery (host-meta, XRD, etc.)
|
||||
|
||||
|
||||
performance
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `high` (boolean, default fakse): Disables some high-performance-intensity components.
|
||||
|
||||
|
||||
login_command
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
* `enabled` (boolean, default false): Whether to enable users to send the text 'login' to
|
||||
the site through any channel and receive a link to login to the site automatically in
|
||||
return. Possibly useful for users who primarily use an XMPP or SMS interface. Note
|
||||
that the security implications of this are pretty serious. You should enable it only
|
||||
after you've convinced yourself that it is safe.
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../INSTALL.md
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,468 @@
|
|||
TABLE OF CONTENTS
|
||||
=================
|
||||
* Prerequisites
|
||||
- PHP modules
|
||||
- Better performance
|
||||
* Installation
|
||||
- Getting it up and running
|
||||
- Fancy URLs
|
||||
- Sphinx
|
||||
- SMS
|
||||
- Queues and daemons
|
||||
- Themes
|
||||
- Translation
|
||||
- Backups
|
||||
- Private
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
PHP modules
|
||||
-----------
|
||||
|
||||
The following software packages are *required* for this software to
|
||||
run correctly.
|
||||
|
||||
- PHP 5.4+ For newer versions, some functions that are used may be
|
||||
disabled by default, such as the pcntl_* family. See the
|
||||
section on 'Queues and daemons' for more information.
|
||||
- MariaDB 5+ GNU Social uses, by default, a MariaDB server for data
|
||||
storage. Versions 5.x and 10.x have both reportedly
|
||||
worked well. It is also possible to run MySQL 5.5+.
|
||||
- Web server Apache, lighttpd and nginx will all work. CGI mode is
|
||||
recommended and also some variant of 'suexec' (or a
|
||||
proper setup php-fpm pool)
|
||||
NOTE: mod_rewrite or its equivalent is extremely useful.
|
||||
|
||||
Your PHP installation must include the following PHP extensions for a
|
||||
functional setup of GNU Social:
|
||||
|
||||
- openssl (compiled in for Debian, enabled manually in Arch Linux)
|
||||
- php5-curl Fetching files by HTTP.
|
||||
- php5-gd Image manipulation (scaling).
|
||||
- php5-gmp For Salmon signatures (part of OStatus).
|
||||
- php5-json For WebFinger lookups and more.
|
||||
- php5-mysqlnd The native driver for PHP5 MariaDB connections. If you
|
||||
use MySQL, 'mysql' or 'mysqli' may work.
|
||||
|
||||
The above package names are for Debian based systems. In the case of
|
||||
Arch Linux, PHP is compiled with support for most extensions but they
|
||||
require manual enabling in the relevant php.ini file (mostly php5-gmp).
|
||||
|
||||
Better performance
|
||||
------------------
|
||||
|
||||
For some functionality, you will also need the following extensions:
|
||||
|
||||
- opcache Improves performance a _lot_. Included in PHP, must be
|
||||
enabled manually in php.ini for most distributions. Find
|
||||
and set at least: opcache.enable=1
|
||||
- mailparse Efficient parsing of email requires this extension.
|
||||
Submission by email or SMS-over-email uses this.
|
||||
- sphinx A client for the sphinx server, an alternative to MySQL
|
||||
or Postgresql fulltext search. You will also need a
|
||||
Sphinx server to serve the search queries.
|
||||
- gettext For multiple languages. Default on many PHP installs;
|
||||
will be emulated if not present.
|
||||
- exif For thumbnails to be properly oriented.
|
||||
|
||||
You may also experience better performance from your site if you configure
|
||||
a PHP cache/accelerator. Most distributions come with "opcache" support.
|
||||
Enable it in your php.ini, it is documented there together with its settings.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Getting it up and running
|
||||
-------------------------
|
||||
|
||||
Installing the basic GNU Social web component is relatively easy,
|
||||
especially if you've previously installed PHP/MariaDB packages.
|
||||
|
||||
1. Unpack the tarball you downloaded on your Web server. Usually a
|
||||
command like this will work:
|
||||
|
||||
tar zxf gnusocial-*.tar.gz
|
||||
|
||||
...which will make a gnusocial-x.y.z subdirectory in your current
|
||||
directory. (If you don't have shell access on your Web server, you
|
||||
may have to unpack the tarball on your local computer and FTP the
|
||||
files to the server.)
|
||||
|
||||
2. Move the tarball to a directory of your choosing in your Web root
|
||||
directory. Usually something like this will work:
|
||||
|
||||
mv gnusocial-x.y.z /var/www/gnusocial
|
||||
|
||||
This will often make your GNU Social instance available in the gnusocial
|
||||
path of your server, like "http://example.net/gnusocial". "social" or
|
||||
"blog" might also be good path names. If you know how to configure
|
||||
virtual hosts on your web server, you can try setting up
|
||||
"http://social.example.net/" or the like.
|
||||
|
||||
If you have "rewrite" support on your webserver, and you should,
|
||||
then please enable this in order to make full use of your site. This
|
||||
will enable "Fancy URL" support, which you can read more about if you
|
||||
scroll down a bit in this document.
|
||||
|
||||
3. Make your target directory writeable by the Web server.
|
||||
|
||||
chmod a+w /var/www/gnusocial/
|
||||
|
||||
On some systems, this will probably work:
|
||||
|
||||
chgrp www-data /var/www/gnusocial/
|
||||
chmod g+w /var/www/gnusocial/
|
||||
|
||||
If your Web server runs as another user besides "www-data", try
|
||||
that user's default group instead. As a last resort, you can create
|
||||
a new group like "gnusocial" and add the Web server's user to the group.
|
||||
|
||||
4. You should also take this moment to make your avatar, background, and
|
||||
file subdirectories writeable by the Web server. An insecure way to do
|
||||
this is:
|
||||
|
||||
chmod a+w /var/www/gnusocial/avatar
|
||||
chmod a+w /var/www/gnusocial/background
|
||||
chmod a+w /var/www/gnusocial/file
|
||||
|
||||
You can also make the avatar, background, and file directories
|
||||
writeable by the Web server group, as noted above.
|
||||
|
||||
5. Create a database to hold your site data. Something like this
|
||||
should work:
|
||||
|
||||
mysqladmin -u "root" --password="rootpassword" create gnusocial
|
||||
|
||||
Note that GNU Social should have its own database; you should not share
|
||||
the database with another program. You can name it whatever you want,
|
||||
though.
|
||||
|
||||
(If you don't have shell access to your server, you may need to use
|
||||
a tool like phpMyAdmin to create a database. Check your hosting
|
||||
service's documentation for how to create a new MariaDB database.)
|
||||
|
||||
6. Create a new database account that GNU Social will use to access the
|
||||
database. If you have shell access, this will probably work from the
|
||||
MariaDB shell:
|
||||
|
||||
GRANT ALL on gnusocial.*
|
||||
TO 'gnusocial'@'localhost'
|
||||
IDENTIFIED BY 'agoodpassword';
|
||||
|
||||
You should change the user identifier 'gnusocial' and 'agoodpassword'
|
||||
to your preferred new database username and password. You may want to
|
||||
test logging in to MariaDB as this new user.
|
||||
|
||||
7. In a browser, navigate to the GNU Social install script; something like:
|
||||
|
||||
http://social.example.net/install.php
|
||||
|
||||
Enter the database connection information and your site name. The
|
||||
install program will configure your site and install the initial,
|
||||
almost-empty database.
|
||||
|
||||
8. You should now be able to navigate to your social site's main directory
|
||||
and see the "Public Timeline", which will probably be empty. You can
|
||||
now register new user, post some notices, edit your profile, etc.
|
||||
|
||||
Fancy URLs
|
||||
----------
|
||||
|
||||
By default, GNU Social will use URLs that include the main PHP program's
|
||||
name in them. For example, a user's home profile might be found at:
|
||||
|
||||
http://example.net/gnusocial/index.php/gnusocial/fred
|
||||
|
||||
On certain systems that don't support this kind of syntax, they'll
|
||||
look like this:
|
||||
|
||||
http://example.net/gnusocial/index.php?p=gnusocial/fred
|
||||
|
||||
It's possible to configure the software so it looks like this instead:
|
||||
|
||||
http://example.net/gnusocial/fred
|
||||
|
||||
These "fancy URLs" are more readable and memorable for users. To use
|
||||
fancy URLs, you must either have Apache 2.x with .htaccess enabled and
|
||||
mod_rewrite enabled, -OR- know how to configure "url redirection" in
|
||||
your server (like lighttpd or nginx).
|
||||
|
||||
1. Copy the htaccess.sample file to .htaccess in your StatusNet
|
||||
directory.
|
||||
|
||||
2. Change the "RewriteBase" in the new .htaccess file to be the URL path
|
||||
to your GNU Social installation on your server. Typically this will
|
||||
be the path to your GNU Social directory relative to your Web root.
|
||||
If you are installing it in the root directory, leave it as '/'.
|
||||
|
||||
3. Add, uncomment or change a line in your config.php file so it says:
|
||||
|
||||
$config['site']['fancy'] = true;
|
||||
|
||||
You should now be able to navigate to a "fancy" URL on your server,
|
||||
like:
|
||||
|
||||
http://example.net/gnusocial/main/register
|
||||
|
||||
If you changed your HTTP server configuration, you may need to restart
|
||||
the server first.
|
||||
|
||||
If it doesn't work, double-check that AllowOverride for the GNU Social
|
||||
directory is 'All' in your Apache configuration file. This is usually
|
||||
/etc/httpd.conf, /etc/apache/httpd.conf, or (on Debian and Ubuntu)
|
||||
/etc/apache2/sites-available/default. See the Apache documentation for
|
||||
.htaccess files for more details:
|
||||
|
||||
http://httpd.apache.org/docs/2.2/howto/htaccess.html
|
||||
|
||||
Also, check that mod_rewrite is installed and enabled:
|
||||
|
||||
http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html
|
||||
|
||||
Sphinx
|
||||
------
|
||||
|
||||
To use a Sphinx server to search users and notices, you'll need to
|
||||
enable the SphinxSearch plugin. Add to your config.php:
|
||||
|
||||
addPlugin('SphinxSearch');
|
||||
$config['sphinx']['server'] = 'searchhost.local';
|
||||
|
||||
You also need to install, compile and enable the sphinx pecl extension for
|
||||
php on the client side, which itself depends on the sphinx development files.
|
||||
|
||||
See plugins/SphinxSearch/README for more details and server setup.
|
||||
|
||||
SMS
|
||||
---
|
||||
|
||||
StatusNet supports a cheap-and-dirty system for sending update messages
|
||||
to mobile phones and for receiving updates from the mobile. Instead of
|
||||
sending through the SMS network itself, which is costly and requires
|
||||
buy-in from the wireless carriers, it simply piggybacks on the email
|
||||
gateways that many carriers provide to their customers. So, SMS
|
||||
configuration is essentially email configuration.
|
||||
|
||||
Each user sends to a made-up email address, which they keep a secret.
|
||||
Incoming email that is "From" the user's SMS email address, and "To"
|
||||
the users' secret email address on the site's domain, will be
|
||||
converted to a notice and stored in the DB.
|
||||
|
||||
For this to work, there *must* be a domain or sub-domain for which all
|
||||
(or most) incoming email can pass through the incoming mail filter.
|
||||
|
||||
1. Run the SQL script carrier.sql in your StatusNet database. This will
|
||||
usually work:
|
||||
|
||||
mysql -u "statusnetuser" --password="statusnetpassword" statusnet < db/carrier.sql
|
||||
|
||||
This will populate your database with a list of wireless carriers
|
||||
that support email SMS gateways.
|
||||
|
||||
2. Make sure the maildaemon.php file is executable:
|
||||
|
||||
chmod +x scripts/maildaemon.php
|
||||
|
||||
Note that "daemon" is kind of a misnomer here; the script is more
|
||||
of a filter than a daemon.
|
||||
|
||||
2. Edit /etc/aliases on your mail server and add the following line:
|
||||
|
||||
*: /path/to/statusnet/scripts/maildaemon.php
|
||||
|
||||
3. Run whatever code you need to to update your aliases database. For
|
||||
many mail servers (Postfix, Exim, Sendmail), this should work:
|
||||
|
||||
newaliases
|
||||
|
||||
You may need to restart your mail server for the new database to
|
||||
take effect.
|
||||
|
||||
4. Set the following in your config.php file:
|
||||
|
||||
$config['mail']['domain'] = 'yourdomain.example.net';
|
||||
|
||||
|
||||
|
||||
Queues and daemons
|
||||
------------------
|
||||
|
||||
Some activities that StatusNet needs to do, like broadcast OStatus, SMS,
|
||||
XMPP messages and TwitterBridge operations, can be 'queued' and done by
|
||||
off-line bots instead.
|
||||
|
||||
Two mechanisms are available to achieve offline operations:
|
||||
|
||||
* New embedded OpportunisticQM plugin, which is enabled by default
|
||||
* Legacy queuedaemon script, which can be enabled via config file.
|
||||
|
||||
### OpportunisticQM plugin
|
||||
|
||||
This plugin is enabled by default. It tries its best to do background
|
||||
job during regular HTTP requests, like API or HTML pages calls.
|
||||
|
||||
Since queueing system is enabled by default, notices to be broadcasted
|
||||
will be stored, by default, into DB (table queue_item).
|
||||
|
||||
Each time it can, OpportunisticQM will try to handle some of them.
|
||||
|
||||
This is a good solution whether you:
|
||||
|
||||
* have no access to command line (shared hosting)
|
||||
* do not want to deal with long-running PHP processes
|
||||
* run a low traffic GNU social instance
|
||||
|
||||
In other case, you really should consider enabling the queuedaemon for
|
||||
performance reasons. Background daemons are necessary anyway if you wish
|
||||
to use the Instant Messaging features such as communicating via XMPP.
|
||||
|
||||
### queuedaemon
|
||||
|
||||
If you want to use legacy queuedaemon, you must be able to run
|
||||
long-running offline processes, either on your main Web server or on
|
||||
another server you control. (Your other server will still need all the
|
||||
above prerequisites, with the exception of Apache.) Installing on a
|
||||
separate server is probably a good idea for high-volume sites.
|
||||
|
||||
1. You'll need the "CLI" (command-line interface) version of PHP
|
||||
installed on whatever server you use.
|
||||
|
||||
Modern PHP versions in some operating systems have disabled functions
|
||||
related to forking, which is required for daemons to operate. To make
|
||||
this work, make sure that your php-cli config (/etc/php5/cli/php.ini)
|
||||
does NOT have these functions listed under 'disable_functions':
|
||||
|
||||
* pcntl_fork, pcntl_wait, pcntl_wifexited, pcntl_wexitstatus,
|
||||
pcntl_wifsignaled, pcntl_wtermsig
|
||||
|
||||
Other recommended settings for optimal performance are:
|
||||
* mysqli.allow_persistent = On
|
||||
* mysqli.reconnect = On
|
||||
|
||||
2. If you're using a separate server for queues, install StatusNet
|
||||
somewhere on the server. You don't need to worry about the
|
||||
.htaccess file, but make sure that your config.php file is close
|
||||
to, or identical to, your Web server's version.
|
||||
|
||||
3. In your config.php files (both the Web server and the queues
|
||||
server!), set the following variable:
|
||||
|
||||
$config['queue']['enabled'] = true;
|
||||
$config['queue']['daemon'] = true;
|
||||
|
||||
You may also want to look at the 'daemon' section of this file for
|
||||
more daemon options. Note that if you set the 'user' and/or 'group'
|
||||
options, you'll need to create that user and/or group by hand.
|
||||
They're not created automatically.
|
||||
|
||||
4. On the queues server, run the command scripts/startdaemons.sh.
|
||||
|
||||
This will run the queue handlers:
|
||||
|
||||
* queuedaemon.php - polls for queued items for inbox processing and
|
||||
pushing out to OStatus, SMS, XMPP, etc.
|
||||
* imdaemon.php - if an IM plugin is enabled (like XMPP)
|
||||
* other daemons, like TwitterBridge ones, that you may have enabled
|
||||
|
||||
These daemons will automatically restart in most cases of failure
|
||||
including memory leaks (if a memory_limit is set), but may still die
|
||||
or behave oddly if they lose connections to the XMPP or queue servers.
|
||||
|
||||
It may be a good idea to use a daemon-monitoring service, like 'monit',
|
||||
to check their status and keep them running.
|
||||
|
||||
All the daemons write their process IDs (pids) to /var/run/ by
|
||||
default. This can be useful for starting, stopping, and monitoring the
|
||||
daemons. If you are running multiple sites on the same machine, it will
|
||||
be necessary to avoid collisions of these PID files by setting a site-
|
||||
specific directory in config.php:
|
||||
|
||||
$config['daemon']['piddir'] = __DIR__ . '/../run/';
|
||||
|
||||
It is also possible to use a STOMP server instead of our kind of hacky
|
||||
home-grown DB-based queue solution. This is strongly recommended for
|
||||
best response time, especially when using XMPP.
|
||||
|
||||
Themes
|
||||
------
|
||||
|
||||
Older themes (version 0.9.x and below) no longer work with StatusNet
|
||||
1.0.x, due to major changes in the site layout. We ship with three new
|
||||
themes for this version, 'neo', 'neo-blue' and 'neo-light'.
|
||||
|
||||
As of right now, your ability to change the theme is site-wide; users
|
||||
can't choose their own theme. Additionally, the only thing you can
|
||||
change in the theme is CSS stylesheets and some image files; you can't
|
||||
change the HTML output, like adding or removing menu items.
|
||||
|
||||
You can choose a theme using the $config['site']['theme'] element in
|
||||
the config.php file. See below for details.
|
||||
|
||||
You can add your own theme by making a sub-directory of the 'theme'
|
||||
subdirectory with the name of your theme. Each theme can have the
|
||||
following files:
|
||||
|
||||
display.css: a CSS2 file for "default" styling for all browsers.
|
||||
logo.png: a logo image for the site.
|
||||
default-avatar-profile.png: a 96x96 pixel image to use as the avatar for
|
||||
users who don't upload their own.
|
||||
default-avatar-stream.png: Ditto, but 48x48. For streams of notices.
|
||||
default-avatar-mini.png: Ditto ditto, but 24x24. For subscriptions
|
||||
listing on profile pages.
|
||||
|
||||
You may want to start by copying the files from the default theme to
|
||||
your own directory.
|
||||
|
||||
Translation
|
||||
-----------
|
||||
|
||||
Translations in StatusNet use the gettext system <http://www.gnu.org/software/gettext/>.
|
||||
Theoretically, you can add your own sub-directory to the locale/
|
||||
subdirectory to add a new language to your system. You'll need to
|
||||
compile the ".po" files into ".mo" files, however.
|
||||
|
||||
Contributions of translation information to StatusNet are very easy:
|
||||
you can use the Web interface at translatewiki.net to add one
|
||||
or a few or lots of new translations -- or even new languages. You can
|
||||
also download more up-to-date .po files there, if you so desire.
|
||||
|
||||
For info on helping with translations, see http://status.net/wiki/Translations
|
||||
|
||||
Backups
|
||||
-------
|
||||
|
||||
There is no built-in system for doing backups in StatusNet. You can make
|
||||
backups of a working StatusNet system by backing up the database and
|
||||
the Web directory. To backup the database use mysqldump <http://ur1.ca/7xo>
|
||||
and to backup the Web directory, try tar.
|
||||
|
||||
Private
|
||||
-------
|
||||
|
||||
The administrator can set the "private" flag for a site so that it's
|
||||
not visible to non-logged-in users. (This is the default for new installs of version 1.0!)
|
||||
|
||||
This might be useful for workgroups who want to share a social
|
||||
networking site for project management, but host it on a public
|
||||
server.
|
||||
|
||||
Total privacy is attempted but not guaranteed or ensured. Private sites
|
||||
currently don't work well with OStatus federation.
|
||||
|
||||
Access to file attachments can also be restricted to logged-in users only.
|
||||
|
||||
1. Add a directory outside the web root where your file uploads will be
|
||||
stored. Usually a command like this will work:
|
||||
|
||||
mkdir /var/www/statusnet-files
|
||||
|
||||
2. Make the file uploads directory writeable by the web server. An
|
||||
insecure way to do this is:
|
||||
|
||||
chmod a+x /var/www/statusnet-files
|
||||
|
||||
3. Tell StatusNet to use this directory for file uploads. Add a line
|
||||
like this to your config.php:
|
||||
|
||||
$config['attachments']['dir'] = '/var/www/statusnet-files';
|
|
@ -1,5 +0,0 @@
|
|||
GNU social
|
||||
=====
|
||||
|
||||
GNU social is a federated social network. For documentation, visit
|
||||
https://docs.gnusocial.rocks/ or view the files under docs/
|
126
Makefile
126
Makefile
|
@ -1,122 +1,18 @@
|
|||
# Warning: do not transform tabs to spaces in this file.
|
||||
|
||||
DIR=$(strip $(notdir $(CURDIR))) # Seems a bit hack-ish, but `basename` works differently
|
||||
all : translations
|
||||
|
||||
translate-container-name = $$(if docker container inspect $(1) > /dev/null 2>&1; then echo $(1); else echo $(1) | sed 'y/_/-/' ; fi)
|
||||
args = `arg="$(filter-out $@,$(MAKECMDGOALS))" && echo $${arg:-${1}}`
|
||||
core_mo = $(patsubst %.po,%.mo,$(wildcard locale/*/LC_MESSAGES/statusnet.po))
|
||||
plugin_mo = $(patsubst %.po,%.mo,$(wildcard plugins/*/locale/*/LC_MESSAGES/*.po))
|
||||
|
||||
%:
|
||||
@:
|
||||
translations : $(core_mo) $(plugin_mo)
|
||||
|
||||
.PHONY:
|
||||
@if ! docker info > /dev/null; then echo "Docker does not seem to be running"; exit 1; fi
|
||||
clean :
|
||||
rm -f $(core_mo) $(plugin_mo)
|
||||
|
||||
up: .PHONY
|
||||
docker-compose up -d
|
||||
updatepo :
|
||||
php scripts/update_po_templates.php --all
|
||||
|
||||
down: .PHONY
|
||||
docker-compose down
|
||||
%.mo : %.po
|
||||
msgfmt -o $@ $<
|
||||
|
||||
redis-shell:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_redis_1) sh -c 'redis-cli'
|
||||
|
||||
php-repl: .PHONY
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c '/var/www/social/bin/console psysh'
|
||||
|
||||
php-shell: .PHONY
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c 'cd /var/www/social; sh'
|
||||
|
||||
psql-shell: .PHONY
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_db_1) sh -c "psql -U postgres social"
|
||||
|
||||
database-force-nuke:
|
||||
docker stop $(call translate-container-name,$(strip $(DIR))_worker_1) \
|
||||
&& docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c "cd /var/www/social; bin/console doctrine:database:drop --force && bin/console doctrine:database:create && bin/console doctrine:schema:update --dump-sql --force && bin/console app:populate_initial_values" \
|
||||
&& docker-compose up -d
|
||||
|
||||
database-force-schema-update:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c "/var/www/social/bin/console doctrine:schema:update --dump-sql --force"
|
||||
|
||||
tooling-docker: .PHONY
|
||||
@cd docker/tooling && docker-compose up -d --build > /dev/null 2>&1
|
||||
|
||||
stop-tooling: .PHONY
|
||||
cd docker/tooling && docker-compose down
|
||||
|
||||
tooling-php-shell: tooling-docker
|
||||
docker exec -it $(call translate-container-name,tooling_php_1) sh
|
||||
|
||||
test-accesibility: tooling-docker
|
||||
cd docker/tooling && docker-compose run pa11y /accessibility.sh
|
||||
|
||||
test: tooling-docker
|
||||
docker exec $(call translate-container-name,tooling_php_1) /var/tooling/coverage.sh $(call args,'')
|
||||
|
||||
cs-fixer: tooling-docker
|
||||
@bin/php-cs-fixer $${CS_FIXER_FILE}
|
||||
|
||||
doc-check: tooling-docker
|
||||
bin/php-doc-check
|
||||
|
||||
phpstan: tooling-docker
|
||||
bin/phpstan
|
||||
|
||||
remove-var:
|
||||
rm -rf var/*
|
||||
|
||||
remove-file:
|
||||
sudo rm -rf file/*
|
||||
|
||||
flush-redis-cache:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_redis_1) sh -c 'redis-cli flushall'
|
||||
|
||||
install-plugins:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) /var/www/social/bin/install_plugins.sh
|
||||
|
||||
update-dependencies:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c 'cd /var/www/social && composer update'
|
||||
|
||||
update-autocode:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) sh -c 'cd /var/www/social && bin/update_autocode'
|
||||
|
||||
backup-actors:
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_db_1) \
|
||||
sh -c 'su postgres -c "mkdir -p /tmp/backup"' && \
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) \
|
||||
sh -c "cd /var/www/social && bin/console doctrine:query:sql \"\
|
||||
copy actor to '/tmp/backup/actor.csv';\
|
||||
copy local_user to '/tmp/backup/local_user.csv';\
|
||||
copy local_group to '/tmp/backup/local_group.csv';\
|
||||
\
|
||||
copy activitypub_actor to '/tmp/backup/ap_actor.csv';\
|
||||
copy activitypub_rsa to '/tmp/backup/ap_rsa.csv';\
|
||||
\
|
||||
copy actor_subscription to '/tmp/backup/actor_subscription.csv';\
|
||||
copy group_member to '/tmp/backup/group_member.csv';\
|
||||
\
|
||||
copy feed to '/tmp/backup/feed.csv';\
|
||||
copy (SELECT 'ALTER SEQUENCE ' || c.relname || ' RESTART WITH ' || nextval(c.relname::regclass) || ';'\
|
||||
FROM pg_class c WHERE c.relkind = 'S') to '/tmp/backup/sequences';\"" && \
|
||||
mkdir -p /tmp/social-sql-backup && \
|
||||
docker cp $(call translate-container-name,$(strip $(DIR))_db_1):/tmp/backup/. /tmp/social-sql-backup
|
||||
|
||||
restore-actors:
|
||||
docker cp /tmp/social-sql-backup/. $(call translate-container-name,$(strip $(DIR))_db_1):/tmp/backup
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_db_1) sh -c 'chown postgres /tmp/backup' && \
|
||||
docker exec -it $(call translate-container-name,$(strip $(DIR))_php_1) \
|
||||
sh -c "cd /var/www/social && bin/console doctrine:query:sql \"\
|
||||
copy actor from '/tmp/backup/actor.csv';\
|
||||
copy local_user from '/tmp/backup/local_user.csv';\
|
||||
copy local_group from '/tmp/backup/local_group.csv';\
|
||||
\
|
||||
copy activitypub_actor from '/tmp/backup/ap_actor.csv';\
|
||||
copy activitypub_rsa from '/tmp/backup/ap_rsa.csv';\
|
||||
\
|
||||
copy actor_subscription from '/tmp/backup/actor_subscription.csv';\
|
||||
copy group_member from '/tmp/backup/group_member.csv';\
|
||||
\
|
||||
copy feed from '/tmp/backup/feed.csv';\
|
||||
`cat /tmp/social-sql-backup/sequences`\""
|
||||
|
||||
force-nuke-everything: down remove-var remove-file up flush-redis-cache database-force-nuke install-plugins
|
||||
|
||||
force-delete-content: backup-actors force-nuke-everything restore-actors
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
Plugins
|
||||
=======
|
||||
|
||||
Beginning with the 0.7.x branch, StatusNet has supported a simple but
|
||||
powerful plugin architecture. Important events in the code are named,
|
||||
like 'StartNoticeSave', and other software can register interest
|
||||
in those events. When the events happen, the other software is called
|
||||
and has a choice of accepting or rejecting the events.
|
||||
|
||||
In the simplest case, you can add a function to config.php and use the
|
||||
Event::addHandler() function to hook an event:
|
||||
|
||||
function AddGoogleLink($action)
|
||||
{
|
||||
$action->menuItem('http://www.google.com/', _('Google'), _('Search engine'));
|
||||
return true;
|
||||
}
|
||||
|
||||
Event::addHandler('EndPrimaryNav', 'AddGoogleLink');
|
||||
|
||||
This adds a menu item to the end of the main navigation menu. You can
|
||||
see the list of existing events, and parameters that handlers must
|
||||
implement, in EVENTS.txt.
|
||||
|
||||
The Plugin class in lib/plugin.php makes it easier to write more
|
||||
complex plugins. Sub-classes can just create methods named
|
||||
'onEventName', where 'EventName' is the name of the event (case
|
||||
matters!). These methods will be automatically registered as event
|
||||
handlers by the Plugin constructor (which you must call from your own
|
||||
class's constructor).
|
||||
|
||||
Several example plugins are included in the plugins/ directory. You
|
||||
can enable a plugin with the following line in config.php:
|
||||
|
||||
addPlugin('Example', array('param1' => 'value1',
|
||||
'param2' => 'value2'));
|
||||
|
||||
This will look for and load files named 'ExamplePlugin.php' or
|
||||
'Example/ExamplePlugin.php' either in the plugins/ directory (for
|
||||
plugins that ship with StatusNet) or in the local/ directory (for
|
||||
plugins you write yourself or that you get from somewhere else) or
|
||||
local/plugins/.
|
||||
|
||||
Plugins are documented in their own directories.
|
|
@ -0,0 +1,247 @@
|
|||
# GNU social 1.1.3
|
||||
February 2015-02-27
|
||||
|
||||
(c) Free Software Foundation, Inc
|
||||
(c) StatusNet, Inc
|
||||
|
||||
This is the README file for GNU social, the free
|
||||
software social networking platform. It includes
|
||||
general information about the software and the
|
||||
project.
|
||||
|
||||
Some other files to review:
|
||||
|
||||
- INSTALL: instructions on how to install the software.
|
||||
- UPGRADE: upgrading from earlier versions
|
||||
- CONFIGURE: configuration options in gruesome detail.
|
||||
- PLUGINS.txt: how to install and configure plugins.
|
||||
- EVENTS.txt: events supported by the plugin system
|
||||
- COPYING: full text of the software license
|
||||
|
||||
Information on using GNU social can be found in
|
||||
the "doc" subdirectory or in the "help" section
|
||||
on-line, or you can catch us on IRC in #social on
|
||||
the freenode network.
|
||||
|
||||
## About
|
||||
|
||||
GNU social is a free social networking
|
||||
platform. It helps people in a community, company
|
||||
or group to exchange short status updates, do
|
||||
polls, announce events, or other social activities
|
||||
(and you can add more!). Users can choose which
|
||||
people to "follow" and receive only their friends'
|
||||
or colleagues' status messages. It provides a
|
||||
similar service to sites like Twitter, Google+ or
|
||||
Facebook, but is much more awesome.
|
||||
|
||||
With a little work, status messages can be sent to
|
||||
mobile phones, instant messenger programs (using
|
||||
XMPP), and specially-designed desktop clients that
|
||||
support the Twitter API.
|
||||
|
||||
GNU social supports an open standard called
|
||||
OStatus <https://www.w3.org/community/ostatus/> that lets users in
|
||||
different networks follow each other. It enables a
|
||||
distributed social network spread all across the
|
||||
Web.
|
||||
|
||||
GNU social was originally developed as "StatusNet" by
|
||||
StatusNet, Inc. with Evan Prodromou as lead developer.
|
||||
|
||||
It is shared with you in hope that you too make an
|
||||
service available to your users. To learn more,
|
||||
please see the Open Software Service Definition
|
||||
1.1: <http://www.opendefinition.org/ossd>
|
||||
|
||||
### License
|
||||
|
||||
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, in the file "COPYING". If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
IMPORTANT NOTE: The GNU Affero General Public License (AGPL) has
|
||||
*different requirements* from the "regular" GPL. In particular, if
|
||||
you make modifications to the GNU social source code on your server,
|
||||
you *MUST MAKE AVAILABLE* the modified version of the source code
|
||||
to your users under the same license. This is a legal requirement
|
||||
of using the software, and if you do not wish to share your
|
||||
modifications, *YOU MAY NOT INSTALL GNU SOCIAL*.
|
||||
|
||||
Documentation in the /doc-src/ directory is available under the
|
||||
Creative Commons Attribution 3.0 Unported license, with attribution to
|
||||
"GNU social". See <http://creativecommons.org/licenses/by/3.0/> for details.
|
||||
|
||||
CSS and images in the /theme/ directory are available under the
|
||||
Creative Commons Attribution 3.0 Unported license, with attribution to
|
||||
"GNU social". See <http://creativecommons.org/licenses/by/3.0/> for details.
|
||||
|
||||
Our understanding and intention is that if you add your own theme that
|
||||
uses only CSS and images, those files are not subject to the copyleft
|
||||
requirements of the Affero General Public License 3.0. See
|
||||
<http://wordpress.org/news/2009/07/themes-are-gpl-too/>. This is not
|
||||
legal advice; consult your lawyer.
|
||||
|
||||
Additional library software has been made available in the 'extlib'
|
||||
directory. All of it is Free Software and can be distributed under
|
||||
liberal terms, but those terms may differ in detail from the AGPL's
|
||||
particulars. See each package's license file in the extlib directory
|
||||
for additional terms.
|
||||
|
||||
## New this version
|
||||
|
||||
This is a security fix and bug fix release since 1.1.3-beta2.
|
||||
All 1.1.x sites should upgrade to this version.
|
||||
|
||||
So far it includes the following changes:
|
||||
|
||||
- XSS security fix (thanks Simon Waters, <https://www.surevine.com/>)
|
||||
- Many improvements to ease adoption of the Qvitter front-end <https://github.com/hannesmannerheim/qvitter>
|
||||
- Protocol adaptions for improved performance and stability
|
||||
- Backing up a user's account now appears to work as it should
|
||||
|
||||
Upgrades from _StatusNet_ 1.1.1 will also experience these improvements:
|
||||
|
||||
- Fixes for SQL injection errors in profile lists.
|
||||
- Improved ActivityStreams JSON representation of activities and objects.
|
||||
- Upgrade to the Twitter 1.1 API.
|
||||
- More robust handling of errors in distribution.
|
||||
- Fix error in OStatus subscription for remote groups.
|
||||
- Fix error in XMPP distribution.
|
||||
- Tracking of conversation URI metadata (more coherent convos)
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
The primary output for GNU social is syslog,
|
||||
unless you configured a separate logfile. This is
|
||||
probably the first place to look if you're getting
|
||||
weird behaviour from GNU social.
|
||||
|
||||
If you're tracking the unstable version of
|
||||
GNU social in the git repository (see below), and you
|
||||
get a compilation error ("unexpected T_STRING") in
|
||||
the browser, check to see that you don't have any
|
||||
conflicts in your code.
|
||||
|
||||
### Unstable version
|
||||
|
||||
If you're adventurous or impatient, you may want
|
||||
to install the development version of GNU social.
|
||||
To get it, use the git version control tool
|
||||
<http://git-scm.com/> like so:
|
||||
|
||||
git clone git@gitorious.org:social/mainline.git
|
||||
|
||||
In the current phase of development it is probably
|
||||
recommended to use git as a means to stay up to date
|
||||
with the source code. You can choose between these
|
||||
branches:
|
||||
- 1.1.x "stable", few updates, well tested code
|
||||
- master "testing", more updates, usually working well
|
||||
- nightly "unstable", most updates, not always working
|
||||
|
||||
To keep it up-to-date, use 'git pull'. Watch for conflicts!
|
||||
|
||||
## Further information
|
||||
|
||||
There are several ways to get more information about GNU social.
|
||||
|
||||
* The #social IRC channel on freenode.net <https://www.freenode.net/>.
|
||||
* The unofficial XMPP room linked to IRC on <xmpp:gnusocial@conference.bka.li>
|
||||
* The GNU social website <https://gnu.io/social/>
|
||||
* Following us on GNU social -- <https://quitter.se/gnusocial>
|
||||
|
||||
* GNU social has a bug tracker for any defects you may find, or ideas for
|
||||
making things better. <https://bugz.foocorp.net/>
|
||||
* Patches are welcome, preferrably to our repository on Gitorious. <https://gitorious.org/social/mainline>
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
The following is an incomplete list of developers
|
||||
who've worked on GNU social, or its predecessors
|
||||
StatusNet and Free Social. Apologies for any
|
||||
oversight; please let mattl@gnu.org know if
|
||||
anyone's been overlooked in error.
|
||||
|
||||
## Project Founders
|
||||
|
||||
* Matt Lee (GNU social)
|
||||
* Evan Prodromou (StatusNet)
|
||||
* Mikael Nordfeldth (Free Social)
|
||||
|
||||
Thanks to all of the StatusNet developers:
|
||||
|
||||
* Zach Copley, StatusNet, Inc.
|
||||
* Earle Martin, StatusNet, Inc.
|
||||
* Marie-Claude Doyon, designer, StatusNet, Inc.
|
||||
* Sarven Capadisli, StatusNet, Inc.
|
||||
* Robin Millette, StatusNet, Inc.
|
||||
* Ciaran Gultnieks
|
||||
* Michael Landers
|
||||
* Ori Avtalion
|
||||
* Garret Buell
|
||||
* Mike Cochrane
|
||||
* Matthew Gregg
|
||||
* Florian Biree
|
||||
* Erik Stambaugh
|
||||
* 'drry'
|
||||
* Gina Haeussge
|
||||
* Tryggvi Björgvinsson
|
||||
* Adrian Lang
|
||||
* Ori Avtalion
|
||||
* Meitar Moscovitz
|
||||
* Ken Sheppardson (Trac server, man-about-town)
|
||||
* Tiago 'gouki' Faria (i18n manager)
|
||||
* Sean Murphy
|
||||
* Leslie Michael Orchard
|
||||
* Eric Helgeson
|
||||
* Ken Sedgwick
|
||||
* Brian Hendrickson
|
||||
* Tobias Diekershoff
|
||||
* Dan Moore
|
||||
* Fil
|
||||
* Jeff Mitchell
|
||||
* Brenda Wallace
|
||||
* Jeffery To
|
||||
* Federico Marani
|
||||
* mEDI
|
||||
* Brett Taylor
|
||||
* Brigitte Schuster
|
||||
* Siebrand Mazeland and the amazing volunteer translators at translatewiki.net
|
||||
* Brion Vibber, StatusNet, Inc.
|
||||
* James Walker, StatusNet, Inc.
|
||||
* Samantha Doherty, designer, StatusNet, Inc.
|
||||
* Simon Waters, Surevine
|
||||
* Joshua Judson Rosen (rozzin)
|
||||
|
||||
### Extra special thanks to the GNU socialites
|
||||
|
||||
* Craig Andrews
|
||||
* Donald Robertson
|
||||
* Deb Nicholson
|
||||
* Ian Denhart
|
||||
* Steven DuBois
|
||||
* Blaine Cook
|
||||
* Henry Story
|
||||
* Melvin Carvalho
|
||||
|
||||
Thanks also to the developers of our upstream
|
||||
library code and to the thousands of people who
|
||||
have tried out GNU social, told their friends, and
|
||||
built the fediverse network to what it is today.
|
||||
|
||||
### License help from
|
||||
|
||||
* Bradley M. Kuhn
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
Things to be done
|
||||
=================
|
||||
|
||||
* Create a theme for GNU social
|
||||
|
||||
* Create a set of plugins to give StatusNet a more social-network UI
|
||||
|
||||
* Work on improvements for annoying things in StatusNet (ie. no
|
||||
redirect to login page when you need to be logged in, etc)
|
||||
|
||||
* Work on adding further Activities, such as sharing photos/video,
|
||||
events, UI for managing relationships.
|
|
@ -0,0 +1,99 @@
|
|||
Upgrading
|
||||
=========
|
||||
|
||||
StatusNet 1.1.1 to GNU social
|
||||
-----------------------------
|
||||
|
||||
We cannot support migrating from any other version of StatusNet than
|
||||
1.1.1. If you are running a StatusNet version lower than this, please
|
||||
follow the upgrade procedures for each respective StatusNet version.
|
||||
|
||||
You are now running StatusNet 1.1.1 and want to migrate to GNU social.
|
||||
Beware there may be changes in minimum required version of PHP and the
|
||||
modules used, so double-check the INSTALL file's requirements list.
|
||||
|
||||
Before you begin: Make backups. Always make backups. Of your entire
|
||||
directory structure and the database too. All tables. All data. Alles.
|
||||
|
||||
0. Stop your queue daemons 'php scripts/stopdaemon.php' should do it.
|
||||
Not everyone runs queue daemons, but the above command won't hurt.
|
||||
|
||||
1. Unpack your GNU social code to a fresh directory.
|
||||
|
||||
2. Synchronize your local files to the GNU social directory. These
|
||||
will be the local files such as avatars, config and files:
|
||||
|
||||
avatar/*
|
||||
background/*
|
||||
file/*
|
||||
local/*
|
||||
.htaccess
|
||||
config.php
|
||||
|
||||
3. Replace your old StatusNet directory with the new GNU social
|
||||
directory in your webserver root.
|
||||
|
||||
4. Run the upgrade script: 'php scripts/upgrade.php'
|
||||
|
||||
5. Start your queue daemons: 'php scripts/startdaemons.php'
|
||||
|
||||
6. Report any issues at https://bugz.foocorp.net/ (tag GNU social)
|
||||
|
||||
|
||||
Legacy StatusNet instructions
|
||||
-----------------------------
|
||||
|
||||
These instructions are here for historical and perhaps informational
|
||||
purposes.
|
||||
|
||||
If you've been using StatusNet 1.0 or lower, or if you've
|
||||
been tracking the "git" version of the software, you will probably
|
||||
want to upgrade and keep your existing data. Try these step-by-step
|
||||
instructions; read to the end first before trying them.
|
||||
|
||||
0. Download StatusNet and set up all the prerequisites as if you were
|
||||
doing a new install.
|
||||
1. Make backups of both your database and your Web directory. UNDER NO
|
||||
CIRCUMSTANCES should you try to do an upgrade without a known-good
|
||||
backup. You have been warned.
|
||||
2. Shut down Web access to your site, either by turning off your Web
|
||||
server or by redirecting all pages to a "sorry, under maintenance"
|
||||
page.
|
||||
3. Shut down XMPP access to your site, typically by shutting down the
|
||||
xmppdaemon.php process and all other daemons that you're running.
|
||||
If you've got "monit" or "cron" automatically restarting your
|
||||
daemons, make sure to turn that off, too.
|
||||
4. Shut down SMS and email access to your site. The easy way to do
|
||||
this is to comment out the line piping incoming email to your
|
||||
maildaemon.php file, and running something like "newaliases".
|
||||
5. Once all writing processes to your site are turned off, make a
|
||||
final backup of the Web directory and database.
|
||||
6. Move your StatusNet directory to a backup spot, like "statusnet.bak".
|
||||
7. Unpack your StatusNet 1.1.1 tarball and move it to "statusnet" or
|
||||
wherever your code used to be.
|
||||
8. Copy the config.php file and the contents of the avatar/, background/,
|
||||
file/, and local/ subdirectories from your old directory to your new
|
||||
directory.
|
||||
9. Copy htaccess.sample to .htaccess in the new directory. Change the
|
||||
RewriteBase to use the correct path.
|
||||
10. Upgrade the database.
|
||||
|
||||
NOTE: this step is destructive and cannot be
|
||||
reversed. YOU CAN EASILY DESTROY YOUR SITE WITH THIS STEP. Don't
|
||||
do it without a known-good backup!
|
||||
|
||||
In your new StatusNet 1.1.1 directory and AFTER YOU MAKE A
|
||||
BACKUP run the upgrade.php script like this:
|
||||
|
||||
php ./scripts/upgrade.php
|
||||
|
||||
11. Use mysql or psql client to log into your database and make sure that
|
||||
the notice, user, profile, subscription etc. tables are non-empty.
|
||||
12. Turn back on the Web server, and check that things still work.
|
||||
13. Turn back on XMPP bots and email maildaemon.
|
||||
|
||||
NOTE: the 1.0.0 version of StatusNet changed the URLs for all admin
|
||||
panels from /admin/* to /panel/*. This now allows the (popular)
|
||||
username 'admin', but blocks the considerably less popular username
|
||||
'panel'. If you have an existing user named 'panel', you should rename
|
||||
them before upgrading.
|
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Site access administration panel
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category Settings
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Administer site access settings
|
||||
*
|
||||
* @category Admin
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AccessadminpanelAction extends AdminPanelAction
|
||||
{
|
||||
/**
|
||||
* Returns the page title
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
function title()
|
||||
{
|
||||
// TRANS: Page title for Access admin panel that allows configuring site access.
|
||||
return _('Access');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for using this form.
|
||||
*
|
||||
* @return string instructions
|
||||
*/
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Page notice.
|
||||
return _('Site access settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the site admin panel form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showForm()
|
||||
{
|
||||
$form = new AccessAdminPanelForm($this);
|
||||
$form->show();
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save settings from the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function saveSettings()
|
||||
{
|
||||
static $booleans = array('site' => array('private', 'inviteonly', 'closed'),
|
||||
'public' => array('localonly'));
|
||||
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
$values[$section][$setting] = ($this->boolean($setting)) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
$config = new Config();
|
||||
|
||||
$config->query('BEGIN');
|
||||
|
||||
foreach ($booleans as $section => $parts) {
|
||||
foreach ($parts as $setting) {
|
||||
Config::save($section, $setting, $values[$section][$setting]);
|
||||
}
|
||||
}
|
||||
|
||||
$config->query('COMMIT');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
class AccessAdminPanelForm extends AdminForm
|
||||
{
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return int ID of the form
|
||||
*/
|
||||
function id()
|
||||
{
|
||||
return 'form_site_admin_panel';
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string class of the form
|
||||
*/
|
||||
function formClass()
|
||||
{
|
||||
return 'form_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
function action()
|
||||
{
|
||||
return common_local_url('accessadminpanel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function formData()
|
||||
{
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_account_access'));
|
||||
// TRANS: Form legend for registration form.
|
||||
$this->out->element('legend', null, _('Registration'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
||||
$this->li();
|
||||
// TRANS: Checkbox instructions for admin setting "Invite only".
|
||||
$instructions = _('Make registration invitation only.');
|
||||
// TRANS: Checkbox label for configuring site as invite only.
|
||||
$this->out->checkbox('inviteonly', _('Invite only'),
|
||||
(bool) $this->value('inviteonly'),
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
// TRANS: Checkbox instructions for admin setting "Closed" (no new registrations).
|
||||
$instructions = _('Disable new registrations.');
|
||||
// TRANS: Checkbox label for disabling new user registrations.
|
||||
$this->out->checkbox('closed', _('Closed'),
|
||||
(bool) $this->value('closed'),
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
|
||||
|
||||
// Public access settings (login requirements for feeds etc.)
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_public_access'));
|
||||
// TRANS: Form legend for registration form.
|
||||
$this->out->element('legend', null, _('Feed access'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->li();
|
||||
// TRANS: Checkbox instructions for admin setting "Private".
|
||||
$instructions = _('Prohibit anonymous users (not logged in) from viewing site?');
|
||||
// TRANS: Checkbox label for prohibiting anonymous users from viewing site.
|
||||
$this->out->checkbox('private', _m('LABEL', 'Private'),
|
||||
(bool) $this->value('private'),
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
// TRANS: Description of the full network notice stream views..
|
||||
$instructions = _('The full network view includes (public) remote notices which may be unrelated to local conversations.');
|
||||
// TRANS: Checkbox label for hiding remote network posts if they have not been interacted with locally.
|
||||
$this->out->checkbox('localonly', _('Restrict full network view to accounts'),
|
||||
(bool) $this->value('localonly', 'public'),
|
||||
$instructions);
|
||||
$this->unli();
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function formActions()
|
||||
{
|
||||
// TRANS: Button title to save access settings in site admin panel.
|
||||
$title = _('Save access settings.');
|
||||
// TRANS: Button text to save access settings in site admin panel.
|
||||
$this->out->submit('submit', _m('BUTTON', 'Save'), 'submit', null, $title);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008-2010, StatusNet, Inc.
|
||||
*
|
||||
* Action to add a people tag to a user.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/togglepeopletag.php';
|
||||
|
||||
/**
|
||||
*
|
||||
* Action to tag a profile with a single tag.
|
||||
*
|
||||
* Takes parameters:
|
||||
*
|
||||
* - tagged: the ID of the profile being tagged
|
||||
* - token: session token to prevent CSRF attacks
|
||||
* - ajax: boolean; whether to return Ajax or full-browser results
|
||||
* - peopletag_id: the ID of the tag being used
|
||||
*
|
||||
* Only works if the current user is logged in.
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AddpeopletagAction extends Action
|
||||
{
|
||||
var $user;
|
||||
var $tagged;
|
||||
var $peopletag;
|
||||
|
||||
/**
|
||||
* Check pre-requisites and instantiate attributes
|
||||
*
|
||||
* @param Array $args array of arguments (URL, GET, POST)
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// CSRF protection
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
// TRANS: Client error displayed when the session token does not match or is not given.
|
||||
$this->clientError(_('There was a problem with your session token.'.
|
||||
' Try again, please.'));
|
||||
}
|
||||
|
||||
// Only for logged-in users
|
||||
|
||||
$this->user = common_current_user();
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Error message displayed when trying to perform an action that requires a logged in user.
|
||||
$this->clientError(_('Not logged in.'));
|
||||
}
|
||||
|
||||
// Profile to subscribe to
|
||||
|
||||
$tagged_id = $this->arg('tagged');
|
||||
|
||||
$this->tagged = Profile::getKV('id', $tagged_id);
|
||||
|
||||
if (empty($this->tagged)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing profile.
|
||||
$this->clientError(_('No such profile.'));
|
||||
}
|
||||
|
||||
$id = $this->arg('peopletag_id');
|
||||
$this->peopletag = Profile_list::getKV('id', $id);
|
||||
|
||||
if (empty($this->peopletag)) {
|
||||
// TRANS: Client error displayed trying to reference a non-existing list.
|
||||
$this->clientError(_('No such list.'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request
|
||||
*
|
||||
* Does the tagging and returns results.
|
||||
*
|
||||
* @param Array $args unused.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
// Throws exception on error
|
||||
$ptag = Profile_tag::setTag($this->user->id, $this->tagged->id,
|
||||
$this->peopletag->tag);
|
||||
|
||||
if (!$ptag) {
|
||||
$user = User::getKV('id', $id);
|
||||
if ($user) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when an unknown error occurs when adding a user to a list.
|
||||
// TRANS: %s is a username.
|
||||
sprintf(_('There was an unexpected error while listing %s.'),
|
||||
$user->nickname));
|
||||
} else {
|
||||
// TRANS: Client error displayed when an unknown error occurs when adding a user to a list.
|
||||
// TRANS: %s is a profile URL.
|
||||
$this->clientError(sprintf(_('There was a problem listing %s. ' .
|
||||
'The remote server is probably not responding correctly. ' .
|
||||
'Please try retrying later.'), $this->profile->profileurl));
|
||||
}
|
||||
}
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title after adding a user to a list.
|
||||
$this->element('title', null, _m('TITLE','Listed'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$unsubscribe = new UntagButton($this, $this->tagged, $this->peopletag);
|
||||
$unsubscribe->show();
|
||||
$this->elementEnd('body');
|
||||
$this->endHTML();
|
||||
} else {
|
||||
$url = common_local_url('subscriptions',
|
||||
array('nickname' => $this->user->nickname));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008-2011, StatusNet, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* @category Actions
|
||||
* @package Actions
|
||||
* @author Adrian Lang <mail@adrianlang.de>
|
||||
* @author Brenda Wallace <shiny@cpan.org>
|
||||
* @author Brion Vibber <brion@pobox.com>
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Meitar Moscovitz <meitarm@gmail.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <millette@status.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @author Siebrand Mazeland <s.mazeland@xs4all.nl>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license GNU Affero General Public License http://www.gnu.org/licenses/
|
||||
* @link http://status.net
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); }
|
||||
|
||||
class AllAction extends ProfileAction
|
||||
{
|
||||
var $notice;
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
if (!empty($user) && $user->streamModeOnly()) {
|
||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||
} else {
|
||||
$stream = new ThreadingInboxNoticeStream($this->target, $this->scoped);
|
||||
}
|
||||
|
||||
$this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1);
|
||||
|
||||
if ($this->page > 1 && $this->notice->N == 0) {
|
||||
// TRANS: Client error when page not found (404).
|
||||
$this->clientError(_('No such page.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
if (!empty($this->scoped) && $this->scoped->id == $this->target->id) {
|
||||
// TRANS: Title of a user's own start page.
|
||||
return _('Home timeline');
|
||||
} else {
|
||||
// TRANS: Title of another user's start page.
|
||||
// TRANS: %s is the other user's name.
|
||||
return sprintf(_("%s's home timeline"), $this->target->getBestName());
|
||||
}
|
||||
}
|
||||
|
||||
function getFeeds()
|
||||
{
|
||||
return array(
|
||||
new Feed(Feed::JSON,
|
||||
common_local_url(
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'as',
|
||||
'id' => $this->target->nickname
|
||||
)
|
||||
),
|
||||
// TRANS: %s is user nickname.
|
||||
sprintf(_('Feed for friends of %s (Activity Streams JSON)'), $this->target->nickname)),
|
||||
new Feed(Feed::RSS1,
|
||||
common_local_url(
|
||||
'allrss', array(
|
||||
'nickname' =>
|
||||
$this->target->nickname)
|
||||
),
|
||||
// TRANS: %s is user nickname.
|
||||
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->target->nickname)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url(
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'rss',
|
||||
'id' => $this->target->nickname
|
||||
)
|
||||
),
|
||||
// TRANS: %s is user nickname.
|
||||
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->target->nickname)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url(
|
||||
'ApiTimelineFriends', array(
|
||||
'format' => 'atom',
|
||||
'id' => $this->target->nickname
|
||||
)
|
||||
),
|
||||
// TRANS: %s is user nickname.
|
||||
sprintf(_('Feed for friends of %s (Atom)'), $this->target->nickname))
|
||||
);
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
// TRANS: Empty list message. %s is a user nickname.
|
||||
$message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->target->nickname) . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
if ($this->target->id === $this->scoped->id) {
|
||||
// TRANS: Encouragement displayed on logged in user's empty timeline.
|
||||
// TRANS: This message contains Markdown links. Keep "](" together.
|
||||
$message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
|
||||
} else {
|
||||
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@".
|
||||
// TRANS: This message contains Markdown links. Keep "](" together.
|
||||
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to them](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->target->nickname, $this->target->nickname, '@' . $this->target->nickname);
|
||||
}
|
||||
} else {
|
||||
// TRANS: Encouragement displayed on empty timeline user pages for anonymous users.
|
||||
// TRANS: %s is a user nickname. This message contains Markdown links. Keep "](" together.
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to them.'), $this->target->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
if (Event::handle('StartShowAllContent', array($this))) {
|
||||
|
||||
$profile = null;
|
||||
|
||||
$current_user = common_current_user();
|
||||
|
||||
if (!empty($current_user)) {
|
||||
$profile = $current_user->getProfile();
|
||||
}
|
||||
|
||||
if (!empty($current_user) && $current_user->streamModeOnly()) {
|
||||
$nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));
|
||||
} else {
|
||||
$nl = new ThreadedNoticeList($this->notice, $this, $profile);
|
||||
}
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
|
||||
$this->pagination(
|
||||
$this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'all', array('nickname' => $this->target->nickname)
|
||||
);
|
||||
|
||||
Event::handle('EndShowAllContent', array($this));
|
||||
}
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
// Show invite button, as long as site isn't closed, and
|
||||
// we have a logged in user.
|
||||
if (common_config('invite', 'enabled') && !common_config('site', 'closed') && common_logged_in()) {
|
||||
if (!common_config('site', 'private')) {
|
||||
$ibs = new InviteButtonSection(
|
||||
$this,
|
||||
// TRANS: Button text for inviting more users to the StatusNet instance.
|
||||
// TRANS: Less business/enterprise-oriented language for public sites.
|
||||
_m('BUTTON', 'Send invite')
|
||||
);
|
||||
} else {
|
||||
$ibs = new InviteButtonSection($this);
|
||||
}
|
||||
$ibs->show();
|
||||
}
|
||||
// XXX: make this a little more convenient
|
||||
|
||||
if (!common_config('performance', 'high')) {
|
||||
$pop = new InboxTagCloudSection($this, $this->target);
|
||||
$pop->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadingInboxNoticeStream extends ThreadingNoticeStream
|
||||
{
|
||||
function __construct(Profile $target, Profile $scoped=null)
|
||||
{
|
||||
parent::__construct(new InboxNoticeStream($target, $scoped));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
/**
|
||||
* RSS feed for user and friends timeline action class.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <millette@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, StatusNet, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/rssaction.php';
|
||||
|
||||
/**
|
||||
* RSS feed for user and friends timeline.
|
||||
*
|
||||
* Formatting of RSS handled by Rss10Action
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <millette@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AllrssAction extends Rss10Action
|
||||
{
|
||||
var $user = null;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean false if user doesn't exist
|
||||
*
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$this->user = User::getKV('nickname', $nickname);
|
||||
|
||||
if (!$this->user) {
|
||||
// TRANS: Client error when user not found for an rss related action.
|
||||
$this->clientError(_('No such user.'));
|
||||
} else {
|
||||
$this->notices = $this->getNotices($this->limit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @param integer $limit max number of notices to return
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices($limit=0)
|
||||
{
|
||||
$stream = new InboxNoticeStream($this->user->getProfile());
|
||||
$notice = $stream->getNotices(0, $limit, null, null);
|
||||
|
||||
$notices = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get channel.
|
||||
*
|
||||
* @return array associative array on channel information
|
||||
*/
|
||||
function getChannel()
|
||||
{
|
||||
$user = $this->user;
|
||||
$c = array('url' => common_local_url('allrss',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
// TRANS: Message is used as link title. %s is a user nickname.
|
||||
'title' => sprintf(_('%s and friends'), $user->nickname),
|
||||
'link' => common_local_url('all',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
// TRANS: Message is used as link description. %1$s is a username, %2$s is a site name.
|
||||
'description' => sprintf(_('Updates from %1$s and friends on %2$s!'),
|
||||
$user->nickname, common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image.
|
||||
*
|
||||
* @return string user avatar URL or null
|
||||
*/
|
||||
function getImage()
|
||||
{
|
||||
$user = $this->user;
|
||||
$profile = $user->getProfile();
|
||||
if (!$profile) {
|
||||
return null;
|
||||
}
|
||||
return $profile->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Dummy action that emulates Twitter's rate limit status API resource
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Brion Vibber <brion@pobox.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Siebrand Mazeland <s.mazeland@xs4all.nl>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* We don't have a rate limit, but some clients check this method.
|
||||
* It always returns the same thing: 150 hits left.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Return some Twitter-ish data about API limits
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$reset = new DateTime();
|
||||
$reset->modify('+1 hour');
|
||||
|
||||
$this->initDocument($this->format);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->elementStart('hash');
|
||||
$this->element('remaining-hits', array('type' => 'integer'), 150);
|
||||
$this->element('hourly-limit', array('type' => 'integer'), 150);
|
||||
$this->element(
|
||||
'reset-time', array('type' => 'datetime'),
|
||||
common_date_iso8601($reset->format('r'))
|
||||
);
|
||||
$this->element(
|
||||
'reset_time_in_seconds',
|
||||
array('type' => 'integer'),
|
||||
strtotime('+1 hour')
|
||||
);
|
||||
$this->elementEnd('hash');
|
||||
} elseif ($this->format == 'json') {
|
||||
$out = array(
|
||||
'reset_time_in_seconds' => strtotime('+1 hour'),
|
||||
'remaining_hits' => 150,
|
||||
'hourly_limit' => 150,
|
||||
'reset_time' => common_date_rfc2822(
|
||||
$reset->format('r')
|
||||
)
|
||||
);
|
||||
print json_encode($out);
|
||||
}
|
||||
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Register account
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiAccountRegisterAction extends ApiAction
|
||||
{
|
||||
|
||||
/**
|
||||
* Has there been an error?
|
||||
*/
|
||||
var $error = null;
|
||||
|
||||
/**
|
||||
* Have we registered?
|
||||
*/
|
||||
var $registered = false;
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
protected $code = null; // invite code
|
||||
protected $invite = null; // invite to-be-stored
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$this->code = $this->trimmed('code');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$email = $this->trimmed('email');
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$bio = $this->trimmed('bio');
|
||||
$location = $this->trimmed('location');
|
||||
|
||||
// We don't trim these... whitespace is OK in a password!
|
||||
$password = $this->arg('password');
|
||||
$confirm = $this->arg('confirm');
|
||||
|
||||
if (empty($this->code)) {
|
||||
common_ensure_session();
|
||||
if (array_key_exists('invitecode', $_SESSION)) {
|
||||
$this->code = $_SESSION['invitecode'];
|
||||
}
|
||||
}
|
||||
|
||||
if (common_config('site', 'inviteonly') && empty($this->code)) {
|
||||
// TRANS: Client error displayed when trying to register to an invite-only site without an invitation.
|
||||
$this->clientError(_('Sorry, only invited people can register.'), 401);
|
||||
}
|
||||
|
||||
if (!empty($this->code)) {
|
||||
$this->invite = Invitation::getKV('code', $this->code);
|
||||
if (empty($this->invite)) {
|
||||
// TRANS: Client error displayed when trying to register to an invite-only site without a valid invitation.
|
||||
$this->clientError(_('Sorry, invalid invitation code.'), 401);
|
||||
}
|
||||
// Store this in case we need it
|
||||
common_ensure_session();
|
||||
$_SESSION['invitecode'] = $this->code;
|
||||
}
|
||||
|
||||
// Input scrubbing
|
||||
try {
|
||||
$nickname = Nickname::normalize($nickname, true);
|
||||
} catch (NicknameException $e) {
|
||||
// clientError handles Api exceptions with various formats and stuff
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
$email = common_canonical_email($email);
|
||||
|
||||
if ($email && !Validate::email($email, common_config('email', 'check_domain'))) {
|
||||
// TRANS: Form validation error displayed when trying to register without a valid e-mail address.
|
||||
$this->clientError(_('Not a valid email address.'), 400);
|
||||
} else if ($this->emailExists($email)) {
|
||||
// TRANS: Form validation error displayed when trying to register with an already registered e-mail address.
|
||||
$this->clientError(_('Email address already exists.'), 400);
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!common_valid_http_url($homepage)) {
|
||||
// TRANS: Form validation error displayed when trying to register with an invalid homepage URL.
|
||||
$this->clientError(_('Homepage is not a valid URL.'), 400);
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
// TRANS: Form validation error displayed when trying to register with a too long full name.
|
||||
$this->clientError(_('Full name is too long (maximum 255 characters).'), 400);
|
||||
} else if (Profile::bioTooLong($bio)) {
|
||||
// TRANS: Form validation error on registration page when providing too long a bio text.
|
||||
// TRANS: %d is the maximum number of characters for bio; used for plural.
|
||||
$this->clientError(sprintf(_m('Bio is too long (maximum %d character).',
|
||||
'Bio is too long (maximum %d characters).',
|
||||
Profile::maxBio()),
|
||||
Profile::maxBio()), 400);
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
// TRANS: Form validation error displayed when trying to register with a too long location.
|
||||
$this->clientError(_('Location is too long (maximum 255 characters).'), 400);
|
||||
} else if (strlen($password) < 6) {
|
||||
// TRANS: Form validation error displayed when trying to register with too short a password.
|
||||
$this->clientError(_('Password must be 6 or more characters.'), 400);
|
||||
} else if ($password != $confirm) {
|
||||
// TRANS: Form validation error displayed when trying to register with non-matching passwords.
|
||||
$this->clientError(_('Passwords do not match.'), 400);
|
||||
} else {
|
||||
|
||||
// annoy spammers
|
||||
sleep(7);
|
||||
|
||||
if ($user = User::register(array('nickname' => $nickname,
|
||||
'password' => $password,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'homepage' => $homepage,
|
||||
'bio' => $bio,
|
||||
'location' => $location,
|
||||
'code' => $this->code))) {
|
||||
if (!$user instanceof User) {
|
||||
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
|
||||
$this->clientError(_('Invalid username or password.'), 400);
|
||||
}
|
||||
|
||||
Event::handle('EndRegistrationTry', array($this));
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($this->twitterUserArray($user->getProfile()));
|
||||
$this->endDocument('json');
|
||||
|
||||
} else {
|
||||
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
|
||||
$this->clientError(_('Invalid username or password.'), 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the given email address already exist?
|
||||
*
|
||||
* Checks a canonical email address against the database.
|
||||
*
|
||||
* @param string $email email address to check
|
||||
*
|
||||
* @return boolean true if the address already exists
|
||||
*/
|
||||
function emailExists($email)
|
||||
{
|
||||
$email = common_canonical_email($email);
|
||||
if (!$email || strlen($email) == 0) {
|
||||
return false;
|
||||
}
|
||||
$user = User::getKV('email', $email);
|
||||
return is_object($user);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update a user's background color
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiAccountUpdateBackgroundColorAction extends ApiAuthAction
|
||||
{
|
||||
var $backgroundcolor = null;
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$this->backgroundcolor = $this->trimmed('backgroundcolor');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Try to save the user's colors in her design. Create a new design
|
||||
* if the user doesn't already have one.
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$validhex = preg_match('/^[a-f0-9]{6}$/i',$this->backgroundcolor);
|
||||
if ($validhex === false || $validhex == 0) {
|
||||
$this->clientError(_('Not a valid hex color.'), 400);
|
||||
}
|
||||
|
||||
// save the new color
|
||||
$original = clone($this->auth_user);
|
||||
$this->auth_user->backgroundcolor = $this->backgroundcolor;
|
||||
if (!$this->auth_user->update($original)) {
|
||||
$this->clientError(_('Error updating user.'), 404);
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->scoped, true);
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update the authenticating user notification channels
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Siebrand Mazeland <s.mazeland@xs4all.nl>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets which channel (device) StatusNet delivers updates to for
|
||||
* the authenticating user. Sending none as the device parameter
|
||||
* will disable IM and/or SMS updates.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$this->device = $this->trimmed('device');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* See which request params have been set, and update the user settings
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
|
||||
// Note: Twitter no longer supports IM
|
||||
|
||||
if (!in_array(strtolower($this->device), array('sms', 'im', 'none'))) {
|
||||
// TRANS: Client error displayed when no valid device parameter is provided for a user's delivery device setting.
|
||||
$this->clientError(_( 'You must specify a parameter named ' .
|
||||
'\'device\' with a value of one of: sms, im, none.' ));
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed when no existing user is provided for a user's delivery device setting.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$original = clone($this->user);
|
||||
|
||||
if (strtolower($this->device) == 'sms') {
|
||||
$this->user->smsnotify = true;
|
||||
} elseif (strtolower($this->device) == 'im') {
|
||||
//TODO IM is pluginized now, so what should we do?
|
||||
//Enable notifications for all IM plugins?
|
||||
//For now, don't do anything
|
||||
//$this->user->jabbernotify = true;
|
||||
} elseif (strtolower($this->device == 'none')) {
|
||||
$this->user->smsnotify = false;
|
||||
//TODO IM is pluginized now, so what should we do?
|
||||
//Disable notifications for all IM plugins?
|
||||
//For now, don't do anything
|
||||
//$this->user->jabbernotify = false;
|
||||
}
|
||||
|
||||
$result = $this->user->update($original);
|
||||
|
||||
if ($result === false) {
|
||||
common_log_db_error($this->user, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error displayed when a user's delivery device cannot be updated.
|
||||
$this->serverError(_('Could not update user.'));
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
$twitter_user = $this->twitterUserArray($profile, true);
|
||||
|
||||
// Note: this Twitter API method is retarded because it doesn't give
|
||||
// any success/failure information. Twitter's docs claim that the
|
||||
// notification field will change to reflect notification choice,
|
||||
// but that's not true; notification> is used to indicate
|
||||
// whether the auth user is following the user in question.
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update a user's link color
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiAccountUpdateLinkColorAction extends ApiAuthAction
|
||||
{
|
||||
var $linkcolor = null;
|
||||
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$this->linkcolor = $this->trimmed('linkcolor');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Try to save the user's colors in her design. Create a new design
|
||||
* if the user doesn't already have one.
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$validhex = preg_match('/^[a-f0-9]{6}$/i',$this->linkcolor);
|
||||
if ($validhex === false || $validhex == 0) {
|
||||
$this->clientError(_('Not a valid hex color.'), 400);
|
||||
}
|
||||
|
||||
// save the new color
|
||||
$original = clone($this->auth_user);
|
||||
$this->auth_user->linkcolor = $this->linkcolor;
|
||||
if (!$this->auth_user->update($original)) {
|
||||
$this->clientError(_('Error updating user.'), 400);
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->scoped, true);
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update the authenticating user's profile
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* API analog to the profile settings page
|
||||
* Only the parameters specified will be updated.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountUpdateProfileAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
|
||||
$this->name = $this->trimmed('name');
|
||||
$this->url = $this->trimmed('url');
|
||||
$this->location = $this->trimmed('location');
|
||||
$this->description = $this->trimmed('description');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* See which request params have been set, and update the profile
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed if a user could not be found.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
if (empty($profile)) {
|
||||
// TRANS: Error message displayed when referring to a user without a profile.
|
||||
$this->clientError(_('User has no profile.'));
|
||||
}
|
||||
|
||||
$original = clone($profile);
|
||||
|
||||
if (!empty($this->name)) {
|
||||
$profile->fullname = $this->name;
|
||||
}
|
||||
|
||||
if (!empty($this->url)) {
|
||||
$profile->homepage = $this->url;
|
||||
}
|
||||
|
||||
if (!empty($this->description)) {
|
||||
$profile->bio = $this->description;
|
||||
}
|
||||
|
||||
if (!empty($this->location)) {
|
||||
$profile->location = $this->location;
|
||||
|
||||
$loc = Location::fromName($this->location);
|
||||
|
||||
if (!empty($loc)) {
|
||||
$profile->lat = $loc->lat;
|
||||
$profile->lon = $loc->lon;
|
||||
$profile->location_id = $loc->location_id;
|
||||
$profile->location_ns = $loc->location_ns;
|
||||
}
|
||||
}
|
||||
|
||||
$result = $profile->update($original);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($profile, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error displayed if a user profile could not be saved.
|
||||
$this->serverError(_('Could not save profile.'));
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($profile, true);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update the authenticating user's profile image
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the authenticating user's profile image. Note that this API method
|
||||
* expects raw multipart data, not a URL to an image.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountUpdateProfileImageAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check whether the credentials are valid and output the result
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
// TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
|
||||
// TRANS: %s is the number of bytes of the CONTENT_LENGTH.
|
||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||
intval($_SERVER['CONTENT_LENGTH']));
|
||||
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed updating profile image without having a user object.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
try {
|
||||
$imagefile = ImageFile::fromUpload('image');
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage());
|
||||
}
|
||||
|
||||
$type = $imagefile->preferredType();
|
||||
$filename = Avatar::filename(
|
||||
$user->id,
|
||||
image_type_to_extension($type),
|
||||
null,
|
||||
'tmp'.common_timestamp()
|
||||
);
|
||||
|
||||
$filepath = Avatar::path($filename);
|
||||
|
||||
$imagefile->copyTo($filepath);
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
$profile->setOriginal($filename);
|
||||
|
||||
$twitter_user = $this->twitterUserArray($profile, true);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Test if supplied user credentials are valid.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a user's credentials. Returns an HTTP 200 OK response code and a
|
||||
* representation of the requesting user if authentication was successful;
|
||||
* returns a 401 status code and an error message if not.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAccountVerifyCredentialsAction extends ApiAuthAction
|
||||
{
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->auth_user->getProfile(), true);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* An AtomPub service document for a user
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows an AtomPub service document for a user
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiAtomServiceAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->user = $this->getTargetUser($this->arg('id'));
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed when making an Atom API request for an unknown user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the arguments. In our case, show a service document.
|
||||
*
|
||||
* @param Array $args unused.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
header('Content-Type: application/atomsvc+xml');
|
||||
|
||||
$this->startXML();
|
||||
$this->elementStart('service', array('xmlns' => 'http://www.w3.org/2007/app',
|
||||
'xmlns:atom' => 'http://www.w3.org/2005/Atom',
|
||||
'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/'));
|
||||
$this->elementStart('workspace');
|
||||
// TRANS: Title for Atom feed.
|
||||
$this->element('atom:title', null, _m('ATOM','Main'));
|
||||
$this->elementStart('collection',
|
||||
array('href' => common_local_url('ApiTimelineUser',
|
||||
array('id' => $this->user->id,
|
||||
'format' => 'atom'))));
|
||||
$this->element('atom:title',
|
||||
null,
|
||||
// TRANS: Title for Atom feed. %s is a user nickname.
|
||||
sprintf(_("%s timeline"),
|
||||
$this->user->nickname));
|
||||
$this->element('accept', null, 'application/atom+xml;type=entry');
|
||||
$this->element('activity:verb', null, ActivityVerb::POST);
|
||||
$this->elementEnd('collection');
|
||||
$this->elementStart('collection',
|
||||
array('href' => common_local_url('AtomPubSubscriptionFeed',
|
||||
array('subscriber' => $this->user->id))));
|
||||
$this->element('atom:title',
|
||||
null,
|
||||
// TRANS: Title for Atom feed with a user's subscriptions. %s is a user nickname.
|
||||
sprintf(_("%s subscriptions"),
|
||||
$this->user->nickname));
|
||||
$this->element('accept', null, 'application/atom+xml;type=entry');
|
||||
$this->element('activity:verb', null, ActivityVerb::FOLLOW);
|
||||
$this->elementEnd('collection');
|
||||
$this->elementStart('collection',
|
||||
array('href' => common_local_url('AtomPubFavoriteFeed',
|
||||
array('profile' => $this->user->id))));
|
||||
$this->element('atom:title',
|
||||
null,
|
||||
// TRANS: Title for Atom feed with a user's favorite notices. %s is a user nickname.
|
||||
sprintf(_("%s favorites"),
|
||||
$this->user->nickname));
|
||||
$this->element('accept', null, 'application/atom+xml;type=entry');
|
||||
$this->element('activity:verb', null, ActivityVerb::FAVORITE);
|
||||
$this->elementEnd('collection');
|
||||
$this->elementStart('collection',
|
||||
array('href' => common_local_url('AtomPubMembershipFeed',
|
||||
array('profile' => $this->user->id))));
|
||||
$this->element('atom:title',
|
||||
null,
|
||||
// TRANS: Title for Atom feed with a user's memberships. %s is a user nickname.
|
||||
sprintf(_("%s memberships"),
|
||||
$this->user->nickname));
|
||||
$this->element('accept', null, 'application/atom+xml;type=entry');
|
||||
$this->element('activity:verb', null, ActivityVerb::JOIN);
|
||||
$this->elementEnd('collection');
|
||||
$this->elementEnd('workspace');
|
||||
$this->elementEnd('service');
|
||||
$this->endXML();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a notice's attachment
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Show a notice's attachment
|
||||
*
|
||||
*/
|
||||
class ApiAttachmentAction extends ApiAuthAction
|
||||
{
|
||||
const MAXCOUNT = 100;
|
||||
|
||||
var $original = null;
|
||||
var $cnt = self::MAXCOUNT;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$file = new File();
|
||||
$file->selectAdd(); // clears it
|
||||
$file->selectAdd('url');
|
||||
$file->id = $this->trimmed('id');
|
||||
$url = $file->fetchAll('url');
|
||||
|
||||
$file_txt = '';
|
||||
if(strstr($url[0],'.html')) {
|
||||
$file_txt['txt'] = file_get_contents($url[0]);
|
||||
$file_txt['body_start'] = strpos($file_txt['txt'],'<body>')+6;
|
||||
$file_txt['body_end'] = strpos($file_txt['txt'],'</body>');
|
||||
$file_txt = substr($file_txt['txt'],$file_txt['body_start'],$file_txt['body_end']-$file_txt['body_start']);
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($file_txt);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Block a user via the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks the user specified in the ID parameter as the authenticating user.
|
||||
* Destroys a friendship to the blocked user if it exists. Returns the
|
||||
* blocked user in the requested format when successful.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiBlockCreateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $other = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new message
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->user) || empty($this->other)) {
|
||||
// TRANS: Client error displayed when trying to block a non-existing user or a user from another site.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
// Don't allow blocking yourself!
|
||||
|
||||
if ($this->user->id == $this->other->id) {
|
||||
// TRANS: Client error displayed when users try to block themselves.
|
||||
$this->clientError(_("You cannot block yourself!"), 403);
|
||||
}
|
||||
|
||||
if (!$this->user->hasBlocked($this->other)) {
|
||||
if (Event::handle('StartBlockProfile', array($this->user, $this->other))) {
|
||||
$result = $this->user->block($this->other);
|
||||
if ($result) {
|
||||
Event::handle('EndBlockProfile', array($this->user, $this->other));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->user->hasBlocked($this->other)) {
|
||||
$this->initDocument($this->format);
|
||||
$this->showProfile($this->other, $this->format);
|
||||
$this->endDocument($this->format);
|
||||
} else {
|
||||
// TRANS: Server error displayed when blocking a user has failed.
|
||||
$this->serverError(_('Block user failed.'), 500);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Un-block a user via the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-blocks the user specified in the ID parameter for the authenticating user.
|
||||
* Returns the un-blocked user in the requested format when successful.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiBlockDestroyAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $other = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->user) || empty($this->other)) {
|
||||
// TRANS: Client error when user not found for an API action to remove a block for a user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if ($this->user->hasBlocked($this->other)) {
|
||||
if (Event::handle('StartUnblockProfile', array($this->user, $this->other))) {
|
||||
$result = $this->user->unblock($this->other);
|
||||
if ($result) {
|
||||
Event::handle('EndUnblockProfile', array($this->user, $this->other));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->user->hasBlocked($this->other)) {
|
||||
$this->initDocument($this->format);
|
||||
$this->showProfile($this->other, $this->format);
|
||||
$this->endDocument($this->format);
|
||||
} else {
|
||||
// TRANS: Server error displayed when unblocking a user has failed.
|
||||
$this->serverError(_('Unblock user failed.'));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a notice's attachment
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Check if a url have a push-hub, i.e. if it is possible to subscribe
|
||||
*
|
||||
*/
|
||||
class ApiCheckHubAction extends ApiAuthAction
|
||||
{
|
||||
protected $url = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$this->url = urldecode($args['url']);
|
||||
|
||||
if (empty($this->url)) {
|
||||
$this->clientError(_('No URL.'), 403);
|
||||
}
|
||||
|
||||
if (!common_valid_http_url($this->url)) {
|
||||
$this->clientError(_('Invalid URL.'), 403);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$discover = new FeedDiscovery();
|
||||
|
||||
try {
|
||||
$feeduri = $discover->discoverFromURL($this->url);
|
||||
if($feeduri) {
|
||||
$huburi = $discover->getHubLink();
|
||||
}
|
||||
} catch (FeedSubNoFeedException $e) {
|
||||
$this->clientError(_('No feed found'), 403);
|
||||
} catch (FeedSubBadResponseException $e) {
|
||||
$this->clientError(_('No hub found'), 403);
|
||||
}
|
||||
|
||||
$hub_status = array();
|
||||
if ($huburi) {
|
||||
$hub_status = array('huburi' => $huburi);
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($hub_status);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check nickname
|
||||
*
|
||||
* Returns 1 if nickname is available on this instance, 0 if not. Error if site is private.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiCheckNicknameAction extends ApiAction
|
||||
{
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (common_config('site', 'private')) {
|
||||
$this->clientError(_('This site is private.'), 403);
|
||||
}
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$nickname = $this->trimmed('nickname');
|
||||
|
||||
try {
|
||||
Nickname::normalize($nickname, true);
|
||||
$nickname_ok = 1;
|
||||
} catch (NicknameException $e) {
|
||||
$nickname_ok = 0;
|
||||
}
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($nickname_ok);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* Show a stream of notices in a particular conversation
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a stream of notices in a particular conversation
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiconversationAction extends ApiAuthAction
|
||||
{
|
||||
protected $conversation = null;
|
||||
protected $notices = null;
|
||||
|
||||
/**
|
||||
* For initializing members of the class.
|
||||
*
|
||||
* @param array $argarray misc. arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function prepare($argarray)
|
||||
{
|
||||
parent::prepare($argarray);
|
||||
|
||||
$convId = $this->trimmed('id');
|
||||
|
||||
if (empty($convId)) {
|
||||
// TRANS: Client exception thrown when no conversation ID is given.
|
||||
throw new ClientException(_('No conversation ID.'));
|
||||
}
|
||||
|
||||
$this->conversation = Conversation::getKV('id', $convId);
|
||||
|
||||
if (empty($this->conversation)) {
|
||||
// TRANS: Client exception thrown when referring to a non-existing conversation ID (%d).
|
||||
throw new ClientException(sprintf(_('No conversation with ID %d.'), $convId),
|
||||
404);
|
||||
}
|
||||
|
||||
$stream = new ConversationNoticeStream($convId, $this->scoped);
|
||||
|
||||
$notice = $stream->getNotices(($this->page-1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
$this->notices = $notice->fetchAll();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler method
|
||||
*
|
||||
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($argarray=null)
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Title for conversion timeline.
|
||||
$title = _m('TITLE', 'Conversation');
|
||||
$id = common_local_url('apiconversation', array('id' => $this->conversation->id, 'format' => $this->format));
|
||||
$link = common_local_url('conversation', array('id' => $this->conversation->id));
|
||||
|
||||
$self = $id;
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setUpdated('now');
|
||||
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
|
||||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last modified, if applicable.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @return string last modified http header
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return etag, if applicable.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @return string etag http header
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->user->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this require authentication?
|
||||
*
|
||||
* @return boolean true if delete, else false
|
||||
*/
|
||||
function requiresAuth()
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
|
||||
$_SERVER['REQUEST_METHOD'] == 'HEAD') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show an external user's profile information
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Ouputs information for a user, specified by ID or screen name.
|
||||
* The user's most recent status will be returned inline.
|
||||
*/
|
||||
class ApiExternalProfileShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if ($this->format !== 'json') {
|
||||
$this->clientError('This method currently only serves JSON.', 415);
|
||||
}
|
||||
|
||||
$profileurl = urldecode($this->arg('profileurl'));
|
||||
|
||||
// TODO: Make this more ... unique!
|
||||
$this->profile = Profile::getKV('profileurl', $profileurl);
|
||||
|
||||
if (!($this->profile instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting profile information for a non-existing profile.
|
||||
$this->clientError(_('Profile not found.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->profile, true);
|
||||
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Subscribe to a user via the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the authenticating users to follow (subscribe) the user specified in
|
||||
* the ID parameter. Returns the befriended user in the requested format when
|
||||
* successful. Returns a string describing the failure condition when unsuccessful.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiFriendshipsCreateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $other = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->other)) {
|
||||
// TRANS: Client error displayed when trying follow who's profile could not be found.
|
||||
$this->clientError(_('Could not follow user: profile not found.'), 403);
|
||||
}
|
||||
|
||||
if ($this->user->isSubscribed($this->other)) {
|
||||
$errmsg = sprintf(
|
||||
// TRANS: Client error displayed when trying to follow a user that's already being followed.
|
||||
// TRANS: %s is the nickname of the user that is already being followed.
|
||||
_('Could not follow user: %s is already on your list.'),
|
||||
$this->other->nickname
|
||||
);
|
||||
$this->clientError($errmsg, 403);
|
||||
}
|
||||
|
||||
try {
|
||||
Subscription::start($this->user->getProfile(), $this->other);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), 403);
|
||||
}
|
||||
|
||||
$this->initDocument($this->format);
|
||||
$this->showProfile($this->other, $this->format);
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Unsubscribe to a user via API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the authenticating users to unfollow (unsubscribe) the user specified in
|
||||
* the ID parameter. Returns the unfollowed user in the requested format when
|
||||
* successful. Returns a string describing the failure condition when unsuccessful.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiFriendshipsDestroyAction extends ApiAuthAction
|
||||
{
|
||||
var $other = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$this->other = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
|
||||
$this->clientError(
|
||||
// TRANS: Client error. POST is a HTTP command. It should not be translated.
|
||||
_('This method requires a POST.'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->other)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when trying to unfollow a user that cannot be found.
|
||||
_('Could not unfollow user: User not found.'),
|
||||
403,
|
||||
$this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't allow unsubscribing from yourself!
|
||||
|
||||
if ($this->user->id == $this->other->id) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when trying to unfollow self.
|
||||
_("You cannot unfollow yourself."),
|
||||
403,
|
||||
$this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// throws an exception on error
|
||||
Subscription::cancel($this->user->getProfile(), $this->other);
|
||||
|
||||
$this->initDocument($this->format);
|
||||
$this->showProfile($this->other, $this->format);
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show whether there is a friendship between two users
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for the existence of friendship between two users. Will return true if
|
||||
* user_a follows user_b, otherwise will return false.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $profile_a = null;
|
||||
var $profile_b = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->profile_a = $this->getTargetProfile($this->trimmed('user_a'));
|
||||
$this->profile_b = $this->getTargetProfile($this->trimmed('user_b'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (empty($this->profile_a) || empty($this->profile_b)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when supplying invalid parameters to an API call checking if a friendship exists.
|
||||
_('Two valid IDs or nick names must be supplied.'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$result = Subscription::exists($this->profile_a, $this->profile_b);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->element('friends', null, $result);
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
print json_encode($result);
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show information about the relationship between two users
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs detailed information about the relationship between two users
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiFriendshipsShowAction extends ApiBareAuthAction
|
||||
{
|
||||
var $source = null;
|
||||
var $target = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$source_id = (int)$this->trimmed('source_id');
|
||||
$source_screen_name = $this->trimmed('source_screen_name');
|
||||
$target_id = (int)$this->trimmed('target_id');
|
||||
$target_screen_name = $this->trimmed('target_screen_name');
|
||||
|
||||
if (!empty($source_id)) {
|
||||
$this->source = User::getKV($source_id);
|
||||
} elseif (!empty($source_screen_name)) {
|
||||
$this->source = User::getKV('nickname', $source_screen_name);
|
||||
} else {
|
||||
$this->source = $this->auth_user;
|
||||
}
|
||||
|
||||
if (!empty($target_id)) {
|
||||
$this->target = User::getKV($target_id);
|
||||
} elseif (!empty($target_screen_name)) {
|
||||
$this->target = User::getKV('nickname', $target_screen_name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this API resource requires auth. Overloaded to look
|
||||
* return true in case source_id and source_screen_name are both empty
|
||||
*
|
||||
* @return boolean true or false
|
||||
*/
|
||||
function requiresAuth()
|
||||
{
|
||||
if (common_config('site', 'private')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$source_id = $this->trimmed('source_id');
|
||||
$source_screen_name = $this->trimmed('source_screen_name');
|
||||
|
||||
if (empty($source_id) && empty($source_screen_name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->source)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when a source user could not be determined showing friendship.
|
||||
_('Could not determine source user.'),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->target)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when a target user could not be determined showing friendship.
|
||||
_('Could not find target user.'),
|
||||
404
|
||||
);
|
||||
}
|
||||
|
||||
$result = $this->twitterRelationshipArray($this->source, $this->target);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlRelationship($result[relationship]);
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
print json_encode($result);
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Dump of configuration variables
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Gives a full dump of configuration variables for this instance
|
||||
* of GNU social, minus variables that may be security-sensitive (like
|
||||
* passwords).
|
||||
* URL: https://example.com/api/gnusocial/config.(xml|json)
|
||||
* Formats: xml, json
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiGNUsocialConfigAction extends ApiAction
|
||||
{
|
||||
var $keys = array(
|
||||
'site' => array('name', 'server', 'theme', 'path', 'logo', 'fancy', 'language',
|
||||
'email', 'broughtby', 'broughtbyurl', 'timezone', 'closed',
|
||||
'inviteonly', 'private', 'textlimit', 'ssl', 'sslserver'),
|
||||
'license' => array('type', 'owner', 'url', 'title', 'image'),
|
||||
'nickname' => array('featured'),
|
||||
'profile' => array('biolimit'),
|
||||
'group' => array('desclimit'),
|
||||
'notice' => array('contentlimit'),
|
||||
'throttle' => array('enabled', 'count', 'timespan'),
|
||||
'xmpp' => array('enabled', 'server', 'port', 'user'),
|
||||
'integration' => array('source'),
|
||||
'attachments' => array('uploads', 'file_quota'),
|
||||
'url' => array('maxurllength', 'maxnoticelength'),
|
||||
);
|
||||
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->elementStart('config');
|
||||
|
||||
// XXX: check that all sections and settings are legal XML elements
|
||||
|
||||
foreach ($this->keys as $section => $settings) {
|
||||
$this->elementStart($section);
|
||||
foreach ($settings as $setting) {
|
||||
$value = $this->setting($section, $setting);
|
||||
if (is_array($value)) {
|
||||
$value = implode(',', $value);
|
||||
} else if ($value === false || $value == '0') {
|
||||
$value = 'false';
|
||||
} else if ($value === true || $value == '1') {
|
||||
$value = 'true';
|
||||
}
|
||||
|
||||
// return theme logo if there's no site specific one
|
||||
if (empty($value)) {
|
||||
if ($section == 'site' && $setting == 'logo') {
|
||||
$value = Theme::path('logo.png');
|
||||
}
|
||||
}
|
||||
|
||||
$this->element($setting, null, $value);
|
||||
}
|
||||
$this->elementEnd($section);
|
||||
}
|
||||
$this->elementEnd('config');
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$result = array();
|
||||
foreach ($this->keys as $section => $settings) {
|
||||
$result[$section] = array();
|
||||
foreach ($settings as $setting) {
|
||||
$result[$section][$setting]
|
||||
= $this->setting($section, $setting);
|
||||
}
|
||||
}
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($result);
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
function setting($section, $key) {
|
||||
$result = common_config($section, $key);
|
||||
if ($key == 'file_quota') {
|
||||
// hack: adjust for the live upload limit
|
||||
if (common_config($section, 'uploads')) {
|
||||
$max = ImageFile::maxFileSizeInt();
|
||||
} else {
|
||||
$max = 0;
|
||||
}
|
||||
return min($result, $max);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* A version stamp for the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Returns a version number for this version of GNU social, which
|
||||
* should make things a bit easier for upgrades.
|
||||
* URL: http://identi.ca/api/statusnet/version.(xml|json)
|
||||
* Formats: xml, js
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiGNUsocialVersionAction extends ApiPrivateAuthAction
|
||||
{
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->element('version', null, GNUSOCIAL_VERSION);
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
print '"'.GNUSOCIAL_VERSION.'"';
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List a group's admins
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* List 20 newest admins of the group specified by name or ID.
|
||||
*
|
||||
* @category API
|
||||
* @package GNUsocial
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Hannes Mannerheim <h@nnesmannerhe.im>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
class ApiGroupAdminsAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed trying to show group membership on a non-existing group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the admin of the group
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// XXX: RSS and Atom
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUsers($this->profiles);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonUsers($this->profiles);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the admins of a group
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
function getProfiles()
|
||||
{
|
||||
$profiles = array();
|
||||
|
||||
$profile = $this->group->getAdmins(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$profiles[] = clone($profile);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this list of profiles last modified?
|
||||
*
|
||||
* @return string datestamp of the lastest profile in the group
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language
|
||||
* the group id, and timestamps of the first and last
|
||||
* user who has joined the group
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Create a group via the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a new group. Sets the authenticated user as the administrator of the group.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupCreateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $group = null;
|
||||
var $nickname = null;
|
||||
var $fullname = null;
|
||||
var $homepage = null;
|
||||
var $description = null;
|
||||
var $location = null;
|
||||
var $aliasstring = null;
|
||||
var $aliases = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->nickname = Nickname::normalize($this->arg('nickname'), true);
|
||||
$this->fullname = $this->arg('full_name');
|
||||
$this->homepage = $this->arg('homepage');
|
||||
$this->description = $this->arg('description');
|
||||
$this->location = $this->arg('location');
|
||||
$this->aliasstring = $this->arg('aliases');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new group
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error given when a user was not found (404).
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if ($this->validateParams() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$group = User_group::register(array('nickname' => $this->nickname,
|
||||
'fullname' => $this->fullname,
|
||||
'homepage' => $this->homepage,
|
||||
'description' => $this->description,
|
||||
'location' => $this->location,
|
||||
'aliases' => $this->aliases,
|
||||
'userid' => $this->user->id,
|
||||
'local' => true));
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate params for the new group
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function validateParams()
|
||||
{
|
||||
if (!is_null($this->homepage)
|
||||
&& strlen($this->homepage) > 0
|
||||
&& !common_valid_http_url($this->homepage)) {
|
||||
// TRANS: Client error in form for group creation.
|
||||
$this->clientError(_('Homepage is not a valid URL.'), 403);
|
||||
|
||||
} elseif (!is_null($this->fullname)
|
||||
&& mb_strlen($this->fullname) > 255) {
|
||||
// TRANS: Client error in form for group creation.
|
||||
$this->clientError(_('Full name is too long (maximum 255 characters).'), 403);
|
||||
|
||||
} elseif (User_group::descriptionTooLong($this->description)) {
|
||||
// TRANS: Client error shown when providing too long a description during group creation.
|
||||
// TRANS: %d is the maximum number of allowed characters.
|
||||
$this->clientError(sprintf(_m('Description is too long (maximum %d character).',
|
||||
'Description is too long (maximum %d characters).',
|
||||
User_group::maxDescription()), User_group::maxDescription()), 403);
|
||||
|
||||
} elseif (!is_null($this->location)
|
||||
&& mb_strlen($this->location) > 255) {
|
||||
// TRANS: Client error shown when providing too long a location during group creation.
|
||||
$this->clientError(_('Location is too long (maximum 255 characters).'), 403);
|
||||
}
|
||||
|
||||
if (!empty($this->aliasstring)) {
|
||||
$this->aliases = array_map(
|
||||
array('Nickname', 'normalize'), // static call to Nickname::normalize
|
||||
array_unique(preg_split('/[\s,]+/', $this->aliasstring))
|
||||
);
|
||||
} else {
|
||||
$this->aliases = array();
|
||||
}
|
||||
|
||||
if (count($this->aliases) > common_config('group', 'maxaliases')) {
|
||||
$this->clientError(sprintf(
|
||||
// TRANS: Client error shown when providing too many aliases during group creation.
|
||||
// TRANS: %d is the maximum number of allowed aliases.
|
||||
_m('Too many aliases! Maximum %d allowed.',
|
||||
'Too many aliases! Maximum %d allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')),
|
||||
403);
|
||||
}
|
||||
|
||||
// Everything looks OK
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check to see whether a user a member of a group
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a user is a member of a specified group.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupIsMemberAction extends ApiBareAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile(null);
|
||||
$this->group = $this->getTargetGroup(null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->target)) {
|
||||
// TRANS: Client error displayed when checking group membership for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed when checking group membership for a non-existing group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$is_member = $this->target->isMember($this->group);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->element('is_member', null, $is_member);
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects(array('is_member' => $is_member));
|
||||
$this->endDocument('json');
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Join a group via the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the authenticated user to the group speicified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupJoinAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Join the authenticated user to the group
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->scoped)) {
|
||||
// TRANS: Client error displayed when trying to have a non-existing user join a group.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed when trying to join a group that does not exist.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
if ($this->scoped->isMember($this->group)) {
|
||||
// TRANS: Server error displayed when trying to join a group the user is already a member of.
|
||||
$this->clientError(_('You are already a member of that group.'), 403);
|
||||
}
|
||||
|
||||
if (Group_block::isBlocked($this->group, $this->scoped)) {
|
||||
// TRANS: Server error displayed when trying to join a group the user is blocked from joining.
|
||||
$this->clientError(_('You have been blocked from that group by the admin.'), 403);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->scoped->joinGroup($this->group);
|
||||
} catch (Exception $e) {
|
||||
// TRANS: Server error displayed when joining a group failed in the database.
|
||||
// TRANS: %1$s is the joining user's nickname, $2$s is the group nickname for which the join failed.
|
||||
$this->serverError(sprintf(_('Could not join user %1$s to group %2$s.'),
|
||||
$this->scoped->nickname, $this->group->nickname));
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Leave a group via the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the authenticated user from the group specified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupLeaveAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Save the new message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!$this->scoped instanceof Profile) {
|
||||
// TRANS: Client error displayed when trying to have a non-existing user leave a group.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if (!$this->group instanceof User_group) {
|
||||
// TRANS: Client error displayed when trying to leave a group that does not exist.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$member = new Group_member();
|
||||
|
||||
$member->group_id = $this->group->id;
|
||||
$member->profile_id = $this->scoped->id;
|
||||
|
||||
if (!$member->find(true)) {
|
||||
// TRANS: Server error displayed when trying to leave a group the user is not a member of.
|
||||
$this->serverError(_('You are not a member of this group.'));
|
||||
}
|
||||
|
||||
try {
|
||||
$this->user->leaveGroup($this->group);
|
||||
} catch (Exception $e) {
|
||||
// TRANS: Server error displayed when leaving a group failed in the database.
|
||||
// TRANS: %1$s is the leaving user's nickname, $2$s is the group nickname for which the leave failed.
|
||||
$this->serverError(sprintf(_('Could not remove user %1$s from group %2$s.'),
|
||||
$this->scoped->getNickname(), $this->group->nickname));
|
||||
}
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check to see whether a user a member of a group
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a user is a member of a specified group.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupListAction extends ApiBareAuthAction
|
||||
{
|
||||
var $groups = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
//TODO: Make sure this doesn't leak unwantedly for federated users
|
||||
$this->target = $this->getTargetProfile(null);
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when user not found for an action.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->groups = $this->getGroups();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the user's groups
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Used as title in check for group membership. %s is a user name.
|
||||
$title = sprintf(_("%s's groups"), $this->target->nickname);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:Groups";
|
||||
$link = common_local_url(
|
||||
'usergroups',
|
||||
array('nickname' => $this->target->nickname)
|
||||
);
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Used as subtitle in check for group membership. %1$s is the site name, %2$s is a user name.
|
||||
_('%1$s groups %2$s is a member of.'),
|
||||
$sitename,
|
||||
$this->target->nickname
|
||||
);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlGroups($this->groups);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssGroups($this->groups, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_local_url('ApiGroupList', array('id'=>$this->target->id, 'format'=>'atom'));
|
||||
$this->showAtomGroups(
|
||||
$this->groups,
|
||||
$title,
|
||||
$id,
|
||||
$link,
|
||||
$subtitle,
|
||||
$selfuri
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonGroups($this->groups);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups
|
||||
*
|
||||
* @return array groups
|
||||
*/
|
||||
function getGroups()
|
||||
{
|
||||
$groups = array();
|
||||
|
||||
$group = $this->target->getGroups(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($group->fetch()) {
|
||||
$groups[] = clone($group);
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest group the user has joined
|
||||
*/
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->groups) && (count($this->groups) > 0)) {
|
||||
return strtotime($this->groups[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID and
|
||||
* timestamps of the first and last group the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->groups) && (count($this->groups) > 0)) {
|
||||
|
||||
$last = count($this->groups) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->groups[0]->created),
|
||||
strtotime($this->groups[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the newest groups
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns of the lastest 20 groups for the site
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupListAllAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $groups = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->getTargetUser(null);
|
||||
$this->groups = $this->getGroups();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the user's groups
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Message is used as a title when listing the lastest 20 groups. %s is a site name.
|
||||
$title = sprintf(_("%s groups"), $sitename);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:Groups";
|
||||
$link = common_local_url('groups');
|
||||
// TRANS: Message is used as a subtitle when listing the latest 20 groups. %s is a site name.
|
||||
$subtitle = sprintf(_("groups on %s"), $sitename);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlGroups($this->groups);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssGroups($this->groups, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$selfuri = common_root_url() .
|
||||
'api/statusnet/groups/list_all.atom';
|
||||
$this->showAtomGroups(
|
||||
$this->groups,
|
||||
$title,
|
||||
$id,
|
||||
$link,
|
||||
$subtitle,
|
||||
$selfuri
|
||||
);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonGroups($this->groups);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get groups
|
||||
*
|
||||
* @return array groups
|
||||
*/
|
||||
function getGroups()
|
||||
{
|
||||
$qry = 'SELECT user_group.* '.
|
||||
'from user_group join local_group on user_group.id = local_group.group_id '.
|
||||
'order by created desc ';
|
||||
$offset = intval($this->page - 1) * intval($this->count);
|
||||
$limit = intval($this->count);
|
||||
if (common_config('db', 'type') == 'pgsql') {
|
||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||
} else {
|
||||
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||
}
|
||||
$group = new User_group();
|
||||
|
||||
$group->query($qry);
|
||||
|
||||
$groups = array();
|
||||
while ($group->fetch()) {
|
||||
$groups[] = clone($group);
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the site's latest group
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->groups) && (count($this->groups) > 0)) {
|
||||
return strtotime($this->groups[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the first and last group the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->groups) && (count($this->groups) > 0)) {
|
||||
|
||||
$last = count($this->groups) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
strtotime($this->groups[0]->created),
|
||||
strtotime($this->groups[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List a group's members
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* List 20 newest members of the group specified by name or ID.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupMembershipAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
var $profiles = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed trying to show group membership on a non-existing group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the members of the group
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// XXX: RSS and Atom
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUsers($this->profiles);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonUsers($this->profiles);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the members of a group
|
||||
*
|
||||
* @return array $profiles list of profiles
|
||||
*/
|
||||
function getProfiles()
|
||||
{
|
||||
$profiles = array();
|
||||
|
||||
$profile = $this->group->getMembers(
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($profile->fetch()) {
|
||||
$profiles[] = clone($profile);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this list of profiles last modified?
|
||||
*
|
||||
* @return string datestamp of the lastest profile in the group
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of groups
|
||||
*
|
||||
* Returns an Etag based on the action name, language
|
||||
* the group id, and timestamps of the first and last
|
||||
* user who has joined the group
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Update a group's profile
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* API analog to the group edit page
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupProfileUpdateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||
|
||||
$this->fullname = $this->trimmed('fullname');
|
||||
$this->homepage = $this->trimmed('homepage');
|
||||
$this->description = $this->trimmed('description');
|
||||
$this->location = $this->trimmed('location');
|
||||
$this->aliasstring = $this->trimmed('aliases');
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* See which request params have been set, and update the profile
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->user)) {
|
||||
// TRANS: Client error displayed when not providing a user or an invalid user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed when not providing a group or an invalid group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
if (!$this->user->isAdmin($this->group)) {
|
||||
// TRANS: Client error displayed when trying to edit a group without being an admin.
|
||||
$this->clientError(_('You must be an admin to edit the group.'), 403);
|
||||
}
|
||||
|
||||
$this->group->query('BEGIN');
|
||||
|
||||
$orig = clone($this->group);
|
||||
|
||||
try {
|
||||
|
||||
if (common_config('profile', 'changenick') == true && $this->group->nickname !== $this->nickname) {
|
||||
try {
|
||||
$this->group->nickname = Nickname::normalize($this->nickname, true);
|
||||
} catch (NicknameException $e) {
|
||||
throw new ApiValidationException($e->getMessage());
|
||||
}
|
||||
$this->group->mainpage = common_local_url('showgroup',
|
||||
array('nickname' => $this->group->nickname));
|
||||
}
|
||||
|
||||
if (!empty($this->fullname)) {
|
||||
$this->validateFullname();
|
||||
$this->group->fullname = $this->fullname;
|
||||
}
|
||||
|
||||
if (!empty($this->homepage)) {
|
||||
$this->validateHomepage();
|
||||
$this->group->homepage = $this->homepage;
|
||||
}
|
||||
|
||||
if (!empty($this->description)) {
|
||||
$this->validateDescription();
|
||||
$this->group->description = $this->decription;
|
||||
}
|
||||
|
||||
if (!empty($this->location)) {
|
||||
$this->validateLocation();
|
||||
$this->group->location = $this->location;
|
||||
}
|
||||
|
||||
} catch (ApiValidationException $ave) {
|
||||
$this->clientError($ave->getMessage(), 400);
|
||||
}
|
||||
|
||||
$result = $this->group->update($orig);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($this->group, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error displayed when group update fails.
|
||||
$this->serverError(_('Could not update group.'));
|
||||
}
|
||||
|
||||
$aliases = array();
|
||||
|
||||
try {
|
||||
if (!empty($this->aliasstring)) {
|
||||
$aliases = $this->validateAliases();
|
||||
}
|
||||
} catch (ApiValidationException $ave) {
|
||||
$this->clientError($ave->getMessage(), 403);
|
||||
}
|
||||
|
||||
$result = $this->group->setAliases($aliases);
|
||||
|
||||
if (!$result) {
|
||||
// TRANS: Server error displayed when adding group aliases fails.
|
||||
$this->serverError(_('Could not create aliases.'));
|
||||
}
|
||||
|
||||
$this->group->query('COMMIT');
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
function validateHomepage()
|
||||
{
|
||||
if (!is_null($this->homepage)
|
||||
&& (strlen($this->homepage) > 0)
|
||||
&& !common_valid_http_url($this->homepage)) {
|
||||
throw new ApiValidationException(
|
||||
// TRANS: API validation exception thrown when homepage URL does not validate.
|
||||
_('Homepage is not a valid URL.')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function validateFullname()
|
||||
{
|
||||
if (!is_null($this->fullname) && mb_strlen($this->fullname) > 255) {
|
||||
throw new ApiValidationException(
|
||||
// TRANS: API validation exception thrown when full name does not validate.
|
||||
_('Full name is too long (maximum 255 characters).')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function validateDescription()
|
||||
{
|
||||
if (User_group::descriptionTooLong($this->description)) {
|
||||
// TRANS: API validation exception thrown when description does not validate.
|
||||
// TRANS: %d is the maximum description length and used for plural.
|
||||
throw new ApiValidationException(sprintf(_m('Description is too long (maximum %d character).',
|
||||
'Description is too long (maximum %d characters).',
|
||||
User_group::maxDescription()),
|
||||
User_group::maxDescription()));
|
||||
}
|
||||
}
|
||||
|
||||
function validateLocation()
|
||||
{
|
||||
if (!is_null($this->location) && mb_strlen($this->location) > 255) {
|
||||
throw new ApiValidationException(
|
||||
// TRANS: API validation exception thrown when location does not validate.
|
||||
_('Location is too long (maximum 255 characters).')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function validateAliases()
|
||||
{
|
||||
try {
|
||||
$aliases = array_map(array('Nickname', 'normalize'),
|
||||
array_unique(preg_split('/[\s,]+/', $this->aliasstring)));
|
||||
} catch (NicknameException $e) {
|
||||
throw new ApiValidationException(sprintf('Error processing aliases: %s', $e->getMessage()));
|
||||
}
|
||||
|
||||
if (count($aliases) > common_config('group', 'maxaliases')) {
|
||||
// TRANS: API validation exception thrown when aliases do not validate.
|
||||
// TRANS: %d is the maximum number of aliases and used for plural.
|
||||
throw new ApiValidationException(sprintf(_m('Too many aliases! Maximum %d allowed.',
|
||||
'Too many aliases! Maximum %d allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')));
|
||||
}
|
||||
|
||||
return $aliases;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show information about a group
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs detailed information about the group specified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Michele <macno@macno.org>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiGroupShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
if (empty($this->group)) {
|
||||
$alias = Group_alias::getKV(
|
||||
'alias',
|
||||
common_canonical_nickname($this->arg('id'))
|
||||
);
|
||||
if (!empty($alias)) {
|
||||
$args = array('id' => $alias->group_id, 'format' => $this->format);
|
||||
common_redirect(common_local_url('ApiGroupShow', $args), 301);
|
||||
} else {
|
||||
// TRANS: Client error displayed when trying to show a group that could not be found.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this group last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->group)) {
|
||||
return strtotime($this->group->modified);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this group
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the notice
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->group)) {
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->group->modified))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Test that you can connect to the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string "ok" in the requested format with a 200 OK HTTP status code.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiHelpTestAction extends ApiPrivateAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->element('ok', null, 'true');
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
print '"ok"';
|
||||
$this->endDocument('json');
|
||||
} else {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show, update or delete a list.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class ApiListAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* The list in question in the current request
|
||||
*/
|
||||
var $list = null;
|
||||
|
||||
/**
|
||||
* Is this an update request?
|
||||
*/
|
||||
var $update = false;
|
||||
|
||||
/**
|
||||
* Is this a delete request?
|
||||
*/
|
||||
var $delete = false;
|
||||
|
||||
/**
|
||||
* Set the flags for handling the request. Show list if this is a GET
|
||||
* request, update it if it is POST, delete list if method is DELETE
|
||||
* or if method is POST and an argument _method is set to DELETE. Act
|
||||
* like we don't know if the current user has no access to the list.
|
||||
*
|
||||
* Takes parameters:
|
||||
* - user: the user id or nickname
|
||||
* - id: the id of the tag or the tag itself
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->delete = ($_SERVER['REQUEST_METHOD'] == 'DELETE' ||
|
||||
($this->trimmed('_method') == 'DELETE' &&
|
||||
$_SERVER['REQUEST_METHOD'] == 'POST'));
|
||||
|
||||
// update list if method is POST or PUT and $this->delete is not true
|
||||
$this->update = (!$this->delete &&
|
||||
in_array($_SERVER['REQUEST_METHOD'], array('POST', 'PUT')));
|
||||
|
||||
$this->user = $this->getTargetUser($this->arg('user'));
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
// TRANS: Client error displayed when referring to a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if($this->delete) {
|
||||
$this->handleDelete();
|
||||
return true;
|
||||
}
|
||||
|
||||
if($this->update) {
|
||||
$this->handlePut();
|
||||
return true;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* require authentication if it is a write action or user is ambiguous
|
||||
*
|
||||
*/
|
||||
function requiresAuth()
|
||||
{
|
||||
return parent::requiresAuth() ||
|
||||
$this->create || $this->delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handlePut()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
// TRANS: Client error displayed when trying to update another user's list.
|
||||
$this->clientError(_('You cannot update lists that do not belong to you.'), 401);
|
||||
}
|
||||
|
||||
$new_list = clone($this->list);
|
||||
$new_list->tag = common_canonical_tag($this->arg('name'));
|
||||
$new_list->description = common_canonical_tag($this->arg('description'));
|
||||
$new_list->private = ($this->arg('mode') === 'private') ? true : false;
|
||||
|
||||
$result = $new_list->update($this->list);
|
||||
|
||||
if(!$result) {
|
||||
// TRANS: Client error displayed when an unknown error occurs updating a list.
|
||||
$this->clientError(_('An error occured.'), 503);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($new_list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($new_list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handleDelete()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
// TRANS: Client error displayed when trying to delete another user's list.
|
||||
$this->clientError(_('You cannot delete lists that do not belong to you.'), 401);
|
||||
}
|
||||
|
||||
$record = clone($this->list);
|
||||
$this->list->delete();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($record);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($record);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that this resource is not read-only.
|
||||
*
|
||||
* @return boolean is_read-only=false
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was the list (people tag) last updated?
|
||||
*
|
||||
* @return String time_last_modified
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if(!empty($this->list)) {
|
||||
return strtotime($this->list->modified);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID and
|
||||
* timestamps of the first and last list the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->list)) {
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->user->id,
|
||||
strtotime($this->list->created),
|
||||
strtotime($this->list->modified))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* API method to check if a user belongs to a list.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action handler for Twitter list_memeber methods
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
* @see ApiBareAuthAction
|
||||
*/
|
||||
class ApiListMemberAction extends ApiBareAuthAction
|
||||
{
|
||||
/**
|
||||
* Set the flags for handling the request. Show the profile if this
|
||||
* is a GET request AND the profile is a member of the list, add a member
|
||||
* if it is a POST, remove the profile from the list if method is DELETE
|
||||
* or if method is POST and an argument _method is set to DELETE. Act
|
||||
* like we don't know if the current user has no access to the list.
|
||||
*
|
||||
* Takes parameters:
|
||||
* - user: the user id or nickname
|
||||
* - list_id: the id of the tag or the tag itself
|
||||
* - id: the id of the member being looked for/added/removed
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('list_id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
// TRANS: Client error displayed when referring to a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when referring to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$arr = array('tagger' => $this->list->tagger,
|
||||
'tag' => $this->list->tag,
|
||||
'tagged' => $this->target->id);
|
||||
$ptag = Profile_tag::pkeyGet($arr);
|
||||
|
||||
if(empty($ptag)) {
|
||||
// TRANS: Client error displayed when referring to a non-list member.
|
||||
$this->clientError(_('The specified user is not a member of this list.'));
|
||||
}
|
||||
|
||||
$user = $this->twitterUserArray($this->target, true);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUser($user, 'user', true);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonUser($user);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List/add/remove list members.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apilistusers.php';
|
||||
|
||||
class ApiListMembersAction extends ApiListUsersAction
|
||||
{
|
||||
/**
|
||||
* Add a user to a list (tag someone)
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handlePost()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
// TRANS: Client error displayed when trying to add members to a list without having the right to do so.
|
||||
$this->clientError(_('You are not allowed to add members to this list.'), 401);
|
||||
}
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when trying to modify list members without specifying them.
|
||||
$this->clientError(_('You must specify a member.'));
|
||||
}
|
||||
|
||||
$result = Profile_tag::setTag($this->auth_user->id,
|
||||
$this->target->id, $this->list->tag);
|
||||
|
||||
if(empty($result)) {
|
||||
// TRANS: Client error displayed when an unknown error occurs viewing list members.
|
||||
$this->clientError(_('An error occured.'), 500);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user from a list (untag someone)
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handleDelete()
|
||||
{
|
||||
if($this->auth_user->id != $this->list->tagger) {
|
||||
// TRANS: Client error displayed when trying to remove members from a list without having the right to do so.
|
||||
$this->clientError(_('You are not allowed to remove members from this list.'), 401);
|
||||
}
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when trying to modify list members without specifying them.
|
||||
$this->clientError(_('You must specify a member.'));
|
||||
}
|
||||
|
||||
$args = array('tagger' => $this->auth_user->id,
|
||||
'tagged' => $this->target->id,
|
||||
'tag' => $this->list->tag);
|
||||
$ptag = Profile_tag::pkeyGet($args);
|
||||
|
||||
if (empty($ptag)) {
|
||||
// TRANS: Client error displayed when trying to remove a list member that is not part of a list.
|
||||
$this->clientError(_('The user you are trying to remove from the list is not a member.'));
|
||||
}
|
||||
|
||||
if (!$ptag->delete()) {
|
||||
// TRANS: Client error displayed when an unknown error occurs viewing list members.
|
||||
$this->clientError(_('An error occured.'), 500);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* List the members of a list (people tagged)
|
||||
*/
|
||||
function getUsers()
|
||||
{
|
||||
$fn = array($this->list, 'getTagged');
|
||||
list($this->users, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Get a list of lists a user belongs to. (people tags for a user)
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action handler for API method to list lists a user belongs to.
|
||||
* (people tags for a user)
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
* @see ApiBareAuthAction
|
||||
*/
|
||||
class ApiListMembershipsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $lists = array();
|
||||
var $cursor = -1;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
|
||||
/**
|
||||
* Prepare for running the action
|
||||
* Take arguments for running:s
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->cursor = (int) $this->arg('cursor', -1);
|
||||
$user = $this->getTargetUser($this->arg('user'));
|
||||
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
|
||||
$this->getLists();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the lists
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function getLists()
|
||||
{
|
||||
$profile = $this->target;
|
||||
$fn = array($profile, 'getOtherTags');
|
||||
|
||||
# 20 lists
|
||||
list($this->lists, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array($this->auth_user), $this->cursor, 20);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List existing lists or create a new list.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action handler for Twitter list_memeber methods
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Shashi Gowda <connect2shashi@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
* @see ApiBareAuthAction
|
||||
*/
|
||||
class ApiListsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $lists = null;
|
||||
var $cursor = 0;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
var $create = false;
|
||||
|
||||
/**
|
||||
* Set the flags for handling the request. List lists created by user if this
|
||||
* is a GET request, create a new list if it is a POST request.
|
||||
*
|
||||
* Takes parameters:
|
||||
* - user: the user id or nickname
|
||||
* Parameters for POST request
|
||||
* - name: name of the new list (the people tag itself)
|
||||
* - mode: (optional) mode for the new list private/public
|
||||
* - description: (optional) description for the list
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->create = ($_SERVER['REQUEST_METHOD'] == 'POST');
|
||||
|
||||
if (!$this->create) {
|
||||
|
||||
$this->user = $this->getTargetUser($this->arg('user'));
|
||||
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
$this->getLists();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* require authentication if it is a write action or user is ambiguous
|
||||
*
|
||||
*/
|
||||
function requiresAuth()
|
||||
{
|
||||
return parent::requiresAuth() ||
|
||||
$this->create || $this->delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request:
|
||||
* Show the lists the user has created if the request method is GET
|
||||
* Create a new list by diferring to handlePost() if it is POST.
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if($this->create) {
|
||||
return $this->handlePost();
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handlePost()
|
||||
{
|
||||
$name=$this->arg('name');
|
||||
if(empty($name)) {
|
||||
// mimick twitter
|
||||
// TRANS: Client error displayed when trying to create a list without a name.
|
||||
print _("A list must have a name.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// twitter creates a new list by appending a number to the end
|
||||
// if the list by the given name already exists
|
||||
// it makes more sense to return the existing list instead
|
||||
|
||||
$private = null;
|
||||
if ($this->arg('mode') === 'public') {
|
||||
$private = false;
|
||||
} else if ($this->arg('mode') === 'private') {
|
||||
$private = true;
|
||||
}
|
||||
|
||||
$list = Profile_list::ensureTag($this->auth_user->id,
|
||||
$this->arg('name'),
|
||||
$this->arg('description'),
|
||||
$private);
|
||||
if (empty($list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lists
|
||||
*/
|
||||
function getLists()
|
||||
{
|
||||
$cursor = (int) $this->arg('cursor', -1);
|
||||
|
||||
// twitter fixes count at 20
|
||||
// there is no argument named count
|
||||
$count = 20;
|
||||
$fn = array($this->target, 'getLists');
|
||||
|
||||
list($this->lists,
|
||||
$this->next_cursor,
|
||||
$this->prev_cursor) = Profile_list::getAtCursor($fn, array($this->auth_user), $cursor, $count);
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
if (!$this->create && !empty($this->lists) && (count($this->lists) > 0)) {
|
||||
return strtotime($this->lists[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this list of lists
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID and
|
||||
* timestamps of the first and last list the user has joined
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!$this->create && !empty($this->lists) && (count($this->lists) > 0)) {
|
||||
|
||||
$last = count($this->lists) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->lists[0]->created),
|
||||
strtotime($this->lists[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Check if a user is subscribed to a list
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class ApiListSubscriberAction extends ApiBareAuthAction
|
||||
{
|
||||
var $list = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('list_id'));
|
||||
|
||||
if (empty($this->list)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$arr = array('profile_tag_id' => $this->list->id,
|
||||
'profile_id' => $this->target->id);
|
||||
$sub = Profile_tag_subscription::pkeyGet($arr);
|
||||
|
||||
if(empty($sub)) {
|
||||
// TRANS: Client error displayed when a membership check for a user is nagative.
|
||||
$this->clientError(_('The specified user is not a subscriber of this list.'));
|
||||
}
|
||||
|
||||
$user = $this->twitterUserArray($this->target, true);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showTwitterXmlUser($user, 'user', true);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonUser($user);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show/add/remove list subscribers.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apilistusers.php';
|
||||
|
||||
class ApiListSubscribersAction extends ApiListUsersAction
|
||||
{
|
||||
/**
|
||||
* Subscribe to list
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function handlePost()
|
||||
{
|
||||
$result = Profile_tag_subscription::add($this->list,
|
||||
$this->auth_user);
|
||||
|
||||
if(empty($result)) {
|
||||
// TRANS: Client error displayed when an unknown error occurs in the list subscribers action.
|
||||
$this->clientError(_('An error occured.'), 500);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
function handleDelete()
|
||||
{
|
||||
$args = array('profile_tag_id' => $this->list->id,
|
||||
'profile_id' => $this->auth_user->id);
|
||||
$ptag = Profile_tag_subscription::pkeyGet($args);
|
||||
|
||||
if(empty($ptag)) {
|
||||
// TRANS: Client error displayed when trying to unsubscribe from a non-subscribed list.
|
||||
$this->clientError(_('You are not subscribed to this list.'));
|
||||
}
|
||||
|
||||
$result = Profile_tag_subscription::remove($this->list, $this->auth_user);
|
||||
|
||||
if (empty($result)) {
|
||||
// TRANS: Client error displayed when an unknown error occurs unsubscribing from a list.
|
||||
$this->clientError(_('An error occured.'), 500);
|
||||
}
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlList($this->list);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonList($this->list);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getUsers()
|
||||
{
|
||||
$fn = array($this->list, 'getSubscribers');
|
||||
list($this->users, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Get a list of lists a user is subscribed to.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class ApiListSubscriptionsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $lists = array();
|
||||
var $cursor = -1;
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->cursor = (int) $this->arg('cursor', -1);
|
||||
$user = $this->getTargetUser($this->arg('user'));
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
$this->getLists();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the lists
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonLists($this->lists, $this->next_cursor, $this->prev_cursor);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function getLists()
|
||||
{
|
||||
$fn = array($this->target, 'getTagSubscriptions');
|
||||
# 20 lists
|
||||
list($this->lists, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Upload an image via the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Upload an image via the API. Returns a shortened URL for the image
|
||||
* to the user.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiMediaUploadAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Grab the file from the 'media' param, then store, and shorten
|
||||
*
|
||||
* @todo Upload throttle!
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
// TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
|
||||
// TRANS: %s is the number of bytes of the CONTENT_LENGTH.
|
||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||
intval($_SERVER['CONTENT_LENGTH']));
|
||||
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
}
|
||||
|
||||
// we could catch "NoUploadedMediaException" as "no media uploaded", but here we _always_ want an upload
|
||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||
|
||||
// Thumbnails will be generated/cached on demand when accessed (such as with /attachment/:id/thumbnail)
|
||||
|
||||
$this->showResponse($upload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a Twitpic-like response with the ID of the media file
|
||||
* and a (hopefully) shortened URL for it.
|
||||
*
|
||||
* @param MediaFile $upload the uploaded file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showResponse(MediaFile $upload)
|
||||
{
|
||||
$this->initDocument();
|
||||
$this->elementStart('rsp', array('stat' => 'ok'));
|
||||
$this->element('mediaid', null, $upload->fileRecord->id);
|
||||
$this->element('mediaurl', null, $upload->shortUrl());
|
||||
$this->elementEnd('rsp');
|
||||
$this->endDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrided clientError to show a more Twitpic-like error
|
||||
*
|
||||
* @param String $msg an error message
|
||||
*/
|
||||
function clientError($msg)
|
||||
{
|
||||
$this->initDocument();
|
||||
$this->elementStart('rsp', array('stat' => 'fail'));
|
||||
|
||||
// @todo add in error code
|
||||
$errAttr = array('msg' => $msg);
|
||||
|
||||
$this->element('err', $errAttr, null);
|
||||
$this->elementEnd('rsp');
|
||||
$this->endDocument();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for getting OAuth token credentials (exchange an authorized
|
||||
* request token for an access token)
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Action for getting OAuth token credentials (exchange an authorized
|
||||
* request token for an access token)
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiOAuthAccessTokenAction extends ApiOAuthAction
|
||||
{
|
||||
protected $reqToken = null;
|
||||
protected $verifier = null;
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$datastore = new ApiGNUsocialOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
$atok = $app = null;
|
||||
|
||||
// XXX: Insist that oauth_token and oauth_verifier be populated?
|
||||
// Spec doesn't say they MUST be.
|
||||
|
||||
try {
|
||||
$req = OAuthRequest::from_request();
|
||||
|
||||
$this->reqToken = $req->get_parameter('oauth_token');
|
||||
$this->verifier = $req->get_parameter('oauth_verifier');
|
||||
|
||||
$app = $datastore->getAppByRequestToken($this->reqToken);
|
||||
$atok = $server->fetch_access_token($req);
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
|
||||
common_debug(var_export($req, true));
|
||||
$code = $e->getCode();
|
||||
$this->clientError($e->getMessage(), empty($code) ? 401 : $code, 'text');
|
||||
}
|
||||
|
||||
if (empty($atok)) {
|
||||
// Token exchange failed -- log it
|
||||
|
||||
$msg = sprintf(
|
||||
'API OAuth - Failure exchanging OAuth request token for access token, '
|
||||
. 'request token = %s, verifier = %s',
|
||||
$this->reqToken,
|
||||
$this->verifier
|
||||
);
|
||||
|
||||
common_log(LOG_WARNING, $msg);
|
||||
// TRANS: Client error given from the OAuth API when the request token or verifier is invalid.
|
||||
$this->clientError(_('Invalid request token or verifier.'), 400, 'text');
|
||||
} else {
|
||||
common_log(
|
||||
LOG_INFO,
|
||||
sprintf(
|
||||
"Issued access token '%s' for application %d (%s).",
|
||||
$atok->key,
|
||||
$app->id,
|
||||
$app->name
|
||||
)
|
||||
);
|
||||
$this->showAccessToken($atok);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Display OAuth token credentials
|
||||
*
|
||||
* @param OAuthToken token the access token
|
||||
*/
|
||||
function showAccessToken($token)
|
||||
{
|
||||
header('Content-Type: application/x-www-form-urlencoded');
|
||||
print $token;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,707 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Authorize an OAuth request token
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010-2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize an OAuth request token
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiOAuthAuthorizeAction extends ApiOAuthAction
|
||||
{
|
||||
var $oauthTokenParam;
|
||||
var $reqToken;
|
||||
var $callback;
|
||||
var $app;
|
||||
var $nickname;
|
||||
var $password;
|
||||
var $store;
|
||||
|
||||
/**
|
||||
* Is this a read-only action?
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
$this->password = $this->arg('password');
|
||||
$this->oauthTokenParam = $this->arg('oauth_token');
|
||||
$this->mode = $this->arg('mode');
|
||||
$this->store = new ApiGNUsocialOAuthDataStore();
|
||||
|
||||
try {
|
||||
$this->app = $this->store->getAppByRequestToken($this->oauthTokenParam);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle input, produce output
|
||||
*
|
||||
* Switches on request method; either shows the form or handles its input.
|
||||
*
|
||||
* @param array $args $_REQUEST data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
||||
$this->handlePost();
|
||||
|
||||
} else {
|
||||
|
||||
// Make sure a oauth_token parameter was provided
|
||||
if (empty($this->oauthTokenParam)) {
|
||||
// TRANS: Client error given when no oauth_token was passed to the OAuth API.
|
||||
$this->clientError(_('No oauth_token parameter provided.'));
|
||||
} else {
|
||||
|
||||
// Check to make sure the token exists
|
||||
$this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
|
||||
|
||||
if (empty($this->reqToken)) {
|
||||
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
|
||||
$this->clientError(_('Invalid request token.'));
|
||||
} else {
|
||||
|
||||
// Check to make sure we haven't already authorized the token
|
||||
if ($this->reqToken->state != 0) {
|
||||
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
|
||||
$this->clientError(_('Request token already authorized.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure there's an app associated with this token
|
||||
if (empty($this->app)) {
|
||||
// TRANS: Client error given when an invalid request token was passed to the OAuth API.
|
||||
$this->clientError(_('Invalid request token.'));
|
||||
}
|
||||
|
||||
$name = $this->app->name;
|
||||
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
// check session token for CSRF protection.
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(
|
||||
// TRANS: Form validation error in API OAuth authorisation because of an invalid session token.
|
||||
_('There was a problem with your session token. Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// check creds
|
||||
|
||||
$user = null;
|
||||
|
||||
if (!common_logged_in()) {
|
||||
|
||||
// XXX Force credentials check?
|
||||
|
||||
// @fixme this should probably use a unified login form handler
|
||||
$user = null;
|
||||
if (Event::handle('StartOAuthLoginCheck', array($this, &$user))) {
|
||||
$user = common_check_user($this->nickname, $this->password);
|
||||
}
|
||||
Event::handle('EndOAuthLoginCheck', array($this, &$user));
|
||||
|
||||
if (empty($user)) {
|
||||
// TRANS: Form validation error given when an invalid username and/or password was passed to the OAuth API.
|
||||
$this->showForm(_("Invalid nickname / password!"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$user = common_current_user();
|
||||
}
|
||||
|
||||
// fetch the token
|
||||
$this->reqToken = $this->store->getTokenByKey($this->oauthTokenParam);
|
||||
assert(!empty($this->reqToken));
|
||||
|
||||
if ($this->arg('allow')) {
|
||||
// mark the req token as authorized
|
||||
try {
|
||||
$this->store->authorize_token($this->oauthTokenParam);
|
||||
} catch (Exception $e) {
|
||||
$this->serverError($e->getMessage());
|
||||
}
|
||||
|
||||
common_log(
|
||||
LOG_INFO,
|
||||
sprintf(
|
||||
"API OAuth - User %d (%s) has authorized request token %s for OAuth application %d (%s).",
|
||||
$user->id,
|
||||
$user->nickname,
|
||||
$this->reqToken->tok,
|
||||
$this->app->id,
|
||||
$this->app->name
|
||||
)
|
||||
);
|
||||
|
||||
$tokenAssoc = new Oauth_token_association();
|
||||
|
||||
$tokenAssoc->profile_id = $user->id;
|
||||
$tokenAssoc->application_id = $this->app->id;
|
||||
$tokenAssoc->token = $this->oauthTokenParam;
|
||||
$tokenAssoc->created = common_sql_now();
|
||||
|
||||
$result = $tokenAssoc->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($tokenAssoc, 'INSERT', __FILE__);
|
||||
// TRANS: Server error displayed when a database action fails.
|
||||
$this->serverError(_('Database error inserting oauth_token_association.'));
|
||||
}
|
||||
|
||||
$callback = $this->getCallback();
|
||||
|
||||
if (!empty($callback) && $this->reqToken->verified_callback != 'oob') {
|
||||
$targetUrl = $this->buildCallbackUrl(
|
||||
$callback,
|
||||
array(
|
||||
'oauth_token' => $this->oauthTokenParam,
|
||||
'oauth_verifier' => $this->reqToken->verifier // 1.0a
|
||||
)
|
||||
);
|
||||
|
||||
common_log(LOG_INFO, "Redirecting to callback: $targetUrl");
|
||||
|
||||
// Redirect the user to the provided OAuth callback
|
||||
common_redirect($targetUrl, 303);
|
||||
|
||||
} elseif ($this->app->type == 2) {
|
||||
// Strangely, a web application seems to want to do the OOB
|
||||
// workflow. Because no callback was specified anywhere.
|
||||
common_log(
|
||||
LOG_WARNING,
|
||||
sprintf(
|
||||
"API OAuth - No callback provided for OAuth web client ID %s (%s) "
|
||||
. "during authorization step. Falling back to OOB workflow.",
|
||||
$this->app->id,
|
||||
$this->app->name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Otherwise, inform the user that the rt was authorized
|
||||
$this->showAuthorized();
|
||||
} else if ($this->arg('cancel')) {
|
||||
common_log(
|
||||
LOG_INFO,
|
||||
sprintf(
|
||||
"API OAuth - User %d (%s) refused to authorize request token %s for OAuth application %d (%s).",
|
||||
$user->id,
|
||||
$user->nickname,
|
||||
$this->reqToken->tok,
|
||||
$this->app->id,
|
||||
$this->app->name
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
$this->store->revoke_token($this->oauthTokenParam, 0);
|
||||
} catch (Exception $e) {
|
||||
$this->ServerError($e->getMessage());
|
||||
}
|
||||
|
||||
$callback = $this->getCallback();
|
||||
|
||||
// If there's a callback available, inform the consumer the user
|
||||
// has refused authorization
|
||||
if (!empty($callback) && $this->reqToken->verified_callback != 'oob') {
|
||||
$targetUrl = $this->buildCallbackUrl(
|
||||
$callback,
|
||||
array(
|
||||
'oauth_problem' => 'user_refused',
|
||||
)
|
||||
);
|
||||
|
||||
common_log(LOG_INFO, "Redirecting to callback: $targetUrl");
|
||||
|
||||
// Redirect the user to the provided OAuth callback
|
||||
common_redirect($targetUrl, 303);
|
||||
}
|
||||
|
||||
// otherwise inform the user that authorization for the rt was declined
|
||||
$this->showCanceled();
|
||||
|
||||
} else {
|
||||
// TRANS: Client error given on when invalid data was passed through a form in the OAuth API.
|
||||
$this->clientError(_('Unexpected form submission.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show body - override to add a special CSS class for the authorize
|
||||
* page's "desktop mode" (minimal display)
|
||||
*
|
||||
* Calls template methods
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showBody()
|
||||
{
|
||||
$bodyClasses = array();
|
||||
|
||||
if ($this->desktopMode()) {
|
||||
$bodyClasses[] = 'oauth-desktop-mode';
|
||||
}
|
||||
|
||||
if (common_current_user()) {
|
||||
$bodyClasses[] = 'user_in';
|
||||
}
|
||||
|
||||
$attrs = array('id' => strtolower($this->trimmed('action')));
|
||||
|
||||
if (!empty($bodyClasses)) {
|
||||
$attrs['class'] = implode(' ', $bodyClasses);
|
||||
}
|
||||
|
||||
$this->elementStart('body', $attrs);
|
||||
|
||||
$this->elementStart('div', array('id' => 'wrap'));
|
||||
if (Event::handle('StartShowHeader', array($this))) {
|
||||
$this->showHeader();
|
||||
Event::handle('EndShowHeader', array($this));
|
||||
}
|
||||
$this->showCore();
|
||||
if (Event::handle('StartShowFooter', array($this))) {
|
||||
$this->showFooter();
|
||||
Event::handle('EndShowFooter', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
$this->showScripts();
|
||||
$this->elementEnd('body');
|
||||
}
|
||||
|
||||
function showForm($error=null)
|
||||
{
|
||||
$this->error = $error;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showScripts()
|
||||
{
|
||||
parent::showScripts();
|
||||
if (!common_logged_in()) {
|
||||
$this->autofocus('nickname');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string title of the page
|
||||
*/
|
||||
function title()
|
||||
{
|
||||
// TRANS: Title for a page where a user can confirm/deny account access by an external application.
|
||||
return _('An application would like to connect to your account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the authorization form.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_apioauthauthorize',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('ApiOAuthAuthorize')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', array('id' => 'apioauthauthorize_allowdeny'),
|
||||
// TRANS: Fieldset legend.
|
||||
_('Allow or deny access'));
|
||||
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->hidden('mode', $this->mode);
|
||||
$this->hidden('oauth_token', $this->oauthTokenParam);
|
||||
$this->hidden('oauth_callback', $this->callback);
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->elementStart('p');
|
||||
if (!empty($this->app->icon) && $this->app->name != 'anonymous') {
|
||||
$this->element('img', array('src' => $this->app->icon));
|
||||
}
|
||||
|
||||
$access = ($this->app->access_type & Oauth_application::$writeAccess) ?
|
||||
'access and update' : 'access';
|
||||
|
||||
if ($this->app->name == 'anonymous') {
|
||||
// Special message for the anonymous app and consumer.
|
||||
// TRANS: User notification of external application requesting account access.
|
||||
// TRANS: %3$s is the access type requested (read-write or read-only), %4$s is the StatusNet sitename.
|
||||
$msg = _('An application would like the ability ' .
|
||||
'to <strong>%3$s</strong> your %4$s account data. ' .
|
||||
'You should only give access to your %4$s account ' .
|
||||
'to third parties you trust.');
|
||||
} else {
|
||||
// TRANS: User notification of external application requesting account access.
|
||||
// TRANS: %1$s is the application name requesting access, %2$s is the organisation behind the application,
|
||||
// TRANS: %3$s is the access type requested, %4$s is the StatusNet sitename.
|
||||
$msg = _('The application <strong>%1$s</strong> by ' .
|
||||
'<strong>%2$s</strong> would like the ability ' .
|
||||
'to <strong>%3$s</strong> your %4$s account data. ' .
|
||||
'You should only give access to your %4$s account ' .
|
||||
'to third parties you trust.');
|
||||
}
|
||||
|
||||
$this->raw(sprintf($msg,
|
||||
$this->app->name,
|
||||
$this->app->organization,
|
||||
$access,
|
||||
common_config('site', 'name')));
|
||||
$this->elementEnd('p');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
// quickie hack
|
||||
$button = false;
|
||||
if (!common_logged_in()) {
|
||||
if (Event::handle('StartOAuthLoginForm', array($this, &$button))) {
|
||||
$this->elementStart('fieldset');
|
||||
// TRANS: Fieldset legend.
|
||||
$this->element('legend', null, _m('LEGEND','Account'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label on OAuth API authorisation form.
|
||||
$this->input('nickname', _('Nickname'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
// TRANS: Field label on OAuth API authorisation form.
|
||||
$this->password('password', _('Password'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
}
|
||||
Event::handle('EndOAuthLoginForm', array($this, &$button));
|
||||
}
|
||||
|
||||
$this->element('input', array('id' => 'cancel_submit',
|
||||
'class' => 'submit submit form_action-primary',
|
||||
'name' => 'cancel',
|
||||
'type' => 'submit',
|
||||
// TRANS: Button text that when clicked will cancel the process of allowing access to an account
|
||||
// TRANS: by an external application.
|
||||
'value' => _m('BUTTON','Cancel')));
|
||||
|
||||
$this->element('input', array('id' => 'allow_submit',
|
||||
'class' => 'submit submit form_action-secondary',
|
||||
'name' => 'allow',
|
||||
'type' => 'submit',
|
||||
// TRANS: Button text that when clicked will allow access to an account by an external application.
|
||||
'value' => $button ? $button : _m('BUTTON','Allow')));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for using the form
|
||||
*
|
||||
* For "remembered" logins, we make the user re-login when they
|
||||
* try to change settings. Different instructions for this case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Form instructions.
|
||||
return _('Authorize access to your account information.');
|
||||
}
|
||||
|
||||
/**
|
||||
* A local menu
|
||||
*
|
||||
* Shows different login/register actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showLocalNav()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to see if a the "mode" parameter is present in the request
|
||||
* and set to "desktop". If it is, the page is meant to be displayed in
|
||||
* a small frame of another application, and we should suppress the
|
||||
* header, aside, and footer.
|
||||
*/
|
||||
function desktopMode()
|
||||
{
|
||||
if (isset($this->mode) && $this->mode == 'desktop') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showHeader()
|
||||
{
|
||||
if ($this->desktopMode() == false) {
|
||||
parent::showHeader();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showAside()
|
||||
{
|
||||
if ($this->desktopMode() == false) {
|
||||
parent::showAside();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showFooter()
|
||||
{
|
||||
if ($this->desktopMode() == false) {
|
||||
parent::showFooter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show site notice.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showSiteNotice()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notice form.
|
||||
*
|
||||
* Show the form for posting a new notice
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showNoticeForm()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/*
|
||||
* Show a nice message confirming the authorization
|
||||
* operation was canceled.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showCanceled()
|
||||
{
|
||||
$info = new InfoAction(
|
||||
// TRANS: Header for user notification after revoking OAuth access to an application.
|
||||
_('Authorization canceled.'),
|
||||
sprintf(
|
||||
// TRANS: User notification after revoking OAuth access to an application.
|
||||
// TRANS: %s is an OAuth token.
|
||||
_('The request token %s has been revoked.'),
|
||||
$this->oauthTokenParam
|
||||
)
|
||||
);
|
||||
|
||||
$info->showPage();
|
||||
}
|
||||
|
||||
/*
|
||||
* Show a nice message that the authorization was successful.
|
||||
* If the operation is out-of-band, show a pin.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showAuthorized()
|
||||
{
|
||||
$title = null;
|
||||
$msg = null;
|
||||
|
||||
if ($this->app->name == 'anonymous') {
|
||||
|
||||
$title =
|
||||
// TRANS: Title of the page notifying the user that an anonymous client application was successfully authorized to access the user's account with OAuth.
|
||||
_('You have successfully authorized the application');
|
||||
|
||||
$msg =
|
||||
// TRANS: Message notifying the user that an anonymous client application was successfully authorized to access the user's account with OAuth.
|
||||
_('Please return to the application and enter the following security code to complete the process.');
|
||||
|
||||
} else {
|
||||
|
||||
$title = sprintf(
|
||||
// TRANS: Title of the page notifying the user that the client application was successfully authorized to access the user's account with OAuth.
|
||||
// TRANS: %s is the authorised application name.
|
||||
_('You have successfully authorized %s'),
|
||||
$this->app->name
|
||||
);
|
||||
|
||||
$msg = sprintf(
|
||||
// TRANS: Message notifying the user that the client application was successfully authorized to access the user's account with OAuth.
|
||||
// TRANS: %s is the authorised application name.
|
||||
_('Please return to %s and enter the following security code to complete the process.'),
|
||||
$this->app->name
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if ($this->reqToken->verified_callback == 'oob') {
|
||||
$pin = new ApiOAuthPinAction(
|
||||
$title,
|
||||
$msg,
|
||||
$this->reqToken->verifier,
|
||||
$this->desktopMode()
|
||||
);
|
||||
$pin->showPage();
|
||||
} else {
|
||||
// NOTE: This would only happen if an application registered as
|
||||
// a web application but sent in 'oob' for the oauth_callback
|
||||
// parameter. Usually web apps will send in a callback and
|
||||
// not use the pin-based workflow.
|
||||
|
||||
$info = new InfoAction(
|
||||
$title,
|
||||
$msg,
|
||||
$this->oauthTokenParam,
|
||||
$this->reqToken->verifier
|
||||
);
|
||||
|
||||
$info->showPage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out what the callback should be
|
||||
*/
|
||||
function getCallback()
|
||||
{
|
||||
$callback = null;
|
||||
|
||||
// Return the verified callback if we have one
|
||||
if ($this->reqToken->verified_callback != 'oob') {
|
||||
|
||||
$callback = $this->reqToken->verified_callback;
|
||||
|
||||
// Otherwise return the callback that was provided when
|
||||
// registering the app
|
||||
if (empty($callback)) {
|
||||
|
||||
common_debug(
|
||||
"No verified callback found for request token, using application callback: "
|
||||
. $this->app->callback_url,
|
||||
__FILE__
|
||||
);
|
||||
|
||||
$callback = $this->app->callback_url;
|
||||
}
|
||||
}
|
||||
|
||||
return $callback;
|
||||
}
|
||||
|
||||
/*
|
||||
* Properly format the callback URL and parameters so it's
|
||||
* suitable for a redirect in the OAuth dance
|
||||
*
|
||||
* @param string $url the URL
|
||||
* @param array $params an array of parameters
|
||||
*
|
||||
* @return string $url a URL to use for redirecting to
|
||||
*/
|
||||
function buildCallbackUrl($url, $params)
|
||||
{
|
||||
foreach ($params as $k => $v) {
|
||||
$url = $this->appendQueryVar(
|
||||
$url,
|
||||
OAuthUtil::urlencode_rfc3986($k),
|
||||
OAuthUtil::urlencode_rfc3986($v)
|
||||
);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/*
|
||||
* Append a new query parameter after any existing query
|
||||
* parameters.
|
||||
*
|
||||
* @param string $url the URL
|
||||
* @prarm string $k the parameter name
|
||||
* @param string $v value of the paramter
|
||||
*
|
||||
* @return string $url the new URL with added parameter
|
||||
*/
|
||||
function appendQueryVar($url, $k, $v) {
|
||||
$url = preg_replace('/(.*)(\?|&)' . $k . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
|
||||
$url = substr($url, 0, -1);
|
||||
if (strpos($url, '?') === false) {
|
||||
return ($url . '?' . $k . '=' . $v);
|
||||
} else {
|
||||
return ($url . '&' . $k . '=' . $v);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for displaying an OAuth verifier pin
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for displaying an OAuth verifier pin
|
||||
*
|
||||
* XXX: I'm pretty sure we don't need to check the logged in state here. -- Zach
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiOAuthPinAction extends InfoAction
|
||||
{
|
||||
function __construct($title, $message, $verifier, $desktopMode = false)
|
||||
{
|
||||
$this->verifier = $verifier;
|
||||
$this->title = $title;
|
||||
$this->desktopMode = $desktopMode;
|
||||
parent::__construct($title, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show body - override to add a special CSS class for the pin pages's
|
||||
* "desktop mode" (minimal display)
|
||||
*
|
||||
* Calls template methods
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showBody()
|
||||
{
|
||||
$bodyClasses = array();
|
||||
|
||||
if ($this->desktopMode) {
|
||||
$bodyClasses[] = 'oauth-desktop-mode';
|
||||
}
|
||||
|
||||
if (common_current_user()) {
|
||||
$bodyClasses[] = 'user_in';
|
||||
}
|
||||
|
||||
$attrs = array('id' => strtolower($this->trimmed('action')));
|
||||
|
||||
if (!empty($bodyClasses)) {
|
||||
$attrs['class'] = implode(' ', $bodyClasses);
|
||||
}
|
||||
|
||||
$this->elementStart('body', $attrs);
|
||||
|
||||
$this->elementStart('div', array('id' => 'wrap'));
|
||||
if (Event::handle('StartShowHeader', array($this))) {
|
||||
$this->showHeader();
|
||||
Event::handle('EndShowHeader', array($this));
|
||||
}
|
||||
$this->showCore();
|
||||
if (Event::handle('StartShowFooter', array($this))) {
|
||||
$this->showFooter();
|
||||
Event::handle('EndShowFooter', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
$this->showScripts();
|
||||
$this->elementEnd('body');
|
||||
}
|
||||
|
||||
/**
|
||||
* A local menu
|
||||
*
|
||||
* Shows different login/register actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showLocalNav()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showHeader()
|
||||
{
|
||||
if ($this->desktopMode == false) {
|
||||
parent::showHeader();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showAside()
|
||||
{
|
||||
if ($this->desktopMode == false) {
|
||||
parent::showAside();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override - suppress output in "desktop" mode
|
||||
*/
|
||||
function showFooter()
|
||||
{
|
||||
if ($this->desktopMode == false) {
|
||||
parent::showFooter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show site notice.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showSiteNotice()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notice form.
|
||||
*
|
||||
* Show the form for posting a new notice
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showNoticeForm()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Display content.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showContent()
|
||||
{
|
||||
$this->element('div', array('class' => 'info'), $this->message);
|
||||
$this->element('div', array('id' => 'oauth_pin'), $this->verifier);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Issue temporary OAuth credentials (a request token)
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue temporary OAuth credentials (a request token)
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiOAuthRequestTokenAction extends ApiOAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// XXX: support "force_login" parameter like Twitter? (Forces the user to enter
|
||||
// their credentials to ensure the correct users account is authorized.)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request for temporary OAuth credentials
|
||||
*
|
||||
* Make sure the request is kosher, then emit a set of temporary
|
||||
* credentials -- AKA an unauthorized request token.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$datastore = new ApiGNUsocialOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
try {
|
||||
|
||||
$req = OAuthRequest::from_request();
|
||||
|
||||
// verify callback
|
||||
if (!$this->verifyCallback($req->get_parameter('oauth_callback'))) {
|
||||
throw new OAuthException(
|
||||
"You must provide a valid URL or 'oob' in oauth_callback.",
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
// check signature and issue a new request token
|
||||
$token = $server->fetch_request_token($req);
|
||||
|
||||
common_log(
|
||||
LOG_INFO,
|
||||
sprintf(
|
||||
"API OAuth - Issued request token %s for consumer %s with oauth_callback %s",
|
||||
$token->key,
|
||||
$req->get_parameter('oauth_consumer_key'),
|
||||
"'" . $req->get_parameter('oauth_callback') ."'"
|
||||
)
|
||||
);
|
||||
|
||||
// return token to the client
|
||||
$this->showRequestToken($token);
|
||||
|
||||
} catch (OAuthException $e) {
|
||||
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
|
||||
|
||||
// Return 401 for for bad credentials or signature problems,
|
||||
// and 400 for missing or unsupported parameters
|
||||
|
||||
$code = $e->getCode();
|
||||
$this->clientError($e->getMessage(), empty($code) ? 401 : $code, 'text');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Display temporary OAuth credentials
|
||||
*/
|
||||
function showRequestToken($token)
|
||||
{
|
||||
header('Content-Type: application/x-www-form-urlencoded');
|
||||
print $token;
|
||||
print '&oauth_callback_confirmed=true';
|
||||
}
|
||||
|
||||
/* Make sure the callback parameter contains either a real URL
|
||||
* or the string 'oob'.
|
||||
*
|
||||
* @todo Check for evil/banned URLs here
|
||||
*
|
||||
* @return boolean true or false
|
||||
*/
|
||||
function verifyCallback($callback)
|
||||
{
|
||||
if ($callback == "oob") {
|
||||
common_debug("OAuth request token requested for out of band client.");
|
||||
|
||||
// XXX: Should we throw an error if a client is registered as a
|
||||
// web application but requests the pin based workflow? For now I'm
|
||||
// allowing the workflow to proceed and issuing a pin. --Zach
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return filter_var($callback, FILTER_VALIDATE_URL);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,392 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for showing Twitter-like Atom search results
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for outputting search results in Twitter compatible Atom
|
||||
* format.
|
||||
*
|
||||
* TODO: abstract Atom stuff into a ruseable base class like
|
||||
* RSS10Action.
|
||||
*
|
||||
* @category Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see ApiPrivateAuthAction
|
||||
*/
|
||||
class ApiSearchAtomAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $cnt;
|
||||
var $query;
|
||||
var $lang;
|
||||
var $rpp;
|
||||
var $page;
|
||||
var $since_id;
|
||||
var $geocode;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Just wraps the Action constructor.
|
||||
*
|
||||
* @param string $output URI to output to, default = stdout
|
||||
* @param boolean $indent Whether to indent output, default true
|
||||
*
|
||||
* @see Action::__construct
|
||||
*/
|
||||
function __construct($output='php://output', $indent=null)
|
||||
{
|
||||
parent::__construct($output, $indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to write to the database?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadonly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read arguments and initialize members
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return boolean success
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->query = $this->trimmed('q');
|
||||
$this->lang = $this->trimmed('lang');
|
||||
$this->rpp = $this->trimmed('rpp');
|
||||
|
||||
if (!$this->rpp) {
|
||||
$this->rpp = 15;
|
||||
}
|
||||
|
||||
if ($this->rpp > 100) {
|
||||
$this->rpp = 100;
|
||||
}
|
||||
|
||||
$this->page = $this->trimmed('page');
|
||||
|
||||
if (!$this->page) {
|
||||
$this->page = 1;
|
||||
}
|
||||
|
||||
// TODO: Suppport max_id -- we need to tweak the backend
|
||||
// Search classes to support it.
|
||||
|
||||
$this->since_id = $this->trimmed('since_id');
|
||||
$this->geocode = $this->trimmed('geocode');
|
||||
|
||||
// TODO: Also, language and geocode
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
common_debug("In apisearchatom handle()");
|
||||
$this->showAtom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notices to output as results. This also sets some class
|
||||
* attrs so we can use them to calculate pagination, and output
|
||||
* since_id and max_id.
|
||||
*
|
||||
* @return array an array of Notice objects sorted in reverse chron
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
// TODO: Support search operators like from: and to:, boolean, etc.
|
||||
|
||||
$notices = array();
|
||||
$notice = new Notice();
|
||||
|
||||
// lcase it for comparison
|
||||
$q = strtolower($this->query);
|
||||
|
||||
$search_engine = $notice->getSearchEngine('notice');
|
||||
$search_engine->set_sort_mode('chron');
|
||||
$search_engine->limit(($this->page - 1) * $this->rpp,
|
||||
$this->rpp + 1, true);
|
||||
if (false === $search_engine->query($q)) {
|
||||
$this->cnt = 0;
|
||||
} else {
|
||||
$this->cnt = $notice->find();
|
||||
}
|
||||
|
||||
$cnt = 0;
|
||||
$this->max_id = 0;
|
||||
|
||||
if ($this->cnt > 0) {
|
||||
while ($notice->fetch()) {
|
||||
++$cnt;
|
||||
|
||||
if (!$this->max_id) {
|
||||
$this->max_id = $notice->id;
|
||||
}
|
||||
|
||||
if ($this->since_id && $notice->id <= $this->since_id) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($cnt > $this->rpp) {
|
||||
break;
|
||||
}
|
||||
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output search results as an Atom feed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showAtom()
|
||||
{
|
||||
$notices = $this->getNotices();
|
||||
|
||||
$this->initAtom();
|
||||
$this->showFeed();
|
||||
|
||||
foreach ($notices as $n) {
|
||||
$profile = $n->getProfile();
|
||||
|
||||
// Don't show notices from deleted users
|
||||
|
||||
if (!empty($profile)) {
|
||||
$this->showEntry($n);
|
||||
}
|
||||
}
|
||||
|
||||
$this->endAtom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show feed specific Atom elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showFeed()
|
||||
{
|
||||
// TODO: A9 OpenSearch stuff like search.twitter.com?
|
||||
|
||||
$server = common_config('site', 'server');
|
||||
$sitename = common_config('site', 'name');
|
||||
|
||||
// XXX: Use xmlns:statusnet instead?
|
||||
|
||||
$this->elementStart('feed',
|
||||
array('xmlns' => 'http://www.w3.org/2005/Atom',
|
||||
|
||||
// XXX: xmlns:twitter causes Atom validation to fail
|
||||
// It's used for the source attr on notices
|
||||
|
||||
'xmlns:twitter' => 'http://api.twitter.com/',
|
||||
'xml:lang' => 'en-US')); // XXX Other locales ?
|
||||
|
||||
$taguribase = TagURI::base();
|
||||
$this->element('id', null, "tag:$taguribase:search/$server");
|
||||
|
||||
$site_uri = common_path(false);
|
||||
|
||||
$search_uri = $site_uri . 'api/search.atom?q=' . urlencode($this->query);
|
||||
|
||||
if ($this->rpp != 15) {
|
||||
$search_uri .= '&rpp=' . $this->rpp;
|
||||
}
|
||||
|
||||
// FIXME: this alternate link is not quite right because our
|
||||
// web-based notice search doesn't support a rpp (responses per
|
||||
// page) param yet
|
||||
|
||||
$this->element('link', array('type' => 'text/html',
|
||||
'rel' => 'alternate',
|
||||
'href' => $site_uri . 'search/notice?q=' .
|
||||
urlencode($this->query)));
|
||||
|
||||
// self link
|
||||
|
||||
$self_uri = $search_uri;
|
||||
$self_uri .= ($this->page > 1) ? '&page=' . $this->page : '';
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'self',
|
||||
'href' => $self_uri));
|
||||
|
||||
// @todo Needs i18n?
|
||||
$this->element('title', null, "$this->query - $sitename Search");
|
||||
$this->element('updated', null, common_date_iso8601('now'));
|
||||
|
||||
// XXX: The below "rel" links are not valid Atom, but it's what
|
||||
// Twitter does...
|
||||
|
||||
// refresh link
|
||||
|
||||
$refresh_uri = $search_uri . "&since_id=" . $this->max_id;
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'refresh',
|
||||
'href' => $refresh_uri));
|
||||
|
||||
// pagination links
|
||||
|
||||
if ($this->cnt > $this->rpp) {
|
||||
|
||||
$next_uri = $search_uri . "&max_id=" . $this->max_id .
|
||||
'&page=' . ($this->page + 1);
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'next',
|
||||
'href' => $next_uri));
|
||||
}
|
||||
|
||||
if ($this->page > 1) {
|
||||
|
||||
$previous_uri = $search_uri . "&max_id=" . $this->max_id .
|
||||
'&page=' . ($this->page - 1);
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'previous',
|
||||
'href' => $previous_uri));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an Atom entry similar to search.twitter.com's based on
|
||||
* a given notice
|
||||
*
|
||||
* @param Notice $notice the notice to use
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showEntry($notice)
|
||||
{
|
||||
$server = common_config('site', 'server');
|
||||
$profile = $notice->getProfile();
|
||||
$nurl = common_local_url('shownotice', array('notice' => $notice->id));
|
||||
|
||||
$this->elementStart('entry');
|
||||
|
||||
$taguribase = TagURI::base();
|
||||
|
||||
$this->element('id', null, "tag:$taguribase:$notice->id");
|
||||
$this->element('published', null, common_date_w3dtf($notice->created));
|
||||
$this->element('link', array('type' => 'text/html',
|
||||
'rel' => 'alternate',
|
||||
'href' => $nurl));
|
||||
$this->element('title', null, common_xml_safe_str(trim($notice->content)));
|
||||
$this->element('content', array('type' => 'html'), $notice->rendered);
|
||||
$this->element('updated', null, common_date_w3dtf($notice->created));
|
||||
$this->element('link', array('type' => 'image/png',
|
||||
// XXX: Twitter uses rel="image" (not valid)
|
||||
'rel' => 'related',
|
||||
'href' => $profile->avatarUrl()));
|
||||
|
||||
// @todo: Here is where we'd put in a link to an atom feed for threads
|
||||
|
||||
$source = null;
|
||||
|
||||
$ns = $notice->getSource();
|
||||
if ($ns instanceof Notice_source) {
|
||||
if (!empty($ns->name) && !empty($ns->url)) {
|
||||
$source = '<a href="'
|
||||
. htmlspecialchars($ns->url)
|
||||
. '" rel="nofollow">'
|
||||
. htmlspecialchars($ns->name)
|
||||
. '</a>';
|
||||
} else {
|
||||
$source = $ns->code;
|
||||
}
|
||||
}
|
||||
|
||||
$this->element("twitter:source", null, $source);
|
||||
|
||||
$this->elementStart('author');
|
||||
|
||||
$name = $profile->nickname;
|
||||
|
||||
if ($profile->fullname) {
|
||||
// @todo Needs proper i18n?
|
||||
$name .= ' (' . $profile->fullname . ')';
|
||||
}
|
||||
|
||||
$this->element('name', null, $name);
|
||||
$this->element('uri', null, common_profile_uri($profile));
|
||||
$this->elementEnd('author');
|
||||
|
||||
$this->elementEnd('entry');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Atom output, send headers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function initAtom()
|
||||
{
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
$this->startXml();
|
||||
}
|
||||
|
||||
/**
|
||||
* End the Atom feed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function endAtom()
|
||||
{
|
||||
$this->elementEnd('feed');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for showing Twitter-like JSON search results
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category Search
|
||||
* @package GNUsocial
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2010 StatusNet, Inc.
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Action handler for Twitter-compatible API search
|
||||
*
|
||||
* @category Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
* @see ApiAction
|
||||
*/
|
||||
class ApiSearchJSONAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $query;
|
||||
var $lang;
|
||||
var $rpp;
|
||||
var $page;
|
||||
var $since_id;
|
||||
var $limit;
|
||||
var $geocode;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean true if nothing goes wrong
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->query = $this->trimmed('q');
|
||||
$this->lang = $this->trimmed('lang');
|
||||
$this->rpp = $this->trimmed('rpp');
|
||||
|
||||
if (!$this->rpp) {
|
||||
$this->rpp = 15;
|
||||
}
|
||||
|
||||
if ($this->rpp > 100) {
|
||||
$this->rpp = 100;
|
||||
}
|
||||
|
||||
$this->page = $this->trimmed('page');
|
||||
|
||||
if (!$this->page) {
|
||||
$this->page = 1;
|
||||
}
|
||||
|
||||
// TODO: Suppport max_id -- we need to tweak the backend
|
||||
// Search classes to support it.
|
||||
|
||||
$this->since_id = $this->trimmed('since_id');
|
||||
$this->geocode = $this->trimmed('geocode');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show search results
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showResults()
|
||||
{
|
||||
// TODO: Support search operators like from: and to:, boolean, etc.
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$this->notices = array();
|
||||
$search_engine = $notice->getSearchEngine('notice');
|
||||
$search_engine->set_sort_mode('chron');
|
||||
$search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1);
|
||||
if ($search_engine->query($this->query)) {
|
||||
$cnt = $notice->find();
|
||||
$this->notices = $notice->fetchAll();
|
||||
}
|
||||
|
||||
$this->showJsonTimeline($this->notices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to write to the database?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Destroy a notice through the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes one of the authenticating user's statuses (notices).
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiStatusesDestroyAction extends ApiAuthAction
|
||||
{
|
||||
var $status = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
$this->notice_id = (int)$this->trimmed('id');
|
||||
|
||||
if (empty($notice_id)) {
|
||||
$this->notice_id = (int)$this->arg('id');
|
||||
}
|
||||
|
||||
$this->notice = Notice::getKV((int)$this->notice_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Delete the notice and all related replies
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
_('API method not found.'),
|
||||
404
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed trying to delete a status not using POST or DELETE.
|
||||
// TRANS: POST and DELETE should not be translated.
|
||||
_('This method requires a POST or DELETE.'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->notice)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed trying to delete a status with an invalid ID.
|
||||
_('No status found with that ID.'),
|
||||
404, $this->format
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->user->id == $this->notice->profile_id) {
|
||||
if (Event::handle('StartDeleteOwnNotice', array($this->user, $this->notice))) {
|
||||
$this->notice->delete();
|
||||
Event::handle('EndDeleteOwnNotice', array($this->user, $this->notice));
|
||||
}
|
||||
$this->showNotice();
|
||||
} else {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed trying to delete a status of another user.
|
||||
_('You may not delete another user\'s status.'),
|
||||
403,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the deleted notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showNotice()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
if ($this->format == 'xml') {
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->show_single_json_status($this->notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Repeat a notice through the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Repeat a notice through the API
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiStatusesRetweetAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $original = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = $this->trimmed('id');
|
||||
|
||||
$this->original = Notice::getKV('id', $id);
|
||||
|
||||
if (!$this->original instanceof Notice) {
|
||||
// TRANS: Client error displayed trying to repeat a non-existing notice through the API.
|
||||
$this->clientError(_('No such notice.'), 400, $this->format);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$repeat = $this->original->repeat($this->scoped, $this->source);
|
||||
|
||||
$this->showNotice($repeat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the resulting notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showNotice($notice)
|
||||
{
|
||||
if (!empty($notice)) {
|
||||
if ($this->format == 'xml') {
|
||||
$this->showSingleXmlStatus($notice);
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->show_single_json_status($notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show up to 100 repeats of a notice
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show up to 100 repeats of a notice
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiStatusesRetweetsAction extends ApiAuthAction
|
||||
{
|
||||
const MAXCOUNT = 100;
|
||||
|
||||
var $original = null;
|
||||
var $cnt = self::MAXCOUNT;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = $this->trimmed('id');
|
||||
|
||||
$this->original = Notice::getKV('id', $id);
|
||||
|
||||
if (empty($this->original)) {
|
||||
// TRANS: Client error displayed trying to display redents of a non-exiting notice.
|
||||
$this->clientError(_('No such notice.'),
|
||||
400, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cnt = $this->trimmed('count');
|
||||
|
||||
if (empty($cnt) || !is_integer($cnt)) {
|
||||
$cnt = 100;
|
||||
} else {
|
||||
$this->cnt = min((int)$cnt, self::MAXCOUNT);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$strm = $this->original->repeatStream($this->cnt);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($strm);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($strm);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a notice (as a Twitter-style status)
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Returns the notice specified by id as a Twitter-style status and inline user
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiStatusesShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $notice_id = null;
|
||||
var $notice = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// 'id' is an undocumented parameter in Twitter's API. Several
|
||||
// clients make use of it, so we support it too.
|
||||
|
||||
// show.json?id=12345 takes precedence over /show/12345.json
|
||||
|
||||
$this->notice_id = (int)$this->trimmed('id');
|
||||
|
||||
$this->notice = Notice::getKV('id', $this->notice_id);
|
||||
if (!$this->notice instanceof Notice) {
|
||||
$deleted = Deleted_notice::getKV('id', $this->notice_id);
|
||||
if ($deleted instanceof Deleted_notice) {
|
||||
// TRANS: Client error displayed trying to show a deleted notice.
|
||||
$this->clientError(_('Notice deleted.'), 410);
|
||||
}
|
||||
// TRANS: Client error displayed trying to show a non-existing notice.
|
||||
$this->clientError(_('No such notice.'), 404);
|
||||
}
|
||||
if (!$this->notice->inScope($this->scoped)) {
|
||||
// TRANS: Client exception thrown when trying a view a notice the user has no access to.
|
||||
throw new ClientException(_('Access restricted.'), 403);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json', 'atom'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
switch ($_SERVER['REQUEST_METHOD']) {
|
||||
case 'GET':
|
||||
$this->showNotice();
|
||||
break;
|
||||
case 'DELETE':
|
||||
$this->deleteNotice();
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed calling an unsupported HTTP error in API status show.
|
||||
$this->clientError(_('HTTP method not supported.'), 405);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showNotice()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_single_json_status($this->notice);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->showSingleAtomStatus($this->notice);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Exception thrown requesting an unsupported notice output format.
|
||||
// TRANS: %s is the requested output format.
|
||||
throw new Exception(sprintf(_("Unsupported format: %s."), $this->format));
|
||||
}
|
||||
} else {
|
||||
// XXX: Twitter just sets a 404 header and doens't bother
|
||||
// to return an err msg
|
||||
|
||||
$deleted = Deleted_notice::getKV($this->notice_id);
|
||||
|
||||
if (!empty($deleted)) {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed requesting a deleted status.
|
||||
_('Status deleted.'),
|
||||
410,
|
||||
$this->format
|
||||
);
|
||||
} else {
|
||||
$this->clientError(
|
||||
// TRANS: Client error displayed requesting a status with an invalid ID.
|
||||
_('No status with that ID found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this notice last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
return strtotime($this->notice->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this notice
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the notice
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->notice->id,
|
||||
strtotime($this->notice->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function deleteNotice()
|
||||
{
|
||||
if ($this->format != 'atom') {
|
||||
// TRANS: Client error displayed when trying to delete a notice not using the Atom format.
|
||||
$this->clientError(_('Can only delete using the Atom format.'));
|
||||
}
|
||||
|
||||
if (empty($this->auth_user) ||
|
||||
($this->notice->profile_id != $this->auth_user->id &&
|
||||
!$this->auth_user->hasRight(Right::DELETEOTHERSNOTICE))) {
|
||||
// TRANS: Client error displayed when a user has no rights to delete notices of other users.
|
||||
$this->clientError(_('Cannot delete this notice.'), 403);
|
||||
}
|
||||
|
||||
if (Event::handle('StartDeleteOwnNotice', array($this->auth_user, $this->notice))) {
|
||||
$this->notice->delete();
|
||||
Event::handle('EndDeleteOwnNotice', array($this->auth_user, $this->notice));
|
||||
}
|
||||
|
||||
// @fixme is there better output we could do here?
|
||||
|
||||
header('HTTP/1.1 200 OK');
|
||||
header('Content-Type: text/plain');
|
||||
// TRANS: Confirmation of notice deletion in API. %d is the ID (number) of the deleted notice.
|
||||
print(sprintf(_('Deleted notice %d'), $this->notice->id));
|
||||
print("\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,345 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Post a notice (update your status) through the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page statusesupdate statuses/update
|
||||
|
||||
@section Description
|
||||
Updates the authenticating user's status. Requires the status parameter specified below.
|
||||
Request must be a POST.
|
||||
|
||||
@par URL pattern
|
||||
/api/statuses/update.:format
|
||||
|
||||
@par Formats (:format)
|
||||
xml, json
|
||||
|
||||
@par HTTP Method(s)
|
||||
POST
|
||||
|
||||
@par Requires Authentication
|
||||
Yes
|
||||
|
||||
@param status (Required) The URL-encoded text of the status update.
|
||||
@param source (Optional) The source application name, if using HTTP authentication or an anonymous OAuth consumer.
|
||||
@param in_reply_to_status_id (Optional) The ID of an existing status that the update is in reply to.
|
||||
@param lat (Optional) The latitude the status refers to.
|
||||
@param long (Optional) The longitude the status refers to.
|
||||
@param media (Optional) a media upload, such as an image or movie file.
|
||||
|
||||
@sa @ref authentication
|
||||
@sa @ref apiroot
|
||||
|
||||
@subsection usagenotes Usage notes
|
||||
|
||||
@li The URL pattern is relative to the @ref apiroot.
|
||||
@li If the @e source parameter is not supplied the source of the status will default to 'api'. When authenticated via a registered OAuth application, the application's registered name and URL will always override the source parameter.
|
||||
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
|
||||
to encode the latitude and longitude (see example response below <georss:point>).
|
||||
@li Data uploaded via the @e media parameter should be multipart/form-data encoded.
|
||||
|
||||
@subsection exampleusage Example usage
|
||||
|
||||
@verbatim
|
||||
curl -u username:password http://example.com/api/statuses/update.xml -d status='Howdy!' -d lat='30.468' -d long='-94.743'
|
||||
@endverbatim
|
||||
|
||||
@subsection exampleresponse Example response
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<status>
|
||||
<text>Howdy!</text>
|
||||
<truncated>false</truncated>
|
||||
<created_at>Tue Mar 30 23:28:05 +0000 2010</created_at>
|
||||
<in_reply_to_status_id/>
|
||||
<source>api</source>
|
||||
<id>26668724</id>
|
||||
<in_reply_to_user_id/>
|
||||
<in_reply_to_screen_name/>
|
||||
<geo xmlns:georss="http://www.georss.org/georss">
|
||||
<georss:point>30.468 -94.743</georss:point>
|
||||
</geo>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>25803</id>
|
||||
<name>Jed Sanders</name>
|
||||
<screen_name>jedsanders</screen_name>
|
||||
<location>Hoop and Holler, Texas</location>
|
||||
<description>I like to think of myself as America's Favorite.</description>
|
||||
<profile_image_url>http://avatar.example.com/25803-48-20080924200604.png</profile_image_url>
|
||||
<url>http://jedsanders.net</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>5</followers_count>
|
||||
<profile_background_color/>
|
||||
<profile_text_color/>
|
||||
<profile_link_color/>
|
||||
<profile_sidebar_fill_color/>
|
||||
<profile_sidebar_border_color/>
|
||||
<friends_count>2</friends_count>
|
||||
<created_at>Wed Sep 24 20:04:00 +0000 2008</created_at>
|
||||
<favourites_count>0</favourites_count>
|
||||
<utc_offset>0</utc_offset>
|
||||
<time_zone>UTC</time_zone>
|
||||
<profile_background_image_url/>
|
||||
<profile_background_tile>false</profile_background_tile>
|
||||
<statuses_count>70</statuses_count>
|
||||
<following>true</following>
|
||||
<notifications>true</notifications>
|
||||
</user>
|
||||
</status>
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the authenticating user's status (posts a notice).
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Tom Blankenship <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
{
|
||||
protected $needPost = true;
|
||||
|
||||
var $status = null;
|
||||
var $in_reply_to_status_id = null;
|
||||
var $lat = null;
|
||||
var $lon = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->status = $this->trimmed('status');
|
||||
$this->lat = $this->trimmed('lat');
|
||||
$this->lon = $this->trimmed('long');
|
||||
|
||||
$this->in_reply_to_status_id
|
||||
= intval($this->trimmed('in_reply_to_status_id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Make a new notice for the update, save it, and show it
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
// TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
|
||||
// TRANS: %s is the number of bytes of the CONTENT_LENGTH.
|
||||
$msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
|
||||
'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
|
||||
intval($_SERVER['CONTENT_LENGTH']));
|
||||
|
||||
$this->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
}
|
||||
|
||||
if (empty($this->status)) {
|
||||
// TRANS: Client error displayed when the parameter "status" is missing.
|
||||
$this->clientError(_('Client must provide a \'status\' parameter with a value.'));
|
||||
}
|
||||
|
||||
if (is_null($this->scoped)) {
|
||||
// TRANS: Client error displayed when updating a status for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
/* Do not call shortenlinks until the whole notice has been build */
|
||||
|
||||
// Check for commands
|
||||
|
||||
$inter = new CommandInterpreter();
|
||||
$cmd = $inter->handle_command($this->auth_user, $this->status);
|
||||
|
||||
if ($cmd) {
|
||||
if ($this->supported($cmd)) {
|
||||
$cmd->execute(new Channel());
|
||||
}
|
||||
|
||||
// Cmd not supported? Twitter just returns your latest status.
|
||||
// And, it returns your last status whether the cmd was successful
|
||||
// or not!
|
||||
|
||||
$this->notice = $this->auth_user->getCurrentNotice();
|
||||
} else {
|
||||
$reply_to = null;
|
||||
|
||||
if (!empty($this->in_reply_to_status_id)) {
|
||||
// Check whether notice actually exists
|
||||
|
||||
$reply = Notice::getKV($this->in_reply_to_status_id);
|
||||
|
||||
if ($reply) {
|
||||
$reply_to = $this->in_reply_to_status_id;
|
||||
} else {
|
||||
// TRANS: Client error displayed when replying to a non-existing notice.
|
||||
$this->clientError(_('Parent notice not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
$upload = null;
|
||||
try {
|
||||
$upload = MediaFile::fromUpload('media', $this->scoped);
|
||||
$this->status .= ' ' . $upload->shortUrl();
|
||||
/* Do not call shortenlinks until the whole notice has been build */
|
||||
} catch (NoUploadedMediaException $e) {
|
||||
// There was no uploaded media for us today.
|
||||
}
|
||||
|
||||
/* Do call shortenlinks here & check notice length since notice is about to be saved & sent */
|
||||
$status_shortened = $this->auth_user->shortenlinks($this->status);
|
||||
|
||||
if (Notice::contentTooLong($status_shortened)) {
|
||||
if ($upload instanceof MediaFile) {
|
||||
$upload->delete();
|
||||
}
|
||||
// TRANS: Client error displayed exceeding the maximum notice length.
|
||||
// TRANS: %d is the maximum lenth for a notice.
|
||||
$msg = _m('Maximum notice size is %d character, including attachment URL.',
|
||||
'Maximum notice size is %d characters, including attachment URL.',
|
||||
Notice::maxContent());
|
||||
/* Use HTTP 413 error code (Request Entity Too Large)
|
||||
* instead of basic 400 for better understanding
|
||||
*/
|
||||
$this->clientError(sprintf($msg, Notice::maxContent()), 413);
|
||||
}
|
||||
|
||||
|
||||
$content = html_entity_decode($status_shortened, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
$options = array('reply_to' => $reply_to);
|
||||
|
||||
if ($this->scoped->shareLocation()) {
|
||||
|
||||
$locOptions = Notice::locationOptions($this->lat,
|
||||
$this->lon,
|
||||
null,
|
||||
null,
|
||||
$this->scoped);
|
||||
|
||||
$options = array_merge($options, $locOptions);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->notice = Notice::saveNew(
|
||||
$this->scoped->id,
|
||||
$content,
|
||||
$this->source,
|
||||
$options
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
$this->clientError($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
if (isset($upload)) {
|
||||
$upload->attachToNotice($this->notice);
|
||||
}
|
||||
}
|
||||
|
||||
$this->showNotice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the resulting notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showNotice()
|
||||
{
|
||||
if (!empty($this->notice)) {
|
||||
if ($this->format == 'xml') {
|
||||
$this->showSingleXmlStatus($this->notice);
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->show_single_json_status($this->notice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this command supported when doing an update from the API?
|
||||
*
|
||||
* @param string $cmd the command to check for
|
||||
*
|
||||
* @return boolean true or false
|
||||
*/
|
||||
function supported($cmd)
|
||||
{
|
||||
static $cmdlist = array('SubCommand', 'UnsubCommand',
|
||||
'OnCommand', 'OffCommand', 'JoinCommand', 'LeaveCommand');
|
||||
|
||||
$supported = null;
|
||||
|
||||
if (Event::handle('CommandSupportedAPI', array($cmd, &$supported))) {
|
||||
$supported = $supported || in_array(get_class($cmd), $cmdlist);
|
||||
}
|
||||
|
||||
return $supported;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Base class for showing subscription information in the API
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* This class outputs a list of profiles as Twitter-style user and status objects.
|
||||
* It is used by the API methods /api/statuses/(friends|followers). To support the
|
||||
* social graph methods it also can output a simple list of IDs.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
abstract class ApiSubscriptionsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $profiles = null;
|
||||
var $tag = null;
|
||||
var $lite = null;
|
||||
var $ids_only = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->tag = $this->arg('tag');
|
||||
|
||||
// Note: Twitter no longer supports 'lite'
|
||||
$this->lite = $this->arg('lite');
|
||||
|
||||
$this->ids_only = $this->arg('ids_only');
|
||||
|
||||
// If called as a social graph method, show 5000 per page, otherwise 100
|
||||
|
||||
$this->count = isset($this->ids_only) ?
|
||||
5000 : (int)$this->arg('count', 100);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting a list of followers for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->profiles = $this->getProfiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Show the profiles
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
$this->initDocument($this->format);
|
||||
|
||||
if (isset($this->ids_only)) {
|
||||
$this->showIds();
|
||||
} else {
|
||||
$this->showProfiles(isset($this->lite) ? false : true);
|
||||
}
|
||||
|
||||
$this->endDocument($this->format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get profiles related to the type of subscriber/subscription action
|
||||
*
|
||||
* @return array Profiles
|
||||
*/
|
||||
abstract protected function getProfiles();
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest profile in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
return strtotime($this->profiles[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this action
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last profiles in the subscriptions list
|
||||
* There's also an indicator to show whether this action is being called
|
||||
* as /api/statuses/(friends|followers) or /api/(friends|followers)/ids
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->profiles) && (count($this->profiles) > 0)) {
|
||||
|
||||
$last = count($this->profiles) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
// Caching tags.
|
||||
isset($this->ids_only) ? 'IDs' : 'Profiles',
|
||||
strtotime($this->profiles[0]->created),
|
||||
strtotime($this->profiles[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the profiles as Twitter-style useres and statuses
|
||||
*
|
||||
* @param boolean $include_statuses Whether to include the latest status
|
||||
* with each user. Default true.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showProfiles($include_statuses = true)
|
||||
{
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->elementStart('users', array('type' => 'array',
|
||||
'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
|
||||
foreach ($this->profiles as $profile) {
|
||||
$this->showProfile(
|
||||
$profile,
|
||||
$this->format,
|
||||
null,
|
||||
$include_statuses
|
||||
);
|
||||
}
|
||||
$this->elementEnd('users');
|
||||
break;
|
||||
case 'json':
|
||||
$arrays = array();
|
||||
foreach ($this->profiles as $profile) {
|
||||
$arrays[] = $this->twitterUserArray(
|
||||
$profile,
|
||||
$include_statuses
|
||||
);
|
||||
}
|
||||
print json_encode($arrays);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when requesting profiles of followers in an unsupported format.
|
||||
$this->clientError(_('Unsupported format.'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the IDs of the profiles only. 5000 per page. To support
|
||||
* the 'social graph' methods: /api/(friends|followers)/ids
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showIds()
|
||||
{
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->elementStart('ids');
|
||||
foreach ($this->profiles as $profile) {
|
||||
$this->element('id', null, $profile->id);
|
||||
}
|
||||
$this->elementEnd('ids');
|
||||
break;
|
||||
case 'json':
|
||||
$ids = array();
|
||||
foreach ($this->profiles as $profile) {
|
||||
$ids[] = (int)$profile->id;
|
||||
}
|
||||
print json_encode($ids);
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when requesting IDs of followers in an unsupported format.
|
||||
$this->clientError(_('Unsupported format.'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,344 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the friends timeline
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page friendstimeline statuses/friends_timeline
|
||||
|
||||
@section Description
|
||||
Returns the 20 most recent statuses posted by the authenticating
|
||||
user and that user's friends. This is the equivalent of "You and
|
||||
friends" page in the web interface.
|
||||
|
||||
@par URL patterns
|
||||
@li /api/statuses/friends_timeline.:format
|
||||
@li /api/statuses/friends_timeline/:id.:format
|
||||
|
||||
@par Formats (:format)
|
||||
xml, json, rss, atom
|
||||
|
||||
@par ID (:id)
|
||||
username, user id
|
||||
|
||||
@par HTTP Method(s)
|
||||
GET
|
||||
|
||||
@par Requires Authentication
|
||||
Sometimes (see: @ref authentication)
|
||||
|
||||
@param user_id (Optional) Specifies a user by ID
|
||||
@param screen_name (Optional) Specifies a user by screename (nickname)
|
||||
@param since_id (Optional) Returns only statuses with an ID greater
|
||||
than (that is, more recent than) the specified ID.
|
||||
@param max_id (Optional) Returns only statuses with an ID less than
|
||||
(that is, older than) or equal to the specified ID.
|
||||
@param count (Optional) Specifies the number of statuses to retrieve.
|
||||
@param page (Optional) Specifies the page of results to retrieve.
|
||||
|
||||
@sa @ref authentication
|
||||
@sa @ref apiroot
|
||||
|
||||
@subsection usagenotes Usage notes
|
||||
@li The URL pattern is relative to the @ref apiroot.
|
||||
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
|
||||
to encode the latitude and longitude (see example response below <georss:point>).
|
||||
|
||||
@subsection exampleusage Example usage
|
||||
|
||||
@verbatim
|
||||
curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
|
||||
@endverbatim
|
||||
|
||||
@subsection exampleresponse Example response
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0"?>
|
||||
<statuses type="array">
|
||||
<status>
|
||||
<text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
|
||||
<truncated>false</truncated>
|
||||
<created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
|
||||
<in_reply_to_status_id/>
|
||||
<source><a href="http://code.google.com/p/microblog-purple/">mbpidgin</a></source>
|
||||
<id>26674201</id>
|
||||
<in_reply_to_user_id/>
|
||||
<in_reply_to_screen_name/>
|
||||
<geo/>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>246</id>
|
||||
<name>Mark</name>
|
||||
<screen_name>lambic</screen_name>
|
||||
<location>Montreal, Canada</location>
|
||||
<description>Geek</description>
|
||||
<profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
|
||||
<url>http://lambic.co.uk</url>
|
||||
<protected>false</protected>
|
||||
<followers_count>73</followers_count>
|
||||
<profile_background_color>#F0F2F5</profile_background_color>
|
||||
<profile_text_color/>
|
||||
<profile_link_color>#002E6E</profile_link_color>
|
||||
<profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
|
||||
<profile_sidebar_border_color/>
|
||||
<friends_count>58</friends_count>
|
||||
<created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
|
||||
<favourites_count>2</favourites_count>
|
||||
<utc_offset>-14400</utc_offset>
|
||||
<time_zone>US/Eastern</time_zone>
|
||||
<profile_background_image_url/>
|
||||
<profile_background_tile>false</profile_background_tile>
|
||||
<statuses_count>933</statuses_count>
|
||||
<following>false</following>
|
||||
<notifications>false</notifications>
|
||||
</user>
|
||||
</status>
|
||||
</statuses>
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by the target user.
|
||||
* This is the equivalent of 'You and friends' page accessed via Web.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineFriendsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting dents of a user and friends for a user that does not exist.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Title of API timeline for a user and friends.
|
||||
// TRANS: %s is a username.
|
||||
$title = sprintf(_("%s and friends"), $this->target->nickname);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:FriendsTimeline:" . $this->target->id;
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
|
||||
_('Updates from %1$s and friends on %2$s!'),
|
||||
$this->target->nickname,
|
||||
$sitename
|
||||
);
|
||||
|
||||
$logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
$link = common_local_url('all',
|
||||
array('nickname' => $this->target->nickname));
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($logo);
|
||||
$atom->setUpdated('now');
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user, $title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||
|
||||
$notice = $stream->getNotices(($this->page-1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a group's notices
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted to the group specified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $group = null;
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->group = $this->getTargetGroup($this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->group)) {
|
||||
// TRANS: Client error displayed requesting most recent notices to a group for a non-existing group.
|
||||
$this->clientError(_('Group not found.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
// We'll pull common formatting out of this for other formats
|
||||
$atom = new AtomGroupNoticeFeed($this->group, $this->auth_user);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
$link = common_local_url('showgroup',
|
||||
array('nickname' => $this->group->nickname));
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$atom->title,
|
||||
$this->group->homeUrl(),
|
||||
$atom->subtitle,
|
||||
null,
|
||||
$atom->logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($atom->title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when trying to handle an unknown API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$notice = $this->group->getNotices(
|
||||
($this->page-1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, group ID and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->group->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the home timeline
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by the target user.
|
||||
* This is the equivalent of 'You and friends' page accessed via Web.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineHomeAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting most recent dents by user and friends for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
// TRANS: Timeline title for user and friends. %s is a user nickname.
|
||||
$title = sprintf(_("%s and friends"), $this->target->nickname);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:HomeTimeline:" . $this->target->id;
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
|
||||
_('Updates from %1$s and friends on %2$s!'),
|
||||
$this->target->nickname, $sitename
|
||||
);
|
||||
|
||||
$logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
$link = common_local_url('all',
|
||||
array('nickname' => $this->target->nickname));
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($logo);
|
||||
$atom->setUpdated('now');
|
||||
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = new InboxNoticeStream($this->target, $this->scoped);
|
||||
|
||||
$notice = $stream->getNotices(($this->page-1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a list's notices
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/atomlistnoticefeed.php';
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted to the list specified by ID
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineListAction extends ApiPrivateAuthAction
|
||||
{
|
||||
|
||||
var $list = null;
|
||||
var $notices = array();
|
||||
var $next_cursor = 0;
|
||||
var $prev_cursor = 0;
|
||||
var $cursor = -1;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->cursor = (int) $this->arg('cursor', -1);
|
||||
$this->list = $this->getTargetList($this->arg('user'), $this->arg('id'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (empty($this->list)) {
|
||||
// TRANS: Client error displayed trying to perform an action related to a non-existing list.
|
||||
$this->clientError(_('List not found.'), 404);
|
||||
}
|
||||
|
||||
$this->getNotices();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
// We'll pull common formatting out of this for other formats
|
||||
$atom = new AtomListNoticeFeed($this->list, $this->auth_user);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->initDocument('xml');
|
||||
$this->elementStart('statuses_list',
|
||||
array('xmlns:statusnet' => 'http://status.net/schema/api/1/'));
|
||||
$this->elementStart('statuses', array('type' => 'array'));
|
||||
|
||||
foreach ($this->notices as $n) {
|
||||
$twitter_status = $this->twitterStatusArray($n);
|
||||
$this->showTwitterXmlStatus($twitter_status);
|
||||
}
|
||||
|
||||
$this->elementEnd('statuses');
|
||||
$this->element('next_cursor', null, $this->next_cursor);
|
||||
$this->element('previous_cursor', null, $this->prev_cursor);
|
||||
$this->elementEnd('statuses_list');
|
||||
$this->endDocument('xml');
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$atom->title,
|
||||
$this->list->getUri(),
|
||||
$atom->subtitle,
|
||||
null,
|
||||
$atom->logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
try {
|
||||
$atom->setId($self);
|
||||
$atom->setSelfLink($self);
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
} catch (Atom10FeedException $e) {
|
||||
// TRANS: Server error displayed whe trying to get a timeline fails.
|
||||
// TRANS: %s is the error message.
|
||||
$this->serverError(sprintf(_('Could not generate feed for list - %s'), $e->getMessage()));
|
||||
}
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->initDocument('json');
|
||||
|
||||
$statuses = array();
|
||||
foreach ($this->notices as $n) {
|
||||
$twitter_status = $this->twitterStatusArray($n);
|
||||
array_push($statuses, $twitter_status);
|
||||
}
|
||||
|
||||
$statuses_list = array('statuses' => $statuses,
|
||||
'next_cursor' => $this->next_cusror,
|
||||
'next_cursor_str' => strval($this->next_cusror),
|
||||
'previous_cursor' => $this->prev_cusror,
|
||||
'previous_cursor_str' => strval($this->prev_cusror)
|
||||
);
|
||||
$this->showJsonObjects($statuses_list);
|
||||
|
||||
$this->initDocument('json');
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$fn = array($this->list, 'getNotices');
|
||||
list($this->notices, $this->next_cursor, $this->prev_cursor) =
|
||||
Profile_list::getAtCursor($fn, array(), $this->cursor, 20);
|
||||
if (!$this->notices) {
|
||||
$this->notices = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, list ID and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->list->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show notices mentioning a user (@nickname)
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent (default 20) mentions (status containing @nickname)
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineMentionsAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed when requesting most recent mentions for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(
|
||||
// TRANS: Title for timeline of most recent mentions of a user.
|
||||
// TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
|
||||
_('%1$s / Updates mentioning %2$s'),
|
||||
$sitename, $this->target->nickname
|
||||
);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:Mentions:" . $this->target->id;
|
||||
|
||||
$logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
|
||||
$link = common_local_url('replies',
|
||||
array('nickname' => $this->target->nickname));
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Subtitle for timeline of most recent mentions of a user.
|
||||
// TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname,
|
||||
// TRANS: %3$s is a user's full name.
|
||||
_('%1$s updates that reply to updates from %3$s / %2$s.'),
|
||||
$sitename, $this->target->nickname, $this->target->getBestName()
|
||||
);
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($logo);
|
||||
$atom->setUpdated('now');
|
||||
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = new ReplyNoticeStream($this->target->id, $this->scoped);
|
||||
|
||||
$notice = $stream->getNotices(($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class ApiTimelineNetworkPublicAction extends ApiTimelinePublicAction
|
||||
{
|
||||
function title()
|
||||
{
|
||||
return sprintf(_("%s network public timeline"), common_config('site', 'name'));
|
||||
}
|
||||
|
||||
protected function getStream()
|
||||
{
|
||||
if (!$this->scoped instanceof Profile && common_config('public', 'localonly')) {
|
||||
$this->clientError(_('Network wide public feed is not permitted without authorization'), 403);
|
||||
}
|
||||
return new NetworkPublicNoticeStream($this->scoped);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,335 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the public timeline
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by everybody
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
/* External API usage documentation. Please update when you change how this method works. */
|
||||
|
||||
/*! @page publictimeline statuses/public_timeline
|
||||
|
||||
@section Description
|
||||
Returns the 20 most recent notices from users throughout the system who have
|
||||
uploaded their own avatars. Depending on configuration, it may or may not
|
||||
not include notices from automatic posting services.
|
||||
|
||||
@par URL patterns
|
||||
@li /api/statuses/public_timeline.:format
|
||||
|
||||
@par Formats (:format)
|
||||
xml, json, rss, atom
|
||||
|
||||
@par HTTP Method(s)
|
||||
GET
|
||||
|
||||
@par Requires Authentication
|
||||
No
|
||||
|
||||
@param since_id (Optional) Returns only statuses with an ID greater
|
||||
than (that is, more recent than) the specified ID.
|
||||
@param max_id (Optional) Returns only statuses with an ID less than
|
||||
(that is, older than) or equal to the specified ID.
|
||||
@param count (Optional) Specifies the number of statuses to retrieve.
|
||||
@param page (Optional) Specifies the page of results to retrieve.
|
||||
|
||||
@sa @ref apiroot
|
||||
|
||||
@subsection usagenotes Usage notes
|
||||
@li The URL pattern is relative to the @ref apiroot.
|
||||
@li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
|
||||
to encode the latitude and longitude (see example response below <georss:point>).
|
||||
|
||||
@subsection exampleusage Example usage
|
||||
|
||||
@verbatim
|
||||
curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
|
||||
@endverbatim
|
||||
|
||||
@subsection exampleresponse Example response
|
||||
|
||||
@verbatim
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<statuses type="array">
|
||||
<status>
|
||||
<text>@skwashd oh, commbank reenabled me super quick both times. but disconcerting when you don't expect it though</text>
|
||||
<truncated>false</truncated>
|
||||
<created_at>Sat Apr 17 00:49:12 +0000 2010</created_at>
|
||||
<in_reply_to_status_id>28838393</in_reply_to_status_id>
|
||||
<source>xmpp</source>
|
||||
<id>28838456</id>
|
||||
<in_reply_to_user_id>39303</in_reply_to_user_id>
|
||||
<in_reply_to_screen_name>skwashd</in_reply_to_screen_name>
|
||||
<geo></geo>
|
||||
<favorited>false</favorited>
|
||||
<user>
|
||||
<id>44517</id>
|
||||
<name>joshua may</name>
|
||||
<screen_name>notjosh</screen_name>
|
||||
<location></location>
|
||||
<description></description>
|
||||
<profile_image_url>http://avatar.identi.ca/44517-48-20090321004106.jpeg</profile_image_url>
|
||||
<url></url>
|
||||
<protected>false</protected>
|
||||
<followers_count>17</followers_count>
|
||||
<profile_background_color></profile_background_color>
|
||||
<profile_text_color></profile_text_color>
|
||||
<profile_link_color></profile_link_color>
|
||||
<profile_sidebar_fill_color></profile_sidebar_fill_color>
|
||||
<profile_sidebar_border_color></profile_sidebar_border_color>
|
||||
<friends_count>20</friends_count>
|
||||
<created_at>Sat Mar 21 00:40:25 +0000 2009</created_at>
|
||||
<favourites_count>0</favourites_count>
|
||||
<utc_offset>0</utc_offset>
|
||||
<time_zone>UTC</time_zone>
|
||||
<profile_background_image_url></profile_background_image_url>
|
||||
<profile_background_tile>false</profile_background_tile>
|
||||
<statuses_count>100</statuses_count>
|
||||
<following>false</following>
|
||||
<notifications>false</notifications>
|
||||
</user>
|
||||
</status>
|
||||
[....]
|
||||
</statuses>
|
||||
@endverbatim
|
||||
*/
|
||||
class ApiTimelinePublicAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
// TRANS: Title for site timeline. %s is the GNU social sitename.
|
||||
return sprintf(_("%s public timeline"), common_config('site', 'name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$nonapi_action = substr($this->action, strlen('apitimeline')); // Just so we don't need to set this explicitly
|
||||
|
||||
$sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
|
||||
$title = $this->title();
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:" . ucfirst($nonapi_action) . 'Timeline'; // Public or Networkpublic probably
|
||||
$link = common_local_url($nonapi_action);
|
||||
$self = $this->getSelfUri();
|
||||
// TRANS: Subtitle for site timeline. %s is the GNU social sitename.
|
||||
$subtitle = sprintf(_("%s updates from everyone!"), common_config('site', 'name'));
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$sitelogo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($sitelogo);
|
||||
$atom->setUpdated('now');
|
||||
$atom->addLink(common_local_url($nonapi_action));
|
||||
$atom->setSelfLink($self);
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$stream = $this->getStream();
|
||||
|
||||
$notice = $stream->getNotices(($this->page - 1) * $this->count,
|
||||
$this->count,
|
||||
$this->since_id,
|
||||
$this->max_id);
|
||||
|
||||
$notices = $notice->fetchAll();
|
||||
|
||||
NoticeList::prefill($notices);
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
protected function getStream()
|
||||
{
|
||||
return new PublicNoticeStream($this->scoped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show authenticating user's most recent repeats
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show authenticating user's most recent repeats
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineRetweetedByMeAction extends ApiAuthAction
|
||||
{
|
||||
const DEFAULTCOUNT = 20;
|
||||
const MAXCOUNT = 200;
|
||||
const MAXNOTICES = 3200;
|
||||
|
||||
var $repeats = null;
|
||||
var $cnt = self::DEFAULTCOUNT;
|
||||
var $page = 1;
|
||||
var $since_id = null;
|
||||
var $max_id = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
// TRANS: Server error displayed calling unimplemented API method for 'retweeted by me'.
|
||||
$this->serverError(_('Unimplemented.'), 503);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show most recent notices that are repeats in user's inbox
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show most recent notices that are repeats in user's inbox
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineRetweetedToMeAction extends ApiAuthAction
|
||||
{
|
||||
const DEFAULTCOUNT = 20;
|
||||
const MAXCOUNT = 200;
|
||||
const MAXNOTICES = 3200;
|
||||
|
||||
var $repeats = null;
|
||||
var $cnt = self::DEFAULTCOUNT;
|
||||
var $page = 1;
|
||||
var $since_id = null;
|
||||
var $max_id = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$cnt = $this->int('count', self::DEFAULTCOUNT, self::MAXCOUNT, 1);
|
||||
|
||||
$page = $this->int('page', 1, (self::MAXNOTICES/$this->cnt));
|
||||
|
||||
$since_id = $this->int('since_id');
|
||||
|
||||
$max_id = $this->int('max_id');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* show a timeline of the user's repeated notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$offset = ($this->page-1) * $this->cnt;
|
||||
$limit = $this->cnt;
|
||||
|
||||
// TRANS: Title for Atom feed "repeated to me". %s is the user nickname.
|
||||
$title = sprintf(_("Repeated to %s"), $this->auth_user->nickname);
|
||||
$subtitle = sprintf(
|
||||
// @todo FIXME: $profile is not defined.
|
||||
// TRANS: Subtitle for API action that shows most recent notices that are repeats in user's inbox.
|
||||
// TRANS: %1$s is the sitename, %2$s is a user nickname, %3$s is a user profile name.
|
||||
_('%1$s notices that were to repeated to %2$s / %3$s.'),
|
||||
$sitename, $this->user->nickname, $profile->getBestName()
|
||||
);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:RepeatedToMe:" . $this->auth_user->id;
|
||||
|
||||
$link = common_local_url(
|
||||
'all',
|
||||
array('nickname' => $this->auth_user->nickname)
|
||||
);
|
||||
|
||||
$strm = $this->auth_user->repeatedToMe($offset, $limit, $this->since_id, $this->max_id);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($strm);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($strm);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setUpdated('now');
|
||||
$atom->addLink($link);
|
||||
|
||||
$id = $this->arg('id');
|
||||
|
||||
$atom->setSelfLink($self);
|
||||
$atom->addEntryFromNotices($strm);
|
||||
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($strm);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show authenticating user's most recent notices that have been repeated
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show authenticating user's most recent notices that have been repeated
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
|
||||
{
|
||||
const DEFAULTCOUNT = 20;
|
||||
const MAXCOUNT = 200;
|
||||
const MAXNOTICES = 3200;
|
||||
|
||||
var $repeats = null;
|
||||
var $cnt = self::DEFAULTCOUNT;
|
||||
var $page = 1;
|
||||
var $since_id = null;
|
||||
var $max_id = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$cnt = $this->int('count', self::DEFAULTCOUNT, self::MAXCOUNT, 1);
|
||||
|
||||
$page = $this->int('page', 1, (self::MAXNOTICES/$this->cnt));
|
||||
|
||||
$since_id = $this->int('since_id');
|
||||
|
||||
$max_id = $this->int('max_id');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* show a timeline of the user's repeated notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$offset = ($this->page-1) * $this->cnt;
|
||||
$limit = $this->cnt;
|
||||
|
||||
// TRANS: Title of list of repeated notices of the logged in user.
|
||||
// TRANS: %s is the nickname of the logged in user.
|
||||
$title = sprintf(_("Repeats of %s"), $this->auth_user->nickname);
|
||||
$sitename = common_config('site', 'name');
|
||||
|
||||
$profile = $this->auth_user->getProfile();
|
||||
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Subtitle of API time with retweets of me.
|
||||
// TRANS: %1$s is the StatusNet sitename, %2$s is the user nickname, %3$s is the user profile name.
|
||||
_('%1$s notices that %2$s / %3$s has repeated.'),
|
||||
$sitename, $this->auth_user->nickname, $profile->getBestName()
|
||||
);
|
||||
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:RepeatsOfMe:" . $this->auth_user->id;
|
||||
|
||||
$link = common_local_url(
|
||||
'all',
|
||||
array('nickname' => $this->auth_user->nickname)
|
||||
);
|
||||
|
||||
// This is a really bad query for some reason
|
||||
|
||||
if (!common_config('performance', 'high')) {
|
||||
$strm = $this->auth_user->repeatsOfMe($offset, $limit, $this->since_id, $this->max_id);
|
||||
} else {
|
||||
$strm = new Notice();
|
||||
$strm->whereAdd('0 = 1');
|
||||
$strm->find();
|
||||
}
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($strm);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($strm);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setUpdated('now');
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($this->getSelfUri());
|
||||
$atom->addEntryFromNotices($strm);
|
||||
$this->raw($atom->getString());
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($strm);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show the latest notices for a given tag
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 20 most recent notices tagged by a given tag
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineTagAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
common_debug("apitimelinetag prepare()");
|
||||
|
||||
$this->tag = $this->arg('tag');
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showTimeline();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
$sitename = common_config('site', 'name');
|
||||
$sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
|
||||
// TRANS: Title for timeline with lastest notices with a given tag.
|
||||
// TRANS: %s is the tag.
|
||||
$title = sprintf(_("Notices tagged with %s"), $this->tag);
|
||||
$subtitle = sprintf(
|
||||
// TRANS: Subtitle for timeline with lastest notices with a given tag.
|
||||
// TRANS: %1$s is the tag, $2$s is the StatusNet sitename.
|
||||
_('Updates tagged with %1$s on %2$s!'),
|
||||
$this->tag,
|
||||
$sitename
|
||||
);
|
||||
$taguribase = TagURI::base();
|
||||
$id = "tag:$taguribase:TagTimeline:".$this->tag;
|
||||
|
||||
$link = common_local_url(
|
||||
'tag',
|
||||
array('tag' => $this->tag)
|
||||
);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$title,
|
||||
$link,
|
||||
$subtitle,
|
||||
null,
|
||||
$sitelogo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom = new AtomNoticeFeed($this->auth_user);
|
||||
|
||||
$atom->setId($id);
|
||||
$atom->setTitle($title);
|
||||
$atom->setSubtitle($subtitle);
|
||||
$atom->setLogo($sitelogo);
|
||||
$atom->setUpdated('now');
|
||||
|
||||
$atom->addLink($link);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$notice = Notice_tag::getStream(
|
||||
$this->tag,
|
||||
($this->page - 1) * $this->count,
|
||||
$this->count + 1,
|
||||
$this->since_id,
|
||||
$this->max_id
|
||||
);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->tag,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,516 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a user's timeline
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent notices (default 20) posted by the authenticating
|
||||
* user. Another user's timeline can be requested via the id parameter. This
|
||||
* is the API equivalent of the user profile web page.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Jeffery To <jeffery.to@gmail.com>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Mike Cochrane <mikec@mikenz.geek.nz>
|
||||
* @author Robin Millette <robin@millette.info>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiTimelineUserAction extends ApiBareAuthAction
|
||||
{
|
||||
var $notices = null;
|
||||
|
||||
var $next_id = null;
|
||||
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->target = $this->getTargetProfile($this->arg('id'));
|
||||
|
||||
if (!($this->target instanceof Profile)) {
|
||||
// TRANS: Client error displayed requesting most recent notices for a non-existing user.
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
}
|
||||
|
||||
$this->notices = $this->getNotices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Just show the notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if ($this->isPost()) {
|
||||
$this->handlePost();
|
||||
} else {
|
||||
$this->showTimeline();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the timeline of notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTimeline()
|
||||
{
|
||||
// We'll use the shared params from the Atom stub
|
||||
// for other feed types.
|
||||
$atom = new AtomUserNoticeFeed($this->target->getUser(), $this->auth_user);
|
||||
|
||||
$link = common_local_url(
|
||||
'showstream',
|
||||
array('nickname' => $this->target->nickname)
|
||||
);
|
||||
|
||||
$self = $this->getSelfUri();
|
||||
|
||||
// FriendFeed's SUP protocol
|
||||
// Also added RSS and Atom feeds
|
||||
|
||||
$suplink = common_local_url('sup', null, null, $this->target->id);
|
||||
header('X-SUP-ID: ' . $suplink);
|
||||
|
||||
|
||||
// paging links
|
||||
$nextUrl = !empty($this->next_id)
|
||||
? common_local_url('ApiTimelineUser',
|
||||
array('format' => $this->format,
|
||||
'id' => $this->target->id),
|
||||
array('max_id' => $this->next_id))
|
||||
: null;
|
||||
|
||||
$prevExtra = array();
|
||||
if (!empty($this->notices)) {
|
||||
assert($this->notices[0] instanceof Notice);
|
||||
$prevExtra['since_id'] = $this->notices[0]->id;
|
||||
}
|
||||
|
||||
$prevUrl = common_local_url('ApiTimelineUser',
|
||||
array('format' => $this->format,
|
||||
'id' => $this->target->id),
|
||||
$prevExtra);
|
||||
$firstUrl = common_local_url('ApiTimelineUser',
|
||||
array('format' => $this->format,
|
||||
'id' => $this->target->id));
|
||||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($this->notices);
|
||||
break;
|
||||
case 'rss':
|
||||
$this->showRssTimeline(
|
||||
$this->notices,
|
||||
$atom->title,
|
||||
$link,
|
||||
$atom->subtitle,
|
||||
$suplink,
|
||||
$atom->logo,
|
||||
$self
|
||||
);
|
||||
break;
|
||||
case 'atom':
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$atom->setId($self);
|
||||
$atom->setSelfLink($self);
|
||||
|
||||
// Add navigation links: next, prev, first
|
||||
// Note: we use IDs rather than pages for navigation; page boundaries
|
||||
// change too quickly!
|
||||
|
||||
if (!empty($this->next_id)) {
|
||||
$atom->addLink($nextUrl,
|
||||
array('rel' => 'next',
|
||||
'type' => 'application/atom+xml'));
|
||||
}
|
||||
|
||||
if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
|
||||
$atom->addLink($prevUrl,
|
||||
array('rel' => 'prev',
|
||||
'type' => 'application/atom+xml'));
|
||||
}
|
||||
|
||||
if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
|
||||
$atom->addLink($firstUrl,
|
||||
array('rel' => 'first',
|
||||
'type' => 'application/atom+xml'));
|
||||
|
||||
}
|
||||
|
||||
$atom->addEntryFromNotices($this->notices);
|
||||
$this->raw($atom->getString());
|
||||
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
case 'as':
|
||||
header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
|
||||
$doc = new ActivityStreamJSONDocument($this->auth_user);
|
||||
$doc->setTitle($atom->title);
|
||||
$doc->addLink($link, 'alternate', 'text/html');
|
||||
$doc->addItemsFromNotices($this->notices);
|
||||
|
||||
if (!empty($this->next_id)) {
|
||||
$doc->addLink($nextUrl,
|
||||
array('rel' => 'next',
|
||||
'type' => ActivityStreamJSONDocument::CONTENT_TYPE));
|
||||
}
|
||||
|
||||
if (($this->page > 1 || !empty($this->max_id)) && !empty($this->notices)) {
|
||||
$doc->addLink($prevUrl,
|
||||
array('rel' => 'prev',
|
||||
'type' => ActivityStreamJSONDocument::CONTENT_TYPE));
|
||||
}
|
||||
|
||||
if ($this->page > 1 || !empty($this->since_id) || !empty($this->max_id)) {
|
||||
$doc->addLink($firstUrl,
|
||||
array('rel' => 'first',
|
||||
'type' => ActivityStreamJSONDocument::CONTENT_TYPE));
|
||||
}
|
||||
|
||||
$this->raw($doc->asString());
|
||||
break;
|
||||
default:
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get notices
|
||||
*
|
||||
* @return array notices
|
||||
*/
|
||||
function getNotices()
|
||||
{
|
||||
$notices = array();
|
||||
|
||||
$notice = $this->target->getNotices(($this->page-1) * $this->count,
|
||||
$this->count + 1,
|
||||
$this->since_id,
|
||||
$this->max_id,
|
||||
$this->scoped);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
if (count($notices) < $this->count) {
|
||||
$notices[] = clone($notice);
|
||||
} else {
|
||||
$this->next_id = $notice->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* We expose AtomPub here, so non-GET/HEAD reqs must be read/write.
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD');
|
||||
}
|
||||
|
||||
/**
|
||||
* When was this feed last modified?
|
||||
*
|
||||
* @return string datestamp of the latest notice in the stream
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
return strtotime($this->notices[0]->created);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this stream
|
||||
*
|
||||
* Returns an Etag based on the action name, language, user ID, and
|
||||
* timestamps of the first and last notice in the timeline
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
if (!empty($this->notices) && (count($this->notices) > 0)) {
|
||||
$last = count($this->notices) - 1;
|
||||
|
||||
return '"' . implode(
|
||||
':',
|
||||
array($this->arg('action'),
|
||||
common_user_cache_hash($this->auth_user),
|
||||
common_language(),
|
||||
$this->target->id,
|
||||
strtotime($this->notices[0]->created),
|
||||
strtotime($this->notices[$last]->created))
|
||||
)
|
||||
. '"';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
if (empty($this->auth_user) ||
|
||||
$this->auth_user->id != $this->target->id) {
|
||||
// TRANS: Client error displayed trying to add a notice to another user's timeline.
|
||||
$this->clientError(_('Only the user can add to their own timeline.'));
|
||||
}
|
||||
|
||||
// Only handle posts for Atom
|
||||
if ($this->format != 'atom') {
|
||||
// TRANS: Client error displayed when using another format than AtomPub.
|
||||
$this->clientError(_('Only accept AtomPub for Atom feeds.'));
|
||||
}
|
||||
|
||||
$xml = trim(file_get_contents('php://input'));
|
||||
if (empty($xml)) {
|
||||
// TRANS: Client error displayed attempting to post an empty API notice.
|
||||
$this->clientError(_('Atom post must not be empty.'));
|
||||
}
|
||||
|
||||
$old = error_reporting(error_reporting() & ~(E_WARNING | E_NOTICE));
|
||||
$dom = new DOMDocument();
|
||||
$ok = $dom->loadXML($xml);
|
||||
error_reporting($old);
|
||||
if (!$ok) {
|
||||
// TRANS: Client error displayed attempting to post an API that is not well-formed XML.
|
||||
$this->clientError(_('Atom post must be well-formed XML.'));
|
||||
}
|
||||
|
||||
if ($dom->documentElement->namespaceURI != Activity::ATOM ||
|
||||
$dom->documentElement->localName != 'entry') {
|
||||
// TRANS: Client error displayed when not using an Atom entry.
|
||||
$this->clientError(_('Atom post must be an Atom entry.'));
|
||||
}
|
||||
|
||||
$activity = new Activity($dom->documentElement);
|
||||
|
||||
$saved = null;
|
||||
|
||||
if (Event::handle('StartAtomPubNewActivity', array(&$activity, $this->target->getUser(), &$saved))) {
|
||||
if ($activity->verb != ActivityVerb::POST) {
|
||||
// TRANS: Client error displayed when not using the POST verb. Do not translate POST.
|
||||
$this->clientError(_('Can only handle POST activities.'));
|
||||
}
|
||||
|
||||
$note = $activity->objects[0];
|
||||
|
||||
if (!in_array($note->type, array(ActivityObject::NOTE,
|
||||
ActivityObject::BLOGENTRY,
|
||||
ActivityObject::STATUS))) {
|
||||
// TRANS: Client error displayed when using an unsupported activity object type.
|
||||
// TRANS: %s is the unsupported activity object type.
|
||||
$this->clientError(sprintf(_('Cannot handle activity object type "%s".'),
|
||||
$note->type));
|
||||
}
|
||||
|
||||
$saved = $this->postNote($activity);
|
||||
|
||||
Event::handle('EndAtomPubNewActivity', array($activity, $this->target->getUser(), $saved));
|
||||
}
|
||||
|
||||
if (!empty($saved)) {
|
||||
header('HTTP/1.1 201 Created');
|
||||
header("Location: " . common_local_url('ApiStatusesShow', array('id' => $saved->id,
|
||||
'format' => 'atom')));
|
||||
$this->showSingleAtomStatus($saved);
|
||||
}
|
||||
}
|
||||
|
||||
function postNote($activity)
|
||||
{
|
||||
$note = $activity->objects[0];
|
||||
|
||||
// Use summary as fallback for content
|
||||
|
||||
if (!empty($note->content)) {
|
||||
$sourceContent = $note->content;
|
||||
} else if (!empty($note->summary)) {
|
||||
$sourceContent = $note->summary;
|
||||
} else if (!empty($note->title)) {
|
||||
$sourceContent = $note->title;
|
||||
} else {
|
||||
// @fixme fetch from $sourceUrl?
|
||||
// TRANS: Client error displayed when posting a notice without content through the API.
|
||||
// TRANS: %d is the notice ID (number).
|
||||
$this->clientError(sprintf(_('No content for notice %d.'), $note->id));
|
||||
}
|
||||
|
||||
// Get (safe!) HTML and text versions of the content
|
||||
|
||||
$rendered = $this->purify($sourceContent);
|
||||
$content = common_strip_html($rendered);
|
||||
|
||||
$shortened = $this->auth_user->shortenLinks($content);
|
||||
|
||||
$options = array('is_local' => Notice::LOCAL_PUBLIC,
|
||||
'rendered' => $rendered,
|
||||
'replies' => array(),
|
||||
'groups' => array(),
|
||||
'tags' => array(),
|
||||
'urls' => array());
|
||||
|
||||
// accept remote URI (not necessarily a good idea)
|
||||
|
||||
common_debug("Note ID is {$note->id}");
|
||||
|
||||
if (!empty($note->id)) {
|
||||
$notice = Notice::getKV('uri', trim($note->id));
|
||||
|
||||
if (!empty($notice)) {
|
||||
// TRANS: Client error displayed when using another format than AtomPub.
|
||||
// TRANS: %s is the notice URI.
|
||||
$this->clientError(sprintf(_('Notice with URI "%s" already exists.'), $note->id));
|
||||
}
|
||||
common_log(LOG_NOTICE, "Saving client-supplied notice URI '$note->id'");
|
||||
$options['uri'] = $note->id;
|
||||
}
|
||||
|
||||
// accept remote create time (also maybe not such a good idea)
|
||||
|
||||
if (!empty($activity->time)) {
|
||||
common_log(LOG_NOTICE, "Saving client-supplied create time {$activity->time}");
|
||||
$options['created'] = common_sql_date($activity->time);
|
||||
}
|
||||
|
||||
// Check for optional attributes...
|
||||
|
||||
if ($activity->context instanceof ActivityContext) {
|
||||
|
||||
foreach ($activity->context->attention as $uri=>$type) {
|
||||
try {
|
||||
$profile = Profile::fromUri($uri);
|
||||
if ($profile->isGroup()) {
|
||||
$options['groups'][] = $profile->id;
|
||||
} else {
|
||||
$options['replies'][] = $uri;
|
||||
}
|
||||
} catch (UnknownUriException $e) {
|
||||
common_log(LOG_WARNING, sprintf('AtomPub post with unknown attention URI %s', $uri));
|
||||
}
|
||||
}
|
||||
|
||||
// Maintain direct reply associations
|
||||
// @fixme what about conversation ID?
|
||||
|
||||
if (!empty($activity->context->replyToID)) {
|
||||
$orig = Notice::getKV('uri',
|
||||
$activity->context->replyToID);
|
||||
if (!empty($orig)) {
|
||||
$options['reply_to'] = $orig->id;
|
||||
}
|
||||
}
|
||||
|
||||
$location = $activity->context->location;
|
||||
|
||||
if ($location) {
|
||||
$options['lat'] = $location->lat;
|
||||
$options['lon'] = $location->lon;
|
||||
if ($location->location_id) {
|
||||
$options['location_ns'] = $location->location_ns;
|
||||
$options['location_id'] = $location->location_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atom categories <-> hashtags
|
||||
|
||||
foreach ($activity->categories as $cat) {
|
||||
if ($cat->term) {
|
||||
$term = common_canonical_tag($cat->term);
|
||||
if ($term) {
|
||||
$options['tags'][] = $term;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atom enclosures -> attachment URLs
|
||||
foreach ($activity->enclosures as $href) {
|
||||
// @fixme save these locally or....?
|
||||
$options['urls'][] = $href;
|
||||
}
|
||||
|
||||
$saved = Notice::saveNew($this->target->id,
|
||||
$content,
|
||||
'atompub', // TODO: deal with this
|
||||
$options);
|
||||
|
||||
return $saved;
|
||||
}
|
||||
|
||||
function purify($content)
|
||||
{
|
||||
require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
|
||||
|
||||
$config = array('safe' => 1,
|
||||
'deny_attribute' => 'id,style,on*');
|
||||
return htmLawed($content, $config);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List of replies
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the top ten queries that are currently trending
|
||||
*
|
||||
* @category Search
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see ApiAction
|
||||
*/
|
||||
class ApiTrendsAction extends ApiPrivateAuthAction
|
||||
{
|
||||
var $callback;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean false if user doesn't exist
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showTrends();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the trends
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTrends()
|
||||
{
|
||||
// TRANS: Server error for unfinished API method showTrends.
|
||||
$this->serverError(_('API method under construction.'), 501);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a user's followers (subscribers)
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Ouputs the authenticating user's followers (subscribers), each with
|
||||
* current Twitter-style status inline. They are ordered by the order
|
||||
* in which they subscribed to the user, 100 at a time.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiUserFollowersAction extends ApiSubscriptionsAction
|
||||
{
|
||||
/**
|
||||
* Get the user's subscribers (followers) as an array of profiles
|
||||
*
|
||||
* @return array Profiles
|
||||
*/
|
||||
protected function getProfiles()
|
||||
{
|
||||
$offset = ($this->page - 1) * $this->count;
|
||||
$limit = $this->count + 1;
|
||||
|
||||
$subs = null;
|
||||
|
||||
if (isset($this->tag)) {
|
||||
$subs = $this->target->getTaggedSubscribers(
|
||||
$this->tag, $offset, $limit
|
||||
);
|
||||
} else {
|
||||
$subs = $this->target->getSubscribers(
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
}
|
||||
|
||||
$profiles = array();
|
||||
|
||||
while ($subs->fetch()) {
|
||||
$profiles[] = clone($subs);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a user's friends (subscriptions)
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Ouputs the authenticating user's friends (subscriptions), each with
|
||||
* current Twitter-style status inline. They are ordered by the date
|
||||
* in which the user subscribed to them, 100 at a time.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiUserFriendsAction extends ApiSubscriptionsAction
|
||||
{
|
||||
/**
|
||||
* Get the user's subscriptions (friends) as an array of profiles
|
||||
*
|
||||
* @return array Profiles
|
||||
*/
|
||||
protected function getProfiles()
|
||||
{
|
||||
$offset = ($this->page - 1) * $this->count;
|
||||
$limit = $this->count + 1;
|
||||
|
||||
$subs = null;
|
||||
|
||||
if (isset($this->tag)) {
|
||||
$subs = $this->target->getTaggedSubscriptions(
|
||||
$this->tag, $offset, $limit
|
||||
);
|
||||
} else {
|
||||
$subs = $this->target->getSubscribed(
|
||||
$offset,
|
||||
$limit
|
||||
);
|
||||
}
|
||||
|
||||
$profiles = array();
|
||||
|
||||
while ($subs->fetch()) {
|
||||
$profiles[] = clone($subs);
|
||||
}
|
||||
|
||||
return $profiles;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Return a user's avatar image
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Brion Vibber <brion@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ouputs avatar URL for a user, specified by screen name.
|
||||
* Unlike most API endpoints, this returns an HTTP redirect rather than direct data.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Brion Vibber <brion@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiUserProfileImageAction extends ApiPrivateAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
$user = User::getKV('nickname', $this->arg('screen_name'));
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed when requesting user information for a non-existing user.
|
||||
$this->clientError(_('User not found.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
$this->size = $this->arg('size');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
$size = $this->avatarSize();
|
||||
$url = $this->target->avatarUrl($size);
|
||||
|
||||
// We don't actually output JSON or XML data -- redirect!
|
||||
common_redirect($url, 302);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate pixel size for an avatar based on the request...
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function avatarSize()
|
||||
{
|
||||
switch ($this->size) {
|
||||
case 'mini':
|
||||
return AVATAR_MINI_SIZE; // 24x24
|
||||
case 'bigger':
|
||||
return AVATAR_PROFILE_SIZE; // Twitter does 73x73, but we do 96x96
|
||||
case 'normal': // fall through
|
||||
default:
|
||||
return AVATAR_STREAM_SIZE; // 48x48
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show a user's profile information
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ouputs information for a user, specified by ID or screen name.
|
||||
* The user's most recent status will be returned inline.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Dan Moore <dan@moore.cx>
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author mac65 <mac65@mac65.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApiUserShowAction extends ApiPrivateAuthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$email = $this->arg('email');
|
||||
|
||||
// XXX: email field deprecated in Twitter's API
|
||||
|
||||
if (!empty($email)) {
|
||||
$user = User::getKV('email', $email);
|
||||
} else {
|
||||
$user = $this->getTargetUser($this->arg('id'));
|
||||
}
|
||||
|
||||
if (!($user instanceof User)) {
|
||||
// TRANS: Client error displayed when requesting user information for a non-existing user.
|
||||
$this->clientError(_('User not found.'), 404);
|
||||
}
|
||||
$this->target = $user->getProfile();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Check the format and show the user info
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function handle()
|
||||
{
|
||||
parent::handle();
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
// TRANS: Client error displayed when coming across a non-supported API method.
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
}
|
||||
|
||||
$twitter_user = $this->twitterUserArray($this->target, true);
|
||||
|
||||
if ($this->format == 'xml') {
|
||||
$this->initDocument('xml');
|
||||
$this->showTwitterXmlUser($twitter_user, 'user', true);
|
||||
$this->endDocument('xml');
|
||||
} elseif ($this->format == 'json') {
|
||||
$this->initDocument('json');
|
||||
$this->showJsonObjects($twitter_user);
|
||||
$this->endDocument('json');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Leave a group
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category Group
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2008-2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave a group
|
||||
*
|
||||
* This is the action for leaving a group. It works more or less like the subscribe action
|
||||
* for users.
|
||||
*
|
||||
* @category Group
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApprovegroupAction extends Action
|
||||
{
|
||||
var $group = null;
|
||||
|
||||
/**
|
||||
* Prepare to run
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
// TRANS: Client error displayed when trying to leave a group while not logged in.
|
||||
$this->clientError(_('You must be logged in to leave a group.'));
|
||||
}
|
||||
|
||||
$nickname_arg = $this->trimmed('nickname');
|
||||
$id = intval($this->arg('id'));
|
||||
if ($id) {
|
||||
$this->group = User_group::getKV('id', $id);
|
||||
} else if ($nickname_arg) {
|
||||
$nickname = common_canonical_nickname($nickname_arg);
|
||||
|
||||
// Permanent redirect on non-canonical nickname
|
||||
|
||||
if ($nickname_arg != $nickname) {
|
||||
$args = array('nickname' => $nickname);
|
||||
common_redirect(common_local_url('leavegroup', $args), 301);
|
||||
}
|
||||
|
||||
$local = Local_group::getKV('nickname', $nickname);
|
||||
|
||||
if (!$local) {
|
||||
// TRANS: Client error displayed when trying to leave a non-local group.
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
}
|
||||
|
||||
$this->group = User_group::getKV('id', $local->group_id);
|
||||
} else {
|
||||
// TRANS: Client error displayed when trying to leave a group without providing a group name or group ID.
|
||||
$this->clientError(_('No nickname or ID.'), 404);
|
||||
}
|
||||
|
||||
if (!$this->group) {
|
||||
// TRANS: Client error displayed when trying to leave a non-existing group.
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
if (empty($cur)) {
|
||||
// TRANS: Client error displayed trying to approve group membership while not logged in.
|
||||
$this->clientError(_('Must be logged in.'), 403);
|
||||
}
|
||||
if ($this->arg('profile_id')) {
|
||||
if ($cur->isAdmin($this->group)) {
|
||||
$this->profile = Profile::getKV('id', $this->arg('profile_id'));
|
||||
} else {
|
||||
// TRANS: Client error displayed trying to approve group membership while not a group administrator.
|
||||
$this->clientError(_('Only group admin can approve or cancel join requests.'), 403);
|
||||
}
|
||||
} else {
|
||||
// TRANS: Client error displayed trying to approve group membership without specifying a profile to approve.
|
||||
$this->clientError(_('Must specify a profile.'));
|
||||
}
|
||||
|
||||
$this->request = Group_join_queue::pkeyGet(array('profile_id' => $this->profile->id,
|
||||
'group_id' => $this->group->id));
|
||||
|
||||
if (empty($this->request)) {
|
||||
// TRANS: Client error displayed trying to approve group membership for a non-existing request.
|
||||
// TRANS: %s is a nickname.
|
||||
$this->clientError(sprintf(_('%s is not in the moderation queue for this group.'), $this->profile->nickname), 403);
|
||||
}
|
||||
|
||||
$this->approve = (bool)$this->arg('approve');
|
||||
$this->cancel = (bool)$this->arg('cancel');
|
||||
if (!$this->approve && !$this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny group membership.
|
||||
$this->clientError(_('Internal error: received neither cancel nor abort.'));
|
||||
}
|
||||
if ($this->approve && $this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny group membership.
|
||||
$this->clientError(_('Internal error: received both cancel and abort.'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* On POST, add the current user to the group
|
||||
*
|
||||
* @param array $args unused
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
try {
|
||||
if ($this->approve) {
|
||||
$this->request->complete();
|
||||
} elseif ($this->cancel) {
|
||||
$this->request->abort();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_ERR, "Exception canceling group sub: " . $e->getMessage());
|
||||
// TRANS: Server error displayed when cancelling a queued group join request fails.
|
||||
// TRANS: %1$s is the leaving user's nickname, $2$s is the group nickname for which the leave failed.
|
||||
$this->serverError(sprintf(_('Could not cancel request for user %1$s to join group %2$s.'),
|
||||
$this->profile->nickname, $this->group->nickname));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title for leave group page after group join request is approved/disapproved.
|
||||
// TRANS: %1$s is the user nickname, %2$s is the group nickname.
|
||||
$this->element('title', null, sprintf(_m('TITLE','%1$s\'s request for %2$s'),
|
||||
$this->profile->nickname,
|
||||
$this->group->nickname));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
if ($this->approve) {
|
||||
// TRANS: Message on page for group admin after approving a join request.
|
||||
$this->element('p', 'success', _('Join request approved.'));
|
||||
} elseif ($this->cancel) {
|
||||
// TRANS: Message on page for group admin after rejecting a join request.
|
||||
$this->element('p', 'success', _('Join request canceled.'));
|
||||
}
|
||||
$this->elementEnd('body');
|
||||
$this->endHTML();
|
||||
} else {
|
||||
common_redirect(common_local_url('groupmembers', array('nickname' => $this->group->nickname)), 303);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Approve group subscription request
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: 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/>.
|
||||
*
|
||||
* @category Group
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2008-2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave a group
|
||||
*
|
||||
* This is the action for leaving a group. It works more or less like the subscribe action
|
||||
* for users.
|
||||
*
|
||||
* @category Group
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApprovesubAction extends Action
|
||||
{
|
||||
var $profile = null;
|
||||
|
||||
/**
|
||||
* Prepare to run
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$cur = common_current_user();
|
||||
if (empty($cur)) {
|
||||
// TRANS: Client error displayed trying to approve group membership while not logged in.
|
||||
$this->clientError(_('Must be logged in.'), 403);
|
||||
}
|
||||
if ($this->arg('profile_id')) {
|
||||
$this->profile = Profile::getKV('id', $this->arg('profile_id'));
|
||||
} else {
|
||||
// TRANS: Client error displayed trying to approve subscriptionswithout specifying a profile to approve.
|
||||
$this->clientError(_('Must specify a profile.'));
|
||||
}
|
||||
|
||||
$this->request = Subscription_queue::pkeyGet(array('subscriber' => $this->profile->id,
|
||||
'subscribed' => $cur->id));
|
||||
|
||||
if (empty($this->request)) {
|
||||
// TRANS: Client error displayed trying to approve subscription for a non-existing request.
|
||||
// TRANS: %s is a user nickname.
|
||||
$this->clientError(sprintf(_('%s is not in the moderation queue for your subscriptions.'), $this->profile->nickname), 403);
|
||||
}
|
||||
|
||||
$this->approve = (bool)$this->arg('approve');
|
||||
$this->cancel = (bool)$this->arg('cancel');
|
||||
if (!$this->approve && !$this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny subscription.
|
||||
$this->clientError(_('Internal error: received neither cancel nor abort.'));
|
||||
}
|
||||
if ($this->approve && $this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny subscription
|
||||
$this->clientError(_('Internal error: received both cancel and abort.'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* On POST, add the current user to the group
|
||||
*
|
||||
* @param array $args unused
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$cur = common_current_user();
|
||||
|
||||
try {
|
||||
if ($this->approve) {
|
||||
$this->request->complete();
|
||||
} elseif ($this->cancel) {
|
||||
$this->request->abort();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_ERR, "Exception canceling sub: " . $e->getMessage());
|
||||
// TRANS: Server error displayed when cancelling a queued subscription request fails.
|
||||
// TRANS: %1$s is the leaving user's nickname, $2$s is the nickname for which the leave failed.
|
||||
$this->serverError(sprintf(_('Could not cancel or approve request for user %1$s to join group %2$s.'),
|
||||
$this->profile->nickname, $cur->nickname));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title for subscription approval ajax return
|
||||
// TRANS: %1$s is the approved user's nickname
|
||||
$this->element('title', null, sprintf(_m('TITLE','%1$s\'s request'),
|
||||
$this->profile->nickname));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
if ($this->approve) {
|
||||
// TRANS: Message on page for user after approving a subscription request.
|
||||
$this->element('p', 'success', _('Subscription approved.'));
|
||||
} elseif ($this->cancel) {
|
||||
// TRANS: Message on page for user after rejecting a subscription request.
|
||||
$this->element('p', 'success', _('Subscription canceled.'));
|
||||
}
|
||||
$this->elementEnd('body');
|
||||
$this->endHTML();
|
||||
} else {
|
||||
common_redirect(common_local_url('subqueue', array('nickname' =>
|
||||
$cur->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,278 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* Feed of group memberships for a user, in ActivityStreams format
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* @category AtomPub
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Feed of group memberships for a user, in ActivityStreams format
|
||||
*
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AtompubmembershipfeedAction extends AtompubAction
|
||||
{
|
||||
private $_profile = null;
|
||||
private $_memberships = null;
|
||||
|
||||
protected function atompubPrepare()
|
||||
{
|
||||
$this->_profile = Profile::getKV('id', $this->trimmed('profile'));
|
||||
|
||||
if (!$this->_profile instanceof Profile) {
|
||||
// TRANS: Client exception.
|
||||
throw new ClientException(_('No such profile.'), 404);
|
||||
}
|
||||
|
||||
$this->_memberships = Group_member::byMember($this->_profile->id,
|
||||
$this->offset,
|
||||
$this->limit);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handleGet()
|
||||
{
|
||||
return $this->showFeed();
|
||||
}
|
||||
|
||||
protected function handlePost()
|
||||
{
|
||||
return $this->addMembership();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a feed of favorite activity streams objects
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showFeed()
|
||||
{
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$url = common_local_url('AtomPubMembershipFeed',
|
||||
array('profile' => $this->_profile->id));
|
||||
|
||||
$feed = new Atom10Feed(true);
|
||||
|
||||
$feed->addNamespace('activity',
|
||||
'http://activitystrea.ms/spec/1.0/');
|
||||
|
||||
$feed->addNamespace('poco',
|
||||
'http://portablecontacts.net/spec/1.0');
|
||||
|
||||
$feed->addNamespace('media',
|
||||
'http://purl.org/syndication/atommedia');
|
||||
|
||||
$feed->id = $url;
|
||||
|
||||
$feed->setUpdated('now');
|
||||
|
||||
$feed->addAuthor($this->_profile->getBestName(),
|
||||
$this->_profile->getURI());
|
||||
|
||||
// TRANS: Title for group membership feed.
|
||||
// TRANS: %s is a username.
|
||||
$feed->setTitle(sprintf(_('Group memberships of %s'),
|
||||
$this->_profile->getBestName()));
|
||||
|
||||
// TRANS: Subtitle for group membership feed.
|
||||
// TRANS: %1$s is a username, %2$s is the StatusNet sitename.
|
||||
$feed->setSubtitle(sprintf(_('Groups %1$s is a member of on %2$s'),
|
||||
$this->_profile->getBestName(),
|
||||
common_config('site', 'name')));
|
||||
|
||||
$feed->addLink(common_local_url('usergroups',
|
||||
array('nickname' =>
|
||||
$this->_profile->nickname)));
|
||||
|
||||
$feed->addLink($url,
|
||||
array('rel' => 'self',
|
||||
'type' => 'application/atom+xml'));
|
||||
|
||||
// If there's more...
|
||||
|
||||
if ($this->page > 1) {
|
||||
$feed->addLink($url,
|
||||
array('rel' => 'first',
|
||||
'type' => 'application/atom+xml'));
|
||||
|
||||
$feed->addLink(common_local_url('AtomPubMembershipFeed',
|
||||
array('profile' =>
|
||||
$this->_profile->id),
|
||||
array('page' =>
|
||||
$this->page - 1)),
|
||||
array('rel' => 'prev',
|
||||
'type' => 'application/atom+xml'));
|
||||
}
|
||||
|
||||
if ($this->_memberships->N > $this->count) {
|
||||
|
||||
$feed->addLink(common_local_url('AtomPubMembershipFeed',
|
||||
array('profile' =>
|
||||
$this->_profile->id),
|
||||
array('page' =>
|
||||
$this->page + 1)),
|
||||
array('rel' => 'next',
|
||||
'type' => 'application/atom+xml'));
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
|
||||
while ($this->_memberships->fetch()) {
|
||||
|
||||
// We get one more than needed; skip that one
|
||||
|
||||
$i++;
|
||||
|
||||
if ($i > $this->count) {
|
||||
break;
|
||||
}
|
||||
|
||||
$act = $this->_memberships->asActivity();
|
||||
$feed->addEntryRaw($act->asString(false, false, false));
|
||||
}
|
||||
|
||||
$this->raw($feed->getString());
|
||||
}
|
||||
|
||||
/**
|
||||
* add a new favorite
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function addMembership()
|
||||
{
|
||||
// XXX: Refactor this; all the same for atompub
|
||||
|
||||
if (empty($this->auth_user) ||
|
||||
$this->auth_user->id != $this->_profile->id) {
|
||||
// TRANS: Client exception thrown when trying subscribe someone else to a group.
|
||||
throw new ClientException(_("Cannot add someone else's".
|
||||
" membership."), 403);
|
||||
}
|
||||
|
||||
$xml = file_get_contents('php://input');
|
||||
|
||||
$dom = DOMDocument::loadXML($xml);
|
||||
|
||||
if ($dom->documentElement->namespaceURI != Activity::ATOM ||
|
||||
$dom->documentElement->localName != 'entry') {
|
||||
// TRANS: Client error displayed when not using an Atom entry.
|
||||
throw new ClientException(_('Atom post must be an Atom entry.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$activity = new Activity($dom->documentElement);
|
||||
|
||||
$membership = null;
|
||||
|
||||
if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
|
||||
if ($activity->verb != ActivityVerb::JOIN) {
|
||||
// TRANS: Client error displayed when not using the join verb.
|
||||
throw new ClientException(_('Can only handle join activities.'));
|
||||
}
|
||||
|
||||
$groupObj = $activity->objects[0];
|
||||
|
||||
if ($groupObj->type != ActivityObject::GROUP) {
|
||||
// TRANS: Client exception thrown when trying to join something which is not a group
|
||||
throw new ClientException(_('Can only join groups.'));
|
||||
}
|
||||
|
||||
$group = User_group::getKV('uri', $groupObj->id);
|
||||
|
||||
if (empty($group)) {
|
||||
// XXX: import from listed URL or something
|
||||
// TRANS: Client exception thrown when trying to subscribe to a non-existing group.
|
||||
throw new ClientException(_('Unknown group.'));
|
||||
}
|
||||
|
||||
$old = Group_member::pkeyGet(array('profile_id' => $this->auth_user->id,
|
||||
'group_id' => $group->id));
|
||||
|
||||
if (!empty($old)) {
|
||||
// TRANS: Client exception thrown when trying to subscribe to an already subscribed group.
|
||||
throw new ClientException(_('Already a member.'));
|
||||
}
|
||||
|
||||
$profile = $this->auth_user->getProfile();
|
||||
|
||||
if (Group_block::isBlocked($group, $profile)) {
|
||||
// XXX: import from listed URL or something
|
||||
// TRANS: Client exception thrown when trying to subscribe to group while blocked from that group.
|
||||
throw new ClientException(_('Blocked by admin.'));
|
||||
}
|
||||
|
||||
$this->auth_user->joinGroup($group);
|
||||
|
||||
Event::handle('EndAtomPubNewActivity', array($activity, $membership));
|
||||
}
|
||||
|
||||
if (!empty($membership)) {
|
||||
$act = $membership->asActivity();
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
header('Content-Location: ' . $act->selfLink);
|
||||
|
||||
$this->startXML();
|
||||
$this->raw($act->asString(true, true, true));
|
||||
$this->endXML();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last modified, if applicable.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @return string last modified http header
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
// For comparison with If-Last-Modified
|
||||
// If not applicable, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return etag, if applicable.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @return string etag http header
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* Show a single membership as an Activity Streams entry
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* @category AtomPub
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Show (or delete) a single membership event as an ActivityStreams entry
|
||||
*
|
||||
* @category AtomPub
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AtompubshowmembershipAction extends AtompubAction
|
||||
{
|
||||
private $_private = null;
|
||||
private $_group = null;
|
||||
private $_membership = null;
|
||||
|
||||
protected function atompubPrepare()
|
||||
{
|
||||
$this->_profile = Profile::getKV('id', $this->trimmed('profile'));
|
||||
|
||||
if (!$this->_profile instanceof Profile) {
|
||||
// TRANS: Client exception.
|
||||
throw new ClientException(_('No such profile.'), 404);
|
||||
}
|
||||
|
||||
$this->_group = User_group::getKV('id', $this->trimmed('group'));
|
||||
|
||||
if (!$this->_group instanceof User_group) {
|
||||
// TRANS: Client exception thrown when referencing a non-existing group.
|
||||
throw new ClientException(_('No such group.'), 404);
|
||||
}
|
||||
|
||||
$kv = array('group_id' => $groupId,
|
||||
'profile_id' => $this->_profile->id);
|
||||
|
||||
$this->_membership = Group_member::pkeyGet($kv);
|
||||
|
||||
if (!$this->_membership instanceof Group_member) {
|
||||
// TRANS: Client exception thrown when trying to show membership of a non-subscribed group
|
||||
throw new ClientException(_('Not a member.'), 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handleGet() {
|
||||
return $this->showMembership();
|
||||
}
|
||||
|
||||
protected function handleDelete() {
|
||||
return $this->deleteMembership();
|
||||
}
|
||||
|
||||
/**
|
||||
* show a single membership
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showMembership()
|
||||
{
|
||||
$activity = $this->_membership->asActivity();
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$this->startXML();
|
||||
$this->raw($activity->asString(true, true, true));
|
||||
$this->endXML();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the membership (leave the group)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function deleteMembership()
|
||||
{
|
||||
if (empty($this->auth_user) ||
|
||||
$this->auth_user->id != $this->_profile->id) {
|
||||
// TRANS: Client exception thrown when deleting someone else's membership.
|
||||
throw new ClientException(_("Cannot delete someone else's".
|
||||
" membership."), 403);
|
||||
}
|
||||
|
||||
$this->auth_user->leaveGroup($this->_group);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last modified, if applicable.
|
||||
*
|
||||
* Because the representation depends on the profile and group,
|
||||
* our last modified value is the maximum of their mod time
|
||||
* with the actual membership's mod time.
|
||||
*
|
||||
* @return string last modified http header
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
return max(strtotime($this->_profile->modified),
|
||||
strtotime($this->_group->modified),
|
||||
strtotime($this->_membership->modified));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return etag, if applicable.
|
||||
*
|
||||
* A "weak" Etag including the profile and group id as well as
|
||||
* the admin flag and ctime of the membership.
|
||||
*
|
||||
* @return string etag http header
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
$ctime = strtotime($this->_membership->created);
|
||||
|
||||
$adminflag = ($this->_membership->is_admin) ? 't' : 'f';
|
||||
|
||||
return 'W/"' . implode(':', array('AtomPubShowMembership',
|
||||
$this->_profile->id,
|
||||
$this->_group->id,
|
||||
$adminflag,
|
||||
$ctime)) . '"';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2010, StatusNet, Inc.
|
||||
*
|
||||
* Single subscription
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* @category AtomPub
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL') && !defined('STATUSNET')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Show a single subscription
|
||||
*
|
||||
* @category AtomPub
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class AtompubshowsubscriptionAction extends AtompubAction
|
||||
{
|
||||
private $_subscriber = null;
|
||||
private $_subscribed = null;
|
||||
private $_subscription = null;
|
||||
|
||||
protected function atompubPrepare()
|
||||
{
|
||||
$subscriberId = $this->trimmed('subscriber');
|
||||
|
||||
$this->_subscriber = Profile::getKV('id', $subscriberId);
|
||||
|
||||
if (!$this->_subscriber instanceof Profile) {
|
||||
// TRANS: Client exception thrown when trying to display a subscription for a non-existing profile ID.
|
||||
// TRANS: %d is the non-existing profile ID number.
|
||||
throw new ClientException(sprintf(_('No such profile id: %d.'),
|
||||
$subscriberId), 404);
|
||||
}
|
||||
|
||||
$subscribedId = $this->trimmed('subscribed');
|
||||
|
||||
$this->_subscribed = Profile::getKV('id', $subscribedId);
|
||||
|
||||
if (!$this->_subscribed instanceof Profile) {
|
||||
// TRANS: Client exception thrown when trying to display a subscription for a non-existing profile ID.
|
||||
// TRANS: %d is the non-existing profile ID number.
|
||||
throw new ClientException(sprintf(_('No such profile id: %d.'),
|
||||
$subscribedId), 404);
|
||||
}
|
||||
|
||||
$this->_subscription = Subscription::pkeyGet(array('subscriber' => $subscriberId,
|
||||
'subscribed' => $subscribedId));
|
||||
if (!$this->_subscription instanceof Subscription) {
|
||||
// TRANS: Client exception thrown when trying to display a subscription for a non-subscribed profile ID.
|
||||
// TRANS: %1$d is the non-existing subscriber ID number, $2$d is the ID of the profile that was not subscribed to.
|
||||
$msg = sprintf(_('Profile %1$d not subscribed to profile %2$d.'),
|
||||
$subscriberId, $subscribedId);
|
||||
throw new ClientException($msg, 404);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handleGet()
|
||||
{
|
||||
$this->showSubscription();
|
||||
}
|
||||
|
||||
protected function handleDelete()
|
||||
{
|
||||
$this->deleteSubscription();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the subscription in ActivityStreams Atom format.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showSubscription()
|
||||
{
|
||||
$activity = $this->_subscription->asActivity();
|
||||
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
|
||||
$this->startXML();
|
||||
$this->raw($activity->asString(true, true, true));
|
||||
$this->endXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the subscription
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function deleteSubscription()
|
||||
{
|
||||
if (!$this->scoped instanceof Profile ||
|
||||
$this->scoped->id != $this->_subscriber->id) {
|
||||
// TRANS: Client exception thrown when trying to delete a subscription of another user.
|
||||
throw new ClientException(_("Cannot delete someone else's subscription."), 403);
|
||||
}
|
||||
|
||||
Subscription::cancel($this->_subscriber, $this->_subscribed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly($args)
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return last modified, if applicable.
|
||||
*
|
||||
* @return string last modified http header
|
||||
*/
|
||||
function lastModified()
|
||||
{
|
||||
return max(strtotime($this->_subscriber->modified),
|
||||
strtotime($this->_subscribed->modified),
|
||||
strtotime($this->_subscription->modified));
|
||||
}
|
||||
|
||||
/**
|
||||
* Etag for this object
|
||||
*
|
||||
* @return string etag http header
|
||||
*/
|
||||
function etag()
|
||||
{
|
||||
$mtime = strtotime($this->_subscription->modified);
|
||||
|
||||
return 'W/"' . implode(':', array('AtomPubShowSubscription',
|
||||
$this->_subscriber->id,
|
||||
$this->_subscribed->id,
|
||||
$mtime)) . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this require authentication?
|
||||
*
|
||||
* @return boolean true if delete, else false
|
||||
*/
|
||||
function requiresAuth()
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue