mirror of
https://github.com/openvk/openvk
synced 2025-04-23 00:23:01 +03:00
Merge branch 'master' into photos-picker
This commit is contained in:
commit
b1910a9ce9
198 changed files with 10474 additions and 1402 deletions
8
.idea/.gitignore
vendored
8
.idea/.gitignore
vendored
|
@ -1,8 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
|
@ -1,35 +0,0 @@
|
|||
<?xml encoding="UTF-8"?>
|
||||
<!ELEMENT latte (tags,filters,variables,functions)>
|
||||
<!ATTLIST latte vendor #REQUIRED>
|
||||
<!ATTLIST latte version #REQUIRED>
|
||||
<!ELEMENT tags (tag)+>
|
||||
<!ELEMENT tag (arguments)?>
|
||||
<!ATTLIST tag name CDATA #REQUIRED>
|
||||
<!ATTLIST tag type (PAIR|UNPAIRED|UNPAIRED_ATTR|ATTR_ONLY|AUTO_EMPTY) #REQUIRED>
|
||||
<!ATTLIST tag allowedFilters (true|false) #IMPLIED>
|
||||
<!ATTLIST tag arguments CDATA #IMPLIED>
|
||||
<!ATTLIST tag deprecatedMessage CDATA #IMPLIED>
|
||||
<!ATTLIST tag multiLine (true|false) #IMPLIED>
|
||||
<!ELEMENT arguments (argument)+>
|
||||
<!ELEMENT argument EMPTY>
|
||||
<!ATTLIST argument name #REQUIRED>
|
||||
<!ATTLIST argument types CDATA #REQUIRED>
|
||||
<!ATTLIST argument repeatable (true|false) #IMPLIED>
|
||||
<!ATTLIST argument required (true|false) #IMPLIED>
|
||||
<!ATTLIST argument validType #IMPLIED>
|
||||
<!ELEMENT filters (filter)+>
|
||||
<!ELEMENT filter EMPTY>
|
||||
<!ATTLIST filter name #REQUIRED>
|
||||
<!ATTLIST filter description CDATA #IMPLIED>
|
||||
<!ATTLIST filter arguments CDATA #IMPLIED>
|
||||
<!ATTLIST filter insertColons #IMPLIED>
|
||||
<!ELEMENT variables (variable)+>
|
||||
<!ELEMENT variable EMPTY>
|
||||
<!ATTLIST variable name #REQUIRED>
|
||||
<!ATTLIST variable type CDATA #REQUIRED>
|
||||
<!ELEMENT functions (function)+>
|
||||
<!ELEMENT function EMPTY>
|
||||
<!ATTLIST function name #REQUIRED>
|
||||
<!ATTLIST function arguments CDATA #REQUIRED>
|
||||
<!ATTLIST function returnType #REQUIRED>
|
||||
<!ATTLIST function description CDATA #IMPLIED>
|
|
@ -1,290 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE latte PUBLIC "-//LATTE//Latte plugin XML V0.0.1//EN" "Latte.dtd">
|
||||
<latte vendor="latte" version="1">
|
||||
<tags>
|
||||
<tag name="_" type="AUTO_EMPTY" allowedFilters="true">
|
||||
<arguments>
|
||||
<argument name="expression" types="PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="=" type="UNPAIRED" allowedFilters="true">
|
||||
<arguments>
|
||||
<argument name="expression" types="PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="block" type="AUTO_EMPTY" allowedFilters="true" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="breakIf" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="condition" types="PHP_CONDITION" validType="bool" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="capture" type="PAIR" allowedFilters="true" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="variable" types="VARIABLE_DEFINITION" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="case" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="condition" types="PHP_CONDITION" required="true" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="catch" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="condition" types="PHP_CONDITION" validType="bool" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="contentType" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="content-type" types="CONTENT_TYPE" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="continueIf" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="condition" types="PHP_CONDITION" validType="bool" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="debugbreak" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="expression" types="PHP_EXPRESSION" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="default" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="variable" types="VARIABLE_DEFINITION_EXPRESSION" required="true" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="define" type="PAIR" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" required="true" />
|
||||
<argument name="variable" types="VARIABLE_DEFINITION_ITEM" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="do" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="expression" types="PHP_EXPRESSION" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="dump" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="expression" types="PHP_EXPRESSION" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="else" type="UNPAIRED_ATTR" />
|
||||
<tag name="elseif" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="condition" types="PHP_CONDITION" validType="bool" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="elseifset" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="var" types="VARIABLE,BLOCK" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="extends" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="file" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION,NONE" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="first" type="PAIR">
|
||||
<arguments>
|
||||
<argument name="width" types="PHP_IDENTIFIER,PHP_EXPRESSION" validType="int" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="for" type="PAIR" arguments="initialization; condition; afterthought" multiLine="true" />
|
||||
<tag name="foreach" type="PAIR" arguments="expression as [$key =>] $value" allowedFilters="true" multiLine="true" />
|
||||
<tag name="if" type="PAIR">
|
||||
<arguments>
|
||||
<argument name="condition" types="PHP_CONDITION" validType="bool" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="ifset" type="PAIR">
|
||||
<arguments>
|
||||
<argument name="var" types="VARIABLE,BLOCK,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="import" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="file" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="include" type="UNPAIRED" allowedFilters="true">
|
||||
<arguments>
|
||||
<argument name="file" types="BLOCK,IDENTIFIER,PHP_EXPRESSION" validType="string" required="true" />
|
||||
<argument name="arguments" types="KEY_VALUE" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="includeblock" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="file" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="l" type="UNPAIRED" />
|
||||
<tag name="last" type="PAIR">
|
||||
<arguments>
|
||||
<argument name="width" types="PHP_IDENTIFIER,PHP_EXPRESSION" validType="int" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="layout" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="file" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION,NONE" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="class" type="ATTR_ONLY" arguments="class" />
|
||||
<tag name="attr" type="ATTR_ONLY" arguments="attr" />
|
||||
<tag name="ifcontent" type="ATTR_ONLY" />
|
||||
<tag name="php" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="expression" types="PHP_EXPRESSION" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="r" type="UNPAIRED" />
|
||||
<tag name="sandbox" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="file" types="BLOCK,PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" validType="string" required="true" />
|
||||
<argument name="key-value" types="KEY_VALUE" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="sep" type="PAIR">
|
||||
<arguments>
|
||||
<argument name="width" types="PHP_IDENTIFIER,PHP_EXPRESSION" validType="int" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="snippet" type="PAIR" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" validType="string" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="snippetArea" type="PAIR" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="spaceless" type="PAIR" />
|
||||
<tag name="switch" type="PAIR" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="expression" types="PHP_EXPRESSION" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="syntax" type="PAIR" arguments="off | double | latte" multiLine="true" />
|
||||
<tag name="templatePrint" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="class-name" types="PHP_CLASS_NAME" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="templateType" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="class-name" types="PHP_CLASS_NAME" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="try" type="PAIR" />
|
||||
<tag name="rollback" type="UNPAIRED" />
|
||||
<tag name="tag" type="ATTR_ONLY">
|
||||
<arguments>
|
||||
<argument name="expression" types="PHP_EXPRESSION" required="true" validType="string" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="ifchanged" type="PAIR">
|
||||
<arguments>
|
||||
<argument name="expression" types="PHP_EXPRESSION" required="true" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="skipIf" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="condition" types="PHP_CONDITION" validType="bool" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="var" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="variable" types="VARIABLE_DEFINITION_EXPRESSION" required="true" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="trace" type="UNPAIRED" />
|
||||
<tag name="varPrint" type="UNPAIRED" arguments="all" />
|
||||
<tag name="varType" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="file" types="PHP_TYPE" required="true" />
|
||||
<argument name="variable" types="VARIABLE_DEFINITION" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="while" type="PAIR" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="condition" types="PHP_CONDITION" validType="bool" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="iterateWhile" type="PAIR" multiLine="true" />
|
||||
<tag name="embed" type="PAIR" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="file" types="BLOCK_USAGE,PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" validType="string" required="true" />
|
||||
<argument name="key-value" types="KEY_VALUE" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<!-- @deprecated - latte -->
|
||||
<tag name="assign" type="UNPAIRED" arguments="$variable = expr" />
|
||||
<tag name="truncate" type="UNPAIRED" arguments="expression" deprecatedMessage="Tag {? ...} is deprecated in Latte 2.4. For variable definitions use {var ...} or {php ...} in other cases." />
|
||||
</tags>
|
||||
<filters>
|
||||
<filter name="truncate" arguments=":($length, $append = '…')" description="shortens the length preserving whole words" insertColons=":" />
|
||||
<filter name="substr" arguments=":($offset [, $length])" description="returns part of the string" insertColons=":" />
|
||||
<filter name="trim" arguments=":($charset = mezery)" description="strips whitespace or other characters from the beginning and end of the string" />
|
||||
<filter name="stripHtml" arguments="" description="removes HTML tags and converts HTML entities to text" />
|
||||
<filter name="strip" arguments="" description="removes whitespace" />
|
||||
<filter name="indent" arguments=":($level = 1, $char = '\t')" description="indents the text from left with number of tabs" />
|
||||
<filter name="replace" arguments=":($search, $replace = '')" description="replaces all occurrences of the search string with the replacement" insertColons=":" />
|
||||
<filter name="replaceRE" arguments=":($pattern, $replace = '')" description="replaces all occurrences according to regular expression" insertColons=":" />
|
||||
<filter name="padLeft" arguments=":($length, $pad = ' ')" description="completes the string to given length from left" insertColons=":" />
|
||||
<filter name="padRight" arguments=":($length, $pad = ' ')" description="completes the string to given length from right" insertColons=":" />
|
||||
<filter name="repeat" arguments=":($count)" description="repeats the string" insertColons=":" />
|
||||
<filter name="implode" arguments=":($glue = '')" description="joins an array to a string" />
|
||||
<filter name="webalize" description="adjusts the UTF-8 string to the shape used in the URL" />
|
||||
<filter name="breaklines" description="inserts HTML line breaks before all newlines" />
|
||||
<filter name="reverse" description="reverse an UTF-8 string or array" />
|
||||
<filter name="length" description="returns length of a string or array" />
|
||||
<filter name="sort" description="simply sorts array" />
|
||||
<filter name="reverse" description="array sorted in reverse order (used with |sort)" />
|
||||
<filter name="batch" arguments=":($array, $length [, $item])" description="returns length of a string or array" insertColons="::" />
|
||||
|
||||
<filter name="clamp" description="returns value clamped to the inclusive range of min and max." insertColons="::" />
|
||||
|
||||
<filter name="lower" description="makes a string lower case" />
|
||||
<filter name="upper" description="makes a string upper case" />
|
||||
<filter name="firstUpper" description="makes the first letter upper case" />
|
||||
<filter name="capitalize" description="lower case, the first letter of each word upper case" />
|
||||
|
||||
<filter name="date" arguments=":($format)" description="formats date" insertColons=":" />
|
||||
<filter name="number" arguments=":($decimals = 0, $decPoint = '.', $thousandsSep = ',')" description="format number" />
|
||||
<filter name="bytes" arguments=":($precision = 2)" description="formats size in bytes" />
|
||||
<filter name="dataStream" arguments=":($mimetype = 'detect')" description="Data URI protocol conversion" />
|
||||
|
||||
<filter name="noescape" description="prints a variable without escaping" />
|
||||
<filter name="escapeurl" description="escapes parameter in URL" />
|
||||
|
||||
<filter name="nocheck" description="prevents automatic URL sanitization" />
|
||||
<filter name="checkurl" description="sanitizes string for use inside href attribute" />
|
||||
|
||||
<filter name="query" description="generates a query string in the URL" />
|
||||
<filter name="ceil" arguments=":(int $precision = 0)" description="rounds a number up to a given precision" />
|
||||
<filter name="explode" arguments=":(string $separator = '')" description="splits a string by the given delimiter" />
|
||||
<filter name="first" description="returns first element of array or character of string" />
|
||||
<filter name="floor" arguments=":(int $precision = 0)" description="rounds a number down to a given precision" />
|
||||
<filter name="join" arguments=":(string $glue = '')" description="joins an array to a string" />
|
||||
<filter name="last" description="returns last element of array or character of string" />
|
||||
<filter name="random" description="returns random element of array or character of string" />
|
||||
<filter name="round" arguments=":(int $precision = 0)" description="rounds a number to a given precision" />
|
||||
<filter name="slice" arguments=":(int $start, int $length = null, bool $preserveKeys = false)" description="extracts a slice of an array or a string" insertColons=":" />
|
||||
<filter name="spaceless" description="removes whitespace" />
|
||||
<filter name="split" arguments=":(string $separator = '')" description="splits a string by the given delimiter" />
|
||||
</filters>
|
||||
<functions>
|
||||
<function name="clamp" returnType="int|float" arguments="(int|float $value, int|float $min, int|float $max)" description="clamps value to the inclusive range of min and max" />
|
||||
<function name="divisibleBy" returnType="bool" arguments="(int $value)" description="checks if a variable is divisible by a number" />
|
||||
<function name="even" returnType="bool" arguments="(int $value)" description="checks if the given number is even" />
|
||||
<function name="first" returnType="mixed" arguments="(string|array $value)" description="returns first element of array or character of string" />
|
||||
<function name="last" returnType="mixed" arguments="(string|array $value)" description="returns last element of array or character of string" />
|
||||
<function name="odd" returnType="bool" arguments="(int $value)" description="checks if the given number is odd" />
|
||||
<function name="slice" returnType="string|array" arguments="(string|array $value, int $start, int $length = null, bool $preserveKeys = false)" description="extracts a slice of an array or a string" />
|
||||
</functions>
|
||||
</latte>
|
|
@ -1,59 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE latte PUBLIC "-//LATTE//Latte plugin configuration XML V0.0.1//EN" "Latte.dtd">
|
||||
<latte version="1" vendor="nette/application">
|
||||
<tags>
|
||||
<!-- nette/application tags -->
|
||||
<tag name="cache" type="PAIR" arguments="if => expr, key, …">
|
||||
<arguments>
|
||||
<argument name="name[:part]" types="KEY_VALUE" validType="string" required="true" />
|
||||
<argument name="arguments" types="PHP_EXPRESSION" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="control" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="name[:part]" types="PHP_IDENTIFIER,PHP_EXPRESSION" validType="string" required="true" />
|
||||
<argument name="arguments" types="PHP_EXPRESSION" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="link" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="destination" types="LINK_DESTINATION,PHP_EXPRESSION" validType="string" required="true" />
|
||||
<argument name="arguments" types="LINK_PARAMETERS" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="href" type="ATTR_ONLY">
|
||||
<arguments>
|
||||
<argument name="destination" types="LINK_DESTINATION,PHP_EXPRESSION" validType="string" required="true" />
|
||||
<argument name="arguments" types="LINK_PARAMETERS" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="nonce" type="ATTR_ONLY" />
|
||||
<tag name="plink" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="destination" types="LINK_DESTINATION,PHP_EXPRESSION" validType="string" required="true" />
|
||||
<argument name="arguments" types="LINK_PARAMETERS" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<!-- @deprecated - nette/application -->
|
||||
<tag name="ifCurrent" type="PAIR" deprecatedMessage="Tag {ifCurrent} is deprecated in Latte 2.6. Use custom function isLinkCurrent() instead.">
|
||||
<arguments>
|
||||
<argument name="destination" types="LINK_DESTINATION,PHP_EXPRESSION" validType="string" required="true" />
|
||||
<argument name="arguments" types="LINK_PARAMETERS" repeatable="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
</tags>
|
||||
<variables>
|
||||
<variable name="control" type="\Nette\Application\UI\Control" />
|
||||
<variable name="basePath" type="string" />
|
||||
<variable name="baseUrl" type="string" />
|
||||
<variable name="flashes" type="mixed[]" />
|
||||
<variable name="presenter" type="\Nette\Application\UI\Presenter" />
|
||||
<variable name="iterator" type="\Latte\Runtime\CachingIterator" />
|
||||
<variable name="form" type="\Nette\Application\UI\Form" />
|
||||
<variable name="user" type="\Nette\Security\User" />
|
||||
</variables>
|
||||
<functions>
|
||||
<function name="isLinkCurrent" returnType="bool" arguments="(string $destination = null, $args = [])" />
|
||||
<function name="isModuleCurrent" returnType="bool" arguments="(string $moduleName)" />
|
||||
</functions>
|
||||
</latte>
|
|
@ -1,41 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE latte PUBLIC "-//LATTE//Latte plugin configuration XML V0.0.1//EN" "Latte.dtd">
|
||||
<latte version="1" vendor="nette/forms">
|
||||
<tags>
|
||||
<tag name="form" type="PAIR" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="formContainer" type="PAIR" multiLine="true">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="formPrint" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="input" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,CONTROL,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="inputError" type="UNPAIRED">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,CONTROL,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="label" type="AUTO_EMPTY">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,CONTROL,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
<tag name="name" type="ATTR_ONLY">
|
||||
<arguments>
|
||||
<argument name="name" types="PHP_IDENTIFIER,VARIABLE,CONTROL,PHP_EXPRESSION" validType="string" required="true" />
|
||||
</arguments>
|
||||
</tag>
|
||||
</tags>
|
||||
</latte>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/openvk.iml" filepath="$PROJECT_DIR$/.idea/openvk.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -1,46 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/rybakit/msgpack" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/chillerlan/php-qrcode" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/cache" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/chillerlan/php-settings-container" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/vearutop/php-obscene-censor-rus" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-message" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php72" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-idn" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/scssphp/scssphp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/bhaktaraz/php-rss-generator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/erusev/parsedown" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ezyang/htmlpurifier" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/whichbrowser/parser" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/komeiji-satori/curl" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/james-heinrich/getid3" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/promises" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ralouphie/getallheaders" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/wapmorgan/binary-stream" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/psr7" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/al/emoji-detector" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/guzzle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/lfkeitel/phptotp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/zadarma/user-api-v1" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-ctype" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php73" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/wapmorgan/morphos" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,48 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/rybakit/msgpack" />
|
||||
<path value="$PROJECT_DIR$/vendor/chillerlan/php-qrcode" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/chillerlan/php-settings-container" />
|
||||
<path value="$PROJECT_DIR$/vendor/vearutop/php-obscene-censor-rus" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php72" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-idn" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/scssphp/scssphp" />
|
||||
<path value="$PROJECT_DIR$/vendor/bhaktaraz/php-rss-generator" />
|
||||
<path value="$PROJECT_DIR$/vendor/erusev/parsedown" />
|
||||
<path value="$PROJECT_DIR$/vendor/ezyang/htmlpurifier" />
|
||||
<path value="$PROJECT_DIR$/vendor/whichbrowser/parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/komeiji-satori/curl" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/james-heinrich/getid3" />
|
||||
<path value="$PROJECT_DIR$/vendor/guzzlehttp/promises" />
|
||||
<path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" />
|
||||
<path value="$PROJECT_DIR$/vendor/wapmorgan/binary-stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" />
|
||||
<path value="$PROJECT_DIR$/vendor/al/emoji-detector" />
|
||||
<path value="$PROJECT_DIR$/vendor/guzzlehttp/guzzle" />
|
||||
<path value="$PROJECT_DIR$/vendor/lfkeitel/phptotp" />
|
||||
<path value="$PROJECT_DIR$/vendor/zadarma/user-api-v1" />
|
||||
<path value="$PROJECT_DIR$/../../../chandler" />
|
||||
<path value="$PROJECT_DIR$/../../../vendor" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php73" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/wapmorgan/morphos" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
|
||||
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
140
DBEntity.updated.php
Normal file
140
DBEntity.updated.php
Normal file
|
@ -0,0 +1,140 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace Chandler\Database;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use Nette\Database\Table\Selection;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
use openvk\Web\Models\Repositories\CurrentUser;
|
||||
use openvk\Web\Models\Repositories\Logs;
|
||||
|
||||
|
||||
abstract class DBEntity
|
||||
{
|
||||
protected $record;
|
||||
protected $changes;
|
||||
protected $deleted;
|
||||
protected $user;
|
||||
|
||||
protected $tableName;
|
||||
|
||||
function __construct(?ActiveRow $row = NULL)
|
||||
{
|
||||
if(is_null($row)) return;
|
||||
|
||||
$_table = $row->getTable()->getName();
|
||||
if($_table !== $this->tableName)
|
||||
throw new ISE("Invalid data supplied for model: table $_table is not compatible with table" . $this->tableName);
|
||||
|
||||
$this->record = $row;
|
||||
}
|
||||
|
||||
function __call(string $fName, array $args)
|
||||
{
|
||||
if(substr($fName, 0, 3) === "set") {
|
||||
$field = mb_strtolower(substr($fName, 3));
|
||||
$this->stateChanges($field, $args[0]);
|
||||
} else {
|
||||
throw new \Error("Call to undefined method " . get_class($this) . "::$fName");
|
||||
}
|
||||
}
|
||||
|
||||
private function getTable(): Selection
|
||||
{
|
||||
return DatabaseConnection::i()->getContext()->table($this->tableName);
|
||||
}
|
||||
|
||||
protected function getRecord(): ?ActiveRow
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
protected function stateChanges(string $column, $value): void
|
||||
{
|
||||
if(!is_null($this->record))
|
||||
$t = $this->record->{$column}; #Test if column exists
|
||||
|
||||
$this->changes[$column] = $value;
|
||||
}
|
||||
|
||||
function getId()
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function isDeleted(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->deleted;
|
||||
}
|
||||
|
||||
function unwrap(): object
|
||||
{
|
||||
return (object) $this->getRecord()->toArray();
|
||||
}
|
||||
|
||||
function delete(bool $softly = true): void
|
||||
{
|
||||
$user = CurrentUser::i()->getUser();
|
||||
$user_id = is_null($user) ? (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getId();
|
||||
|
||||
if(is_null($this->record))
|
||||
throw new ISE("Can't delete a model, that hasn't been flushed to DB. Have you forgotten to call save() first?");
|
||||
|
||||
(new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 2, $this->record->toArray(), $this->changes);
|
||||
|
||||
if($softly) {
|
||||
$this->record = $this->getTable()->where("id", $this->record->id)->update(["deleted" => true]);
|
||||
} else {
|
||||
$this->record->delete();
|
||||
$this->deleted = true;
|
||||
}
|
||||
}
|
||||
|
||||
function undelete(): void
|
||||
{
|
||||
if(is_null($this->record))
|
||||
throw new ISE("Can't undelete a model, that hasn't been flushed to DB. Have you forgotten to call save() first?");
|
||||
|
||||
$user = CurrentUser::i()->getUser();
|
||||
$user_id = is_null($user) ? (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getId();
|
||||
|
||||
(new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 3, $this->record->toArray(), ["deleted" => false]);
|
||||
|
||||
$this->getTable()->where("id", $this->record->id)->update(["deleted" => false]);
|
||||
}
|
||||
|
||||
function save(?bool $log = true): void
|
||||
{
|
||||
if ($log) {
|
||||
$user = CurrentUser::i();
|
||||
$user_id = is_null($user) ? (int)OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getUser()->getId();
|
||||
}
|
||||
|
||||
if(is_null($this->record)) {
|
||||
$this->record = $this->getTable()->insert($this->changes);
|
||||
|
||||
if ($log && $this->getTable()->getName() !== "logs") {
|
||||
(new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 0, $this->record->toArray(), $this->changes);
|
||||
}
|
||||
} else {
|
||||
if ($log && $this->getTable()->getName() !== "logs") {
|
||||
(new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 1, $this->record->toArray(), $this->changes);
|
||||
}
|
||||
|
||||
if ($this->deleted) {
|
||||
$this->record = $this->getTable()->insert((array)$this->record);
|
||||
} else {
|
||||
$this->getTable()->get($this->record->id)->update($this->changes);
|
||||
$this->record = $this->getTable()->get($this->record->id);
|
||||
}
|
||||
}
|
||||
|
||||
$this->changes = [];
|
||||
}
|
||||
|
||||
function getTableName(): string
|
||||
{
|
||||
return $this->getTable()->getName();
|
||||
}
|
||||
|
||||
use \Nette\SmartObject;
|
||||
}
|
|
@ -66,7 +66,7 @@ Once you are done, you can login as a system administrator on the network itself
|
|||
* **Password**: `admin`
|
||||
* It is recommended to change the password of the built-in account or disable it.
|
||||
|
||||
💡Confused? Full installation walkthrough is available [here](https://docs.openvk.su/openvk_engine/centos8_installation/) (CentOS 8 [and](https://almalinux.org/) [family](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
💡Confused? Full installation walkthrough is available [here](https://docs.openvk.uk/openvk_engine/centos8_installation/) (CentOS 8 [and](https://almalinux.org/) [family](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
|
||||
### Looking for Docker or Kubernetes deployment?
|
||||
See `install/automated/docker/README.md` and `install/automated/kubernetes/README.md` for Docker and Kubernetes deployment instructions.
|
||||
|
|
|
@ -66,7 +66,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
* **Пароль**: `admin`
|
||||
* Перед использованием встроенной учетной записи рекомендуется сменить пароль или отключить её.
|
||||
|
||||
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.openvk.su/openvk_engine/centos8_installation/) (CentOS 8 [и](https://almalinux.org/ru/) [семейство](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
💡Запутались? Полное руководство по установке доступно [здесь](https://docs.openvk.uk/openvk_engine/centos8_installation/) (CentOS 8 [и](https://almalinux.org/ru/) [семейство](https://yum.oracle.com/oracle-linux-isos.html)).
|
||||
|
||||
# Установка в Docker/Kubernetes
|
||||
Подробные иструкции можно найти в `install/automated/docker/README.md` и `install/automated/kubernetes/README.md` соответственно.
|
||||
|
|
39
ServiceAPI/Groups.php
Normal file
39
ServiceAPI/Groups.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\ServiceAPI;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\Clubs;
|
||||
|
||||
class Groups implements Handler
|
||||
{
|
||||
protected $user;
|
||||
protected $groups;
|
||||
|
||||
function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->groups = new Clubs;
|
||||
}
|
||||
|
||||
function getWriteableClubs(callable $resolve, callable $reject)
|
||||
{
|
||||
$clubs = [];
|
||||
$wclubs = $this->groups->getWriteableClubs($this->user->getId());
|
||||
$count = $this->groups->getWriteableClubsCount($this->user->getId());
|
||||
|
||||
if(!$count) {
|
||||
$reject("You don't have any groups with write access");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($wclubs as $club) {
|
||||
$clubs[] = [
|
||||
"name" => $club->getName(),
|
||||
"id" => $club->getId(),
|
||||
"avatar" => $club->getAvatarUrl() # если в овк когда-нибудь появится крутой список с аватарками, то можно использовать это поле
|
||||
];
|
||||
}
|
||||
|
||||
$resolve($clubs);
|
||||
}
|
||||
}
|
41
ServiceAPI/Notes.php
Normal file
41
ServiceAPI/Notes.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace openvk\ServiceAPI;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\Notes as NoteRepo;
|
||||
|
||||
class Notes implements Handler
|
||||
{
|
||||
protected $user;
|
||||
protected $notes;
|
||||
|
||||
function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->notes = new NoteRepo;
|
||||
}
|
||||
|
||||
function getNote(int $noteId, callable $resolve, callable $reject): void
|
||||
{
|
||||
$note = $this->notes->get($noteId);
|
||||
if(!$note || $note->isDeleted())
|
||||
$reject(83, "Note is gone");
|
||||
|
||||
$noteOwner = $note->getOwner();
|
||||
assert($noteOwner instanceof User);
|
||||
if(!$noteOwner->getPrivacyPermission("notes.read", $this->user))
|
||||
$reject(160, "You don't have permission to access this note");
|
||||
|
||||
$resolve([
|
||||
"title" => $note->getName(),
|
||||
"link" => "/note" . $note->getPrettyId(),
|
||||
"html" => $note->getText(),
|
||||
"created" => (string) $note->getPublicationTime(),
|
||||
"author" => [
|
||||
"name" => $noteOwner->getCanonicalName(),
|
||||
"ava" => $noteOwner->getAvatarUrl(),
|
||||
"link" => $noteOwner->getURL(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
76
ServiceAPI/Search.php
Normal file
76
ServiceAPI/Search.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\ServiceAPI;
|
||||
use openvk\Web\Models\Entities\{User, Club};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Videos};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
class Search implements Handler
|
||||
{
|
||||
protected $user;
|
||||
private $users;
|
||||
private $clubs;
|
||||
private $videos;
|
||||
|
||||
function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->users = new Users;
|
||||
$this->clubs = new Clubs;
|
||||
$this->videos = new Videos;
|
||||
}
|
||||
|
||||
function fastSearch(string $query, string $type = "users", callable $resolve, callable $reject)
|
||||
{
|
||||
if($query == "" || strlen($query) < 3)
|
||||
$reject(12, "No input or input < 3");
|
||||
|
||||
$repo;
|
||||
$sort;
|
||||
|
||||
switch($type) {
|
||||
default:
|
||||
case "users":
|
||||
$repo = (new Users);
|
||||
$sort = "rating DESC";
|
||||
|
||||
break;
|
||||
case "groups":
|
||||
$repo = (new Clubs);
|
||||
$sort = "id ASC";
|
||||
|
||||
break;
|
||||
case "videos":
|
||||
$repo = (new Videos);
|
||||
$sort = "created ASC";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$res = $repo->find($query, ["doNotSearchMe" => $this->user->getId()], $sort);
|
||||
|
||||
$results = array_slice(iterator_to_array($res), 0, 5);
|
||||
|
||||
$count = sizeof($results);
|
||||
|
||||
$arr = [
|
||||
"count" => $count,
|
||||
"items" => []
|
||||
];
|
||||
|
||||
if(sizeof($results) < 1) {
|
||||
$reject(2, "No results");
|
||||
}
|
||||
|
||||
foreach($results as $res) {
|
||||
$arr["items"][] = [
|
||||
"id" => $res->getId(),
|
||||
"name" => $type == "users" ? $res->getCanonicalName() : $res->getName(),
|
||||
"avatar" => $type != "videos" ? $res->getAvatarUrl() : $res->getThumbnailURL(),
|
||||
"url" => $type != "videos" ? $res->getUrl() : "/video".$res->getPrettyId(),
|
||||
"description" => ovk_proc_strtr($res->getDescription() ?? "...", 40)
|
||||
];
|
||||
}
|
||||
|
||||
$resolve($arr);
|
||||
}
|
||||
}
|
|
@ -2,17 +2,20 @@
|
|||
namespace openvk\ServiceAPI;
|
||||
use openvk\Web\Models\Entities\Post;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\Posts;
|
||||
use openvk\Web\Models\Repositories\{Posts, Notes, Videos};
|
||||
|
||||
class Wall implements Handler
|
||||
{
|
||||
protected $user;
|
||||
protected $posts;
|
||||
protected $notes;
|
||||
|
||||
function __construct(?User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->posts = new Posts;
|
||||
$this->notes = new Notes;
|
||||
$this->videos = new Videos;
|
||||
}
|
||||
|
||||
function getPost(int $id, callable $resolve, callable $reject): void
|
||||
|
@ -71,4 +74,67 @@ class Wall implements Handler
|
|||
|
||||
$resolve($post->getId());
|
||||
}
|
||||
|
||||
function getMyNotes(callable $resolve, callable $reject)
|
||||
{
|
||||
$count = $this->notes->getUserNotesCount($this->user);
|
||||
$myNotes = $this->notes->getUserNotes($this->user, 1, $count);
|
||||
|
||||
$arr = [
|
||||
"count" => $count,
|
||||
"closed" => $this->user->getPrivacySetting("notes.read"),
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($myNotes as $note) {
|
||||
$arr["items"][] = [
|
||||
"id" => $note->getId(),
|
||||
"name" => ovk_proc_strtr($note->getName(), 30),
|
||||
#"preview" => $note->getPreview()
|
||||
];
|
||||
}
|
||||
|
||||
$resolve($arr);
|
||||
}
|
||||
|
||||
function getVideos(int $page = 1, callable $resolve, callable $reject)
|
||||
{
|
||||
$videos = $this->videos->getByUser($this->user, $page, 8);
|
||||
$count = $this->videos->getUserVideosCount($this->user);
|
||||
|
||||
$arr = [
|
||||
"count" => $count,
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($videos as $video) {
|
||||
$res = json_decode(json_encode($video->toVkApiStruct()), true);
|
||||
$res["video"]["author_name"] = $video->getOwner()->getCanonicalName();
|
||||
|
||||
$arr["items"][] = $res;
|
||||
}
|
||||
|
||||
$resolve($arr);
|
||||
}
|
||||
|
||||
function searchVideos(int $page = 1, string $query, callable $resolve, callable $reject)
|
||||
{
|
||||
$dbc = $this->videos->find($query);
|
||||
$videos = $dbc->page($page, 8);
|
||||
$count = $dbc->size();
|
||||
|
||||
$arr = [
|
||||
"count" => $count,
|
||||
"items" => [],
|
||||
];
|
||||
|
||||
foreach($videos as $video) {
|
||||
$res = json_decode(json_encode($video->toVkApiStruct()), true);
|
||||
$res["video"]["author_name"] = $video->getOwner()->getCanonicalName();
|
||||
|
||||
$arr["items"][] = $res;
|
||||
}
|
||||
|
||||
$resolve($arr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,8 @@ final class Account extends VKAPIRequestHandler
|
|||
|
||||
function getCounters(string $filter = ""): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
return (object) [
|
||||
"friends" => $this->getUser()->getFollowersCount(),
|
||||
"notifications" => $this->getUser()->getNotificationsCount(),
|
||||
|
|
431
VKAPI/Handlers/Board.php
Normal file
431
VKAPI/Handlers/Board.php
Normal file
|
@ -0,0 +1,431 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\VKAPI\Handlers\Wall;
|
||||
use openvk\Web\Models\Repositories\Topics as TopicsRepo;
|
||||
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
||||
use openvk\Web\Models\Repositories\Photos as PhotosRepo;
|
||||
use openvk\Web\Models\Repositories\Videos as VideosRepo;
|
||||
use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
||||
use openvk\Web\Models\Entities\{Topic, Comment, User, Photo, Video};
|
||||
|
||||
final class Board extends VKAPIRequestHandler
|
||||
{
|
||||
# 13/13
|
||||
function addTopic(int $group_id, string $title, string $text = "", bool $from_group = true, string $attachments = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = (new ClubsRepo)->get($group_id);
|
||||
|
||||
if(!$club) {
|
||||
$this->fail(403, "Invalid club");
|
||||
}
|
||||
|
||||
if(!$club->canBeModifiedBy($this->getUser()) && !$club->isEveryoneCanCreateTopics()) {
|
||||
$this->fail(403, "Access to club denied");
|
||||
}
|
||||
|
||||
$flags = 0;
|
||||
|
||||
if($from_group == true && $club->canBeModifiedBy($this->getUser()))
|
||||
$flags |= 0b10000000;
|
||||
|
||||
$topic = new Topic;
|
||||
$topic->setGroup($club->getId());
|
||||
$topic->setOwner($this->getUser()->getId());
|
||||
$topic->setTitle(ovk_proc_strtr($title, 127));
|
||||
$topic->setCreated(time());
|
||||
$topic->setFlags($flags);
|
||||
$topic->save();
|
||||
|
||||
if(!empty($text)) {
|
||||
$comment = new Comment;
|
||||
$comment->setOwner($this->getUser()->getId());
|
||||
$comment->setModel(get_class($topic));
|
||||
$comment->setTarget($topic->getId());
|
||||
$comment->setContent($text);
|
||||
$comment->setCreated(time());
|
||||
$comment->setFlags($flags);
|
||||
$comment->save();
|
||||
|
||||
if(!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
# блин а мне это везде копировать типа
|
||||
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
$attachmentType = "video";
|
||||
else
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Photo does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Video does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $topic->getId();
|
||||
}
|
||||
|
||||
function closeTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!$topic->isClosed()) {
|
||||
$topic->setClosed(1);
|
||||
$topic->save();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function createComment(int $group_id, int $topic_id, string $message = "", string $attachments = "", bool $from_group = true)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if(empty($message) && empty($attachments)) {
|
||||
$this->fail(100, "Required parameter 'message' missing.");
|
||||
}
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || $topic->isDeleted() || $topic->isClosed()) {
|
||||
$this->fail(100, "Topic is deleted, closed or invalid.");
|
||||
}
|
||||
|
||||
$flags = 0;
|
||||
|
||||
if($from_group != 0 && !is_null($topic->getClub()) && $topic->getClub()->canBeModifiedBy($this->user))
|
||||
$flags |= 0b10000000;
|
||||
|
||||
if(strlen($message) > 300) {
|
||||
$this->fail(20, "Comment is too long.");
|
||||
}
|
||||
|
||||
$comment = new Comment;
|
||||
$comment->setOwner($this->getUser()->getId());
|
||||
$comment->setModel(get_class($topic));
|
||||
$comment->setTarget($topic->getId());
|
||||
$comment->setContent($message);
|
||||
$comment->setCreated(time());
|
||||
$comment->setFlags($flags);
|
||||
$comment->save();
|
||||
|
||||
if(!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
$attachmentType = "video";
|
||||
else
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Photo does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Video does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $comment->getId();
|
||||
}
|
||||
|
||||
function deleteComment(int $comment_id, int $group_id = 0, int $topic_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
|
||||
if($comment->isDeleted() || !$comment || !$comment->canBeDeletedBy($this->getUser()))
|
||||
$this->fail(403, "Access to comment denied");
|
||||
|
||||
$comment->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function deleteTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || $topic->isDeleted() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$topic->deleteTopic();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function editComment(int $comment_id, int $group_id = 0, int $topic_id = 0, string $message, string $attachments)
|
||||
{
|
||||
/*
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
|
||||
if($comment->getOwner() != $this->getUser()->getId())
|
||||
$this->fail(15, "Access to comment denied");
|
||||
|
||||
$comment->setContent($message);
|
||||
$comment->setEdited(time());
|
||||
$comment->save();
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
function editTopic(int $group_id, int $topic_id, string $title)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || $topic->isDeleted() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$topic->setTitle(ovk_proc_strtr($title, 127));
|
||||
|
||||
$topic->save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function fixTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$topic->setPinned(1);
|
||||
|
||||
$topic->save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function getComments(int $group_id, int $topic_id, bool $need_likes = false, int $start_comment_id = 0, int $offset = 0, int $count = 40, bool $extended = false, string $sort = "asc")
|
||||
{
|
||||
# start_comment_id ne robit
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || $topic->isDeleted()) {
|
||||
$this->fail(5, "Invalid topic");
|
||||
}
|
||||
|
||||
$arr = [
|
||||
"items" => []
|
||||
];
|
||||
|
||||
$comms = array_slice(iterator_to_array($topic->getComments(1, $count + $offset)), $offset);
|
||||
foreach($comms as $comm) {
|
||||
$arr["items"][] = $this->getApiBoardComment($comm, $need_likes);
|
||||
|
||||
if($extended) {
|
||||
if($comm->getOwner() instanceof \openvk\Web\Models\Entities\User) {
|
||||
$arr["profiles"][] = $comm->getOwner()->toVkApiStruct();
|
||||
}
|
||||
|
||||
if($comm->getOwner() instanceof \openvk\Web\Models\Entities\Club) {
|
||||
$arr["groups"][] = $comm->getOwner()->toVkApiStruct();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
function getTopics(int $group_id, string $topic_ids = "", int $order = 1, int $offset = 0, int $count = 40, bool $extended = false, int $preview = 0, int $preview_length = 90)
|
||||
{
|
||||
# order и extended ничё не делают
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$arr = [];
|
||||
$club = (new ClubsRepo)->get($group_id);
|
||||
|
||||
$topics = array_slice(iterator_to_array((new TopicsRepo)->getClubTopics($club, 1, $count + $offset)), $offset);
|
||||
$arr["count"] = (new TopicsRepo)->getClubTopicsCount($club);
|
||||
$arr["items"] = [];
|
||||
$arr["default_order"] = $order;
|
||||
$arr["can_add_topics"] = $club->canBeModifiedBy($this->getUser()) ? true : $club->isEveryoneCanCreateTopics() ? true : false;
|
||||
$arr["profiles"] = [];
|
||||
|
||||
if(empty($topic_ids)) {
|
||||
foreach($topics as $topic) {
|
||||
if($topic->isDeleted()) continue;
|
||||
$arr["items"][] = $topic->toVkApiStruct($preview, $preview_length > 1 ? $preview_length : 90);
|
||||
}
|
||||
} else {
|
||||
$topics = explode(',', $topic_ids);
|
||||
|
||||
foreach($topics as $topic) {
|
||||
$id = explode("_", $topic);
|
||||
$topicy = (new TopicsRepo)->getTopicById((int)$id[0], (int)$id[1]);
|
||||
|
||||
if($topicy && !$topicy->isDeleted()) {
|
||||
$arr["items"][] = $topicy->toVkApiStruct($preview, $preview_length > 1 ? $preview_length : 90);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
function openTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || !$topic->isDeleted() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if($topic->isClosed()) {
|
||||
$topic->setClosed(0);
|
||||
$topic->save();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function restoreComment(int $group_id, int $topic_id, int $comment_id)
|
||||
{
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
function unfixTopic(int $group_id, int $topic_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$topic = (new TopicsRepo)->getTopicById($group_id, $topic_id);
|
||||
|
||||
if(!$topic || !$topic->getClub() || !$topic->getClub()->canBeModifiedBy($this->getUser())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if($topic->isPinned()) {
|
||||
$topic->setClosed(0);
|
||||
$topic->save();
|
||||
}
|
||||
|
||||
$topic->setPinned(0);
|
||||
|
||||
$topic->save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private function getApiBoardComment(?Comment $comment, bool $need_likes = false)
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $comment->getId();
|
||||
$res->from_id = $comment->getOwner()->getId();
|
||||
$res->date = $comment->getPublicationTime()->timestamp();
|
||||
$res->text = $comment->getText(false);
|
||||
$res->attachments = [];
|
||||
$res->likes = [];
|
||||
if($need_likes) {
|
||||
$res->likes = [
|
||||
"count" => $comment->getLikesCount(),
|
||||
"user_likes" => (int) $comment->hasLikeFrom($this->getUser()),
|
||||
"can_like" => 1 # а чё типо не может ахахаххахах
|
||||
];
|
||||
}
|
||||
|
||||
foreach($comment->getChildren() as $attachment) {
|
||||
if($attachment->isDeleted())
|
||||
continue;
|
||||
|
||||
$res->attachments[] = $attachment->toVkApiStruct();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
174
VKAPI/Handlers/Gifts.php
Normal file
174
VKAPI/Handlers/Gifts.php
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\Gifts as GiftsRepo;
|
||||
use openvk\Web\Models\Entities\Notifications\GiftNotification;
|
||||
|
||||
final class Gifts extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $user_id, int $count = 10, int $offset = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$i = 0;
|
||||
|
||||
$i += $offset;
|
||||
|
||||
$user = (new UsersRepo)->get($user_id);
|
||||
|
||||
if(!$user || $user->isDeleted())
|
||||
$this->fail(177, "Invalid user");
|
||||
|
||||
$gift_item = [];
|
||||
|
||||
$userGifts = array_slice(iterator_to_array($user->getGifts(1, $count, false)), $offset);
|
||||
|
||||
if(sizeof($userGifts) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
foreach($userGifts as $gift) {
|
||||
if($i < $count) {
|
||||
$gift_item[] = [
|
||||
"id" => $i,
|
||||
"from_id" => $gift->anon == true ? 0 : $gift->sender->getId(),
|
||||
"message" => $gift->caption == NULL ? "" : $gift->caption,
|
||||
"date" => $gift->sent->timestamp(),
|
||||
"gift" => [
|
||||
"id" => $gift->gift->getId(),
|
||||
"thumb_256" => $gift->gift->getImage(2),
|
||||
"thumb_96" => $gift->gift->getImage(2),
|
||||
"thumb_48" => $gift->gift->getImage(2)
|
||||
],
|
||||
"privacy" => 0
|
||||
];
|
||||
}
|
||||
$i+=1;
|
||||
}
|
||||
|
||||
return $gift_item;
|
||||
}
|
||||
|
||||
function send(int $user_ids, int $gift_id, string $message = "", int $privacy = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$user = (new UsersRepo)->get((int) $user_ids);
|
||||
|
||||
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
|
||||
$this->fail(105, "Commerce is disabled on this instance");
|
||||
|
||||
if(!$user || $user->isDeleted())
|
||||
$this->fail(177, "Invalid user");
|
||||
|
||||
$gift = (new GiftsRepo)->get($gift_id);
|
||||
|
||||
if(!$gift)
|
||||
$this->fail(165, "Invalid gift");
|
||||
|
||||
$price = $gift->getPrice();
|
||||
$coinsLeft = $this->getUser()->getCoins() - $price;
|
||||
|
||||
if(!$gift->canUse($this->getUser()))
|
||||
return (object)
|
||||
[
|
||||
"success" => 0,
|
||||
"user_ids" => $user_ids,
|
||||
"error" => "You don't have any more of these gifts."
|
||||
];
|
||||
|
||||
if($coinsLeft < 0)
|
||||
return (object)
|
||||
[
|
||||
"success" => 0,
|
||||
"user_ids" => $user_ids,
|
||||
"error" => "You don't have enough voices."
|
||||
];
|
||||
|
||||
$user->gift($this->getUser(), $gift, $message);
|
||||
$gift->used();
|
||||
|
||||
$this->getUser()->setCoins($coinsLeft);
|
||||
$this->getUser()->save();
|
||||
|
||||
$notification = new GiftNotification($user, $this->getUser(), $gift, $message);
|
||||
$notification->emit();
|
||||
|
||||
return (object)
|
||||
[
|
||||
"success" => 1,
|
||||
"user_ids" => $user_ids,
|
||||
"withdraw_votes" => $price
|
||||
];
|
||||
}
|
||||
|
||||
function delete()
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
# этих методов не было в ВК, но я их добавил чтобы можно было отобразить список подарков
|
||||
function getCategories(bool $extended = false, int $page = 1)
|
||||
{
|
||||
$cats = (new GiftsRepo)->getCategories($page);
|
||||
$categ = [];
|
||||
$i = 0;
|
||||
|
||||
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
|
||||
$this->fail(105, "Commerce is disabled on this instance");
|
||||
|
||||
foreach($cats as $cat) {
|
||||
$categ[$i] = [
|
||||
"name" => $cat->getName(),
|
||||
"description" => $cat->getDescription(),
|
||||
"id" => $cat->getId(),
|
||||
"thumbnail" => $cat->getThumbnailURL(),
|
||||
];
|
||||
|
||||
if($extended == true) {
|
||||
$categ[$i]["localizations"] = [];
|
||||
foreach(getLanguages() as $lang) {
|
||||
$code = $lang["code"];
|
||||
$categ[$i]["localizations"][$code] =
|
||||
[
|
||||
"name" => $cat->getName($code),
|
||||
"desc" => $cat->getDescription($code),
|
||||
];
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $categ;
|
||||
}
|
||||
|
||||
function getGiftsInCategory(int $id, int $page = 1)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
if(!OPENVK_ROOT_CONF['openvk']['preferences']['commerce'])
|
||||
$this->fail(105, "Commerce is disabled on this instance");
|
||||
|
||||
if(!(new GiftsRepo)->getCat($id))
|
||||
$this->fail(177, "Category not found");
|
||||
|
||||
$giftz = ((new GiftsRepo)->getCat($id))->getGifts($page);
|
||||
$gifts = [];
|
||||
|
||||
foreach($giftz as $gift) {
|
||||
$gifts[] = [
|
||||
"name" => $gift->getName(),
|
||||
"image" => $gift->getImage(2),
|
||||
"usages_left" => (int)$gift->getUsagesLeft($this->getUser()),
|
||||
"price" => $gift->getPrice(), # голосов
|
||||
"is_free" => $gift->isFree()
|
||||
];
|
||||
}
|
||||
|
||||
return $gifts;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\Web\Models\Repositories\Clubs as ClubsRepo;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Entities\Club;
|
||||
|
||||
final class Groups extends VKAPIRequestHandler
|
||||
{
|
||||
|
@ -263,4 +264,272 @@ final class Groups extends VKAPIRequestHandler
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function create(string $title, string $description = "", string $type = "group", int $public_category = 1, int $public_subcategory = 1, int $subtype = 1)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = new Club;
|
||||
|
||||
$club->setName($title);
|
||||
$club->setAbout($description);
|
||||
$club->setOwner($this->getUser()->getId());
|
||||
$club->save();
|
||||
|
||||
$club->toggleSubscription($this->getUser());
|
||||
|
||||
return $this->getById((string)$club->getId());
|
||||
}
|
||||
|
||||
function edit(
|
||||
int $group_id,
|
||||
string $title = NULL,
|
||||
string $description = NULL,
|
||||
string $screen_name = NULL,
|
||||
string $website = NULL,
|
||||
int $wall = NULL,
|
||||
int $topics = NULL,
|
||||
int $adminlist = NULL,
|
||||
int $topicsAboveWall = NULL,
|
||||
int $hideFromGlobalFeed = NULL)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$club = (new ClubsRepo)->get($group_id);
|
||||
|
||||
if(!$club) $this->fail(203, "Club not found");
|
||||
if(!$club || !$club->canBeModifiedBy($this->getUser())) $this->fail(15, "You can't modify this group.");
|
||||
if(!empty($screen_name) && !$club->setShortcode($screen_name)) $this->fail(103, "Invalid shortcode.");
|
||||
|
||||
!is_null($title) ? $club->setName($title) : NULL;
|
||||
!is_null($description) ? $club->setAbout($description) : NULL;
|
||||
!is_null($screen_name) ? $club->setShortcode($screen_name) : NULL;
|
||||
!is_null($website) ? $club->setWebsite((!parse_url($website, PHP_URL_SCHEME) ? "https://" : "") . $website) : NULL;
|
||||
!is_null($wall) ? $club->setWall($wall) : NULL;
|
||||
!is_null($topics) ? $club->setEveryone_Can_Create_Topics($topics) : NULL;
|
||||
!is_null($adminlist) ? $club->setAdministrators_List_Display($adminlist) : NULL;
|
||||
!is_null($topicsAboveWall) ? $club->setDisplay_Topics_Above_Wall($topicsAboveWall) : NULL;
|
||||
!is_null($hideFromGlobalFeed) ? $club->setHide_From_Global_Feed($hideFromGlobalFeed) : NULL;
|
||||
|
||||
$club->save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function getMembers(string $group_id, string $sort = "id_asc", int $offset = 0, int $count = 100, string $fields = "", string $filter = "any")
|
||||
{
|
||||
# bdate,can_post,can_see_all_posts,can_see_audio,can_write_private_message,city,common_count,connections,contacts,country,domain,education,has_mobile,last_seen,lists,online,online_mobile,photo_100,photo_200,photo_200_orig,photo_400_orig,photo_50,photo_max,photo_max_orig,relation,relatives,schools,sex,site,status,universities
|
||||
$club = (new ClubsRepo)->get((int) $group_id);
|
||||
if(!$club)
|
||||
$this->fail(125, "Invalid group id");
|
||||
|
||||
$sorter = "follower ASC";
|
||||
|
||||
switch($sort) {
|
||||
default:
|
||||
case "time_asc":
|
||||
case "id_asc":
|
||||
$sorter = "follower ASC";
|
||||
break;
|
||||
case "time_desc":
|
||||
case "id_desc":
|
||||
$sorter = "follower DESC";
|
||||
break;
|
||||
}
|
||||
|
||||
$members = array_slice(iterator_to_array($club->getFollowers(1, $count, $sorter)), $offset);
|
||||
$arr = (object) [
|
||||
"count" => count($members),
|
||||
"items" => array()];
|
||||
|
||||
$filds = explode(",", $fields);
|
||||
|
||||
$i = 0;
|
||||
foreach($members as $member) {
|
||||
if($i > $count) {
|
||||
break;
|
||||
}
|
||||
|
||||
$arr->items[] = (object) [
|
||||
"id" => $member->getId(),
|
||||
"first_name" => $member->getFirstName(),
|
||||
"last_name" => $member->getLastName(),
|
||||
];
|
||||
|
||||
foreach($filds as $fild) {
|
||||
switch($fild) {
|
||||
case "bdate":
|
||||
$arr->items[$i]->bdate = $member->getBirthday()->format('%e.%m.%Y');
|
||||
break;
|
||||
case "can_post":
|
||||
$arr->items[$i]->can_post = $club->canBeModifiedBy($member);
|
||||
break;
|
||||
case "can_see_all_posts":
|
||||
$arr->items[$i]->can_see_all_posts = 1;
|
||||
break;
|
||||
case "can_see_audio":
|
||||
$arr->items[$i]->can_see_audio = 0;
|
||||
break;
|
||||
case "can_write_private_message":
|
||||
$arr->items[$i]->can_write_private_message = 0;
|
||||
break;
|
||||
case "common_count":
|
||||
$arr->items[$i]->common_count = 420;
|
||||
break;
|
||||
case "connections":
|
||||
$arr->items[$i]->connections = 1;
|
||||
break;
|
||||
case "contacts":
|
||||
$arr->items[$i]->contacts = $member->getContactEmail();
|
||||
break;
|
||||
case "country":
|
||||
$arr->items[$i]->country = 1;
|
||||
break;
|
||||
case "domain":
|
||||
$arr->items[$i]->domain = "";
|
||||
break;
|
||||
case "education":
|
||||
$arr->items[$i]->education = "";
|
||||
break;
|
||||
case "has_mobile":
|
||||
$arr->items[$i]->has_mobile = false;
|
||||
break;
|
||||
case "last_seen":
|
||||
$arr->items[$i]->last_seen = $member->getOnline()->timestamp();
|
||||
break;
|
||||
case "lists":
|
||||
$arr->items[$i]->lists = "";
|
||||
break;
|
||||
case "online":
|
||||
$arr->items[$i]->online = $member->isOnline();
|
||||
break;
|
||||
case "online_mobile":
|
||||
$arr->items[$i]->online_mobile = $member->getOnlinePlatform() == "android" || $member->getOnlinePlatform() == "iphone" || $member->getOnlinePlatform() == "mobile";
|
||||
break;
|
||||
case "photo_100":
|
||||
$arr->items[$i]->photo_100 = $member->getAvatarURL("tiny");
|
||||
break;
|
||||
case "photo_200":
|
||||
$arr->items[$i]->photo_200 = $member->getAvatarURL("normal");
|
||||
break;
|
||||
case "photo_200_orig":
|
||||
$arr->items[$i]->photo_200_orig = $member->getAvatarURL("normal");
|
||||
break;
|
||||
case "photo_400_orig":
|
||||
$arr->items[$i]->photo_400_orig = $member->getAvatarURL("normal");
|
||||
break;
|
||||
case "photo_max":
|
||||
$arr->items[$i]->photo_max = $member->getAvatarURL("original");
|
||||
break;
|
||||
case "photo_max_orig":
|
||||
$arr->items[$i]->photo_max_orig = $member->getAvatarURL();
|
||||
break;
|
||||
case "relation":
|
||||
$arr->items[$i]->relation = $member->getMaritalStatus();
|
||||
break;
|
||||
case "relatives":
|
||||
$arr->items[$i]->relatives = 0;
|
||||
break;
|
||||
case "schools":
|
||||
$arr->items[$i]->schools = 0;
|
||||
break;
|
||||
case "sex":
|
||||
$arr->items[$i]->sex = $member->isFemale() ? 1 : 2;
|
||||
break;
|
||||
case "site":
|
||||
$arr->items[$i]->site = $member->getWebsite();
|
||||
break;
|
||||
case "status":
|
||||
$arr->items[$i]->status = $member->getStatus();
|
||||
break;
|
||||
case "universities":
|
||||
$arr->items[$i]->universities = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
function getSettings(string $group_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$club = (new ClubsRepo)->get((int)$group_id);
|
||||
|
||||
if(!$club || !$club->canBeModifiedBy($this->getUser()))
|
||||
$this->fail(15, "You can't get settings of this group.");
|
||||
|
||||
$arr = (object) [
|
||||
"title" => $club->getName(),
|
||||
"description" => $club->getDescription() != NULL ? $club->getDescription() : "",
|
||||
"address" => $club->getShortcode(),
|
||||
"wall" => $club->canPost() == true ? 1 : 0,
|
||||
"photos" => 1,
|
||||
"video" => 0,
|
||||
"audio" => 0,
|
||||
"docs" => 0,
|
||||
"topics" => $club->isEveryoneCanCreateTopics() == true ? 1 : 0,
|
||||
"wiki" => 0,
|
||||
"messages" => 0,
|
||||
"obscene_filter" => 0,
|
||||
"obscene_stopwords" => 0,
|
||||
"obscene_words" => "",
|
||||
"access" => 1,
|
||||
"subject" => 1,
|
||||
"subject_list" => [
|
||||
0 => "в",
|
||||
1 => "опенвк",
|
||||
2 => "нет",
|
||||
3 => "категорий",
|
||||
4 => "групп",
|
||||
],
|
||||
"rss" => "/club".$club->getId()."/rss",
|
||||
"website" => $club->getWebsite(),
|
||||
"age_limits" => 0,
|
||||
"market" => [],
|
||||
];
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
function isMember(string $group_id, int $user_id, string $user_ids = "", bool $extended = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$id = $user_id != NULL ? $user_id : explode(",", $user_ids);
|
||||
|
||||
if($group_id < 0)
|
||||
$this->fail(228, "Remove the minus from group_id");
|
||||
|
||||
$club = (new ClubsRepo)->get((int)$group_id);
|
||||
$usver = (new UsersRepo)->get((int)$id);
|
||||
|
||||
if(!$club || $group_id == 0)
|
||||
$this->fail(203, "Invalid club");
|
||||
|
||||
if(!$usver || $usver->isDeleted() || $user_id == 0)
|
||||
$this->fail(30, "Invalid user");
|
||||
|
||||
if($extended == false) {
|
||||
return $club->getSubscriptionStatus($usver) ? 1 : 0;
|
||||
} else {
|
||||
return (object)
|
||||
[
|
||||
"member" => $club->getSubscriptionStatus($usver) ? 1 : 0,
|
||||
"request" => 0,
|
||||
"invitation" => 0,
|
||||
"can_invite" => 0,
|
||||
"can_recall" => 0
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
function remove(int $group_id, int $user_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,11 +54,7 @@ final class Likes extends VKAPIRequestHandler
|
|||
case "post":
|
||||
$user = (new UsersRepo)->get($user_id);
|
||||
if (is_null($user))
|
||||
return (object) [
|
||||
"liked" => 0,
|
||||
"copied" => 0,
|
||||
"sex" => 0
|
||||
];
|
||||
$this->fail(100, "One of the parameters specified was missing or invalid: user not found");
|
||||
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $item_id);
|
||||
if (is_null($post))
|
||||
|
|
|
@ -7,7 +7,7 @@ use openvk\VKAPI\Handlers\Wall;
|
|||
|
||||
final class Newsfeed extends VKAPIRequestHandler
|
||||
{
|
||||
function get(string $fields = "", int $start_from = 0, int $offset = 0, int $count = 30, int $extended = 0, int $forGodSakePleaseDoNotReportAboutMyOnlineActivity = 0)
|
||||
function get(string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0, int $forGodSakePleaseDoNotReportAboutMyOnlineActivity = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -33,6 +33,8 @@ final class Newsfeed extends VKAPIRequestHandler
|
|||
->where("wall IN (?)", $ids)
|
||||
->where("deleted", 0)
|
||||
->where("id < (?)", empty($start_from) ? PHP_INT_MAX : $start_from)
|
||||
->where("? <= created", empty($start_time) ? 0 : $start_time)
|
||||
->where("? >= created", empty($end_time) ? PHP_INT_MAX : $end_time)
|
||||
->order("created DESC");
|
||||
|
||||
$rposts = [];
|
||||
|
@ -45,7 +47,7 @@ final class Newsfeed extends VKAPIRequestHandler
|
|||
return $response;
|
||||
}
|
||||
|
||||
function getGlobal(string $fields = "", int $start_from = 0, int $offset = 0, int $count = 30, int $extended = 0)
|
||||
function getGlobal(string $fields = "", int $start_from = 0, int $start_time = 0, int $end_time = 0, int $offset = 0, int $count = 30, int $extended = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -55,7 +57,9 @@ final class Newsfeed extends VKAPIRequestHandler
|
|||
$queryBase .= " AND `nsfw` = 0";
|
||||
|
||||
$start_from = empty($start_from) ? PHP_INT_MAX : $start_from;
|
||||
$posts = DatabaseConnection::i()->getConnection()->query("SELECT `posts`.`id` " . $queryBase . " AND `posts`.`id` < " . $start_from . " ORDER BY `created` DESC LIMIT " . $count . " OFFSET " . $offset);
|
||||
$start_time = empty($start_time) ? 0 : $start_time;
|
||||
$end_time = empty($end_time) ? PHP_INT_MAX : $end_time;
|
||||
$posts = DatabaseConnection::i()->getConnection()->query("SELECT `posts`.`id` " . $queryBase . " AND `posts`.`id` <= " . $start_from . " AND " . $start_time . " <= `posts`.`created` AND `posts`.`created` <= " . $end_time . " ORDER BY `created` DESC LIMIT " . $count . " OFFSET " . $offset);
|
||||
|
||||
$rposts = [];
|
||||
$ids = [];
|
||||
|
|
283
VKAPI/Handlers/Notes.php
Normal file
283
VKAPI/Handlers/Notes.php
Normal file
|
@ -0,0 +1,283 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\Web\Models\Repositories\Notes as NotesRepo;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
||||
use openvk\Web\Models\Repositories\Photos as PhotosRepo;
|
||||
use openvk\Web\Models\Repositories\Videos as VideosRepo;
|
||||
use openvk\Web\Models\Entities\{Note, Comment};
|
||||
|
||||
final class Notes extends VKAPIRequestHandler
|
||||
{
|
||||
function add(string $title, string $text, int $privacy = 0, int $comment_privacy = 0, string $privacy_view = "", string $privacy_comment = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$note = new Note;
|
||||
$note->setOwner($this->getUser()->getId());
|
||||
$note->setCreated(time());
|
||||
$note->setName($title);
|
||||
$note->setSource($text);
|
||||
$note->setEdited(time());
|
||||
$note->save();
|
||||
|
||||
return $note->getVirtualId();
|
||||
}
|
||||
|
||||
function createComment(string $note_id, int $owner_id, string $message, int $reply_to = 0, string $attachments = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
$note = (new NotesRepo)->getNoteById((int)$owner_id, (int)$note_id);
|
||||
|
||||
if(!$note)
|
||||
$this->fail(180, "Note not found");
|
||||
|
||||
if($note->isDeleted())
|
||||
$this->fail(189, "Note is deleted");
|
||||
|
||||
if($note->getOwner()->isDeleted())
|
||||
$this->fail(403, "Owner is deleted");
|
||||
|
||||
if(!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser()))
|
||||
$this->fail(43, "No access");
|
||||
|
||||
if(empty($message) && empty($attachments))
|
||||
$this->fail(100, "Required parameter 'message' missing.");
|
||||
|
||||
$comment = new Comment;
|
||||
$comment->setOwner($this->getUser()->getId());
|
||||
$comment->setModel(get_class($note));
|
||||
$comment->setTarget($note->getId());
|
||||
$comment->setContent($message);
|
||||
$comment->setCreated(time());
|
||||
$comment->save();
|
||||
|
||||
if(!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
$attachmentType = "video";
|
||||
else
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Photo does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Video does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $comment->getId();
|
||||
}
|
||||
|
||||
function delete(string $note_id)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$note = (new NotesRepo)->get((int)$note_id);
|
||||
|
||||
if(!$note)
|
||||
$this->fail(180, "Note not found");
|
||||
|
||||
if(!$note->canBeModifiedBy($this->getUser()))
|
||||
$this->fail(15, "Access to note denied");
|
||||
|
||||
$note->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function deleteComment(int $comment_id, int $owner_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
|
||||
if(!$comment || !$comment->canBeDeletedBy($this->getUser()))
|
||||
$this->fail(403, "Access to comment denied");
|
||||
|
||||
$comment->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function edit(string $note_id, string $title = "", string $text = "", int $privacy = 0, int $comment_privacy = 0, string $privacy_view = "", string $privacy_comment = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$note = (new NotesRepo)->getNoteById($this->getUser()->getId(), (int)$note_id);
|
||||
|
||||
if(!$note)
|
||||
$this->fail(180, "Note not found");
|
||||
|
||||
if($note->isDeleted())
|
||||
$this->fail(189, "Note is deleted");
|
||||
|
||||
if(!$note->canBeModifiedBy($this->getUser()))
|
||||
$this->fail(403, "No access");
|
||||
|
||||
!empty($title) ? $note->setName($title) : NULL;
|
||||
!empty($text) ? $note->setSource($text) : NULL;
|
||||
|
||||
$note->setCached_Content(NULL);
|
||||
$note->setEdited(time());
|
||||
$note->save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function editComment(int $comment_id, string $message, int $owner_id = NULL)
|
||||
{
|
||||
/*
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
|
||||
if($comment->getOwner() != $this->getUser()->getId())
|
||||
$this->fail(15, "Access to comment denied");
|
||||
|
||||
$comment->setContent($message);
|
||||
$comment->setEdited(time());
|
||||
$comment->save();
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function get(int $user_id, string $note_ids = "", int $offset = 0, int $count = 10, int $sort = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$user = (new UsersRepo)->get($user_id);
|
||||
|
||||
if(!$user || $user->isDeleted())
|
||||
$this->fail(15, "Invalid user");
|
||||
|
||||
if(!$user->getPrivacyPermission('notes.read', $this->getUser()))
|
||||
$this->fail(43, "Access denied: this user chose to hide his notes");
|
||||
|
||||
if(empty($note_ids)) {
|
||||
$notes = array_slice(iterator_to_array((new NotesRepo)->getUserNotes($user, 1, $count + $offset, $sort == 0 ? "ASC" : "DESC")), $offset);
|
||||
$nodez = (object) [
|
||||
"count" => (new NotesRepo)->getUserNotesCount((new UsersRepo)->get($user_id)),
|
||||
"notes" => []
|
||||
];
|
||||
|
||||
foreach($notes as $note) {
|
||||
if($note->isDeleted()) continue;
|
||||
|
||||
$nodez->notes[] = $note->toVkApiStruct();
|
||||
}
|
||||
} else {
|
||||
$notes = explode(',', $note_ids);
|
||||
|
||||
foreach($notes as $note)
|
||||
{
|
||||
$id = explode("_", $note);
|
||||
|
||||
$items = [];
|
||||
|
||||
$note = (new NotesRepo)->getNoteById((int)$id[0], (int)$id[1]);
|
||||
if($note && !$note->isDeleted()) {
|
||||
$nodez->notes[] = $note->toVkApiStruct();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $nodez;
|
||||
}
|
||||
|
||||
function getById(int $note_id, int $owner_id, bool $need_wiki = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$note = (new NotesRepo)->getNoteById($owner_id, $note_id);
|
||||
|
||||
if(!$note)
|
||||
$this->fail(180, "Note not found");
|
||||
|
||||
if($note->isDeleted())
|
||||
$this->fail(189, "Note is deleted");
|
||||
|
||||
if(!$note->getOwner() || $note->getOwner()->isDeleted())
|
||||
$this->fail(177, "Owner does not exists");
|
||||
|
||||
if(!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser()))
|
||||
$this->fail(40, "Access denied: this user chose to hide his notes");
|
||||
|
||||
return $note->toVkApiStruct();
|
||||
}
|
||||
|
||||
function getComments(int $note_id, int $owner_id, int $sort = 1, int $offset = 0, int $count = 100)
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
$note = (new NotesRepo)->getNoteById($owner_id, $note_id);
|
||||
|
||||
if(!$note)
|
||||
$this->fail(180, "Note not found");
|
||||
|
||||
if($note->isDeleted())
|
||||
$this->fail(189, "Note is deleted");
|
||||
|
||||
if(!$note->getOwner())
|
||||
$this->fail(177, "Owner does not exists");
|
||||
|
||||
if(!$note->getOwner()->getPrivacyPermission('notes.read', $this->getUser()))
|
||||
$this->fail(14, "No access");
|
||||
|
||||
$arr = (object) [
|
||||
"count" => $note->getCommentsCount(),
|
||||
"comments" => []];
|
||||
$comments = array_slice(iterator_to_array($note->getComments(1, $count + $offset)), $offset);
|
||||
|
||||
foreach($comments as $comment) {
|
||||
$arr->comments[] = $comment->toVkApiStruct($this->getUser(), false, false, $note);
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
function getFriendsNotes(int $offset = 0, int $count = 0)
|
||||
{
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
function restoreComment(int $comment_id = 0, int $owner_id = 0)
|
||||
{
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
}
|
|
@ -3,9 +3,12 @@ namespace openvk\VKAPI\Handlers;
|
|||
|
||||
use Nette\InvalidStateException;
|
||||
use Nette\Utils\ImageException;
|
||||
use openvk\Web\Models\Entities\Photo;
|
||||
use openvk\Web\Models\Entities\{Photo, Album, Comment};
|
||||
use openvk\Web\Models\Repositories\Albums;
|
||||
use openvk\Web\Models\Repositories\Photos as PhotosRepo;
|
||||
use openvk\Web\Models\Repositories\Clubs;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
||||
|
||||
final class Photos extends VKAPIRequestHandler
|
||||
{
|
||||
|
@ -58,7 +61,7 @@ final class Photos extends VKAPIRequestHandler
|
|||
}
|
||||
|
||||
return (object) [
|
||||
"upload_url" => $this->getPhotoUploadUrl("photo", isset($club) ? 0 : $club->getId()),
|
||||
"upload_url" => $this->getPhotoUploadUrl("photo", !isset($club) ? 0 : $club->getId()),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -227,4 +230,504 @@ final class Photos extends VKAPIRequestHandler
|
|||
"items" => $images,
|
||||
];
|
||||
}
|
||||
|
||||
function createAlbum(string $title, int $group_id = 0, string $description = "", int $privacy = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($group_id != 0) {
|
||||
$club = (new Clubs)->get((int) $group_id);
|
||||
|
||||
if(!$club || !$club->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(20, "Invalid club");
|
||||
}
|
||||
}
|
||||
|
||||
$album = new Album;
|
||||
$album->setOwner(isset($club) ? $club->getId() * -1 : $this->getUser()->getId());
|
||||
$album->setName($title);
|
||||
$album->setDescription($description);
|
||||
$album->setCreated(time());
|
||||
$album->save();
|
||||
|
||||
return $album->toVkApiStruct($this->getUser());
|
||||
}
|
||||
|
||||
function editAlbum(int $album_id, int $owner_id, string $title, string $description = "", int $privacy = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Albums)->getAlbumByOwnerAndId($owner_id, $album_id);
|
||||
|
||||
if(!$album || $album->isDeleted()) {
|
||||
$this->fail(2, "Invalid album");
|
||||
}
|
||||
|
||||
if(empty($title)) {
|
||||
$this->fail(25, "Title is empty");
|
||||
}
|
||||
|
||||
if($album->isCreatedBySystem()) {
|
||||
$this->fail(40, "You can't change system album");
|
||||
}
|
||||
|
||||
if(!$album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(2, "Access to album denied");
|
||||
}
|
||||
|
||||
$album->setName($title);
|
||||
$album->setDescription($description);
|
||||
|
||||
$album->save();
|
||||
|
||||
return $album->toVkApiStruct($this->getUser());
|
||||
}
|
||||
|
||||
function getAlbums(int $owner_id, string $album_ids = "", int $offset = 0, int $count = 100, bool $need_system = true, bool $need_covers = true, bool $photo_sizes = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$res = [];
|
||||
|
||||
if(empty($album_ids)) {
|
||||
if($owner_id > 0) {
|
||||
$user = (new UsersRepo)->get($owner_id);
|
||||
|
||||
$res = [
|
||||
"count" => (new Albums)->getUserAlbumsCount($user),
|
||||
"items" => []
|
||||
];
|
||||
|
||||
if(!$user || $user->isDeleted())
|
||||
$this->fail(2, "Invalid user");
|
||||
|
||||
|
||||
if(!$user->getPrivacyPermission('photos.read', $this->getUser()))
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
|
||||
$albums = array_slice(iterator_to_array((new Albums)->getUserAlbums($user, 1, $count + $offset)), $offset);
|
||||
|
||||
foreach($albums as $album) {
|
||||
if(!$need_system && $album->isCreatedBySystem()) continue;
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
$club = (new Clubs)->get($owner_id * -1);
|
||||
|
||||
$res = [
|
||||
"count" => (new Albums)->getClubAlbumsCount($club),
|
||||
"items" => []
|
||||
];
|
||||
|
||||
if(!$club)
|
||||
$this->fail(2, "Invalid club");
|
||||
|
||||
$albums = array_slice(iterator_to_array((new Albums)->getClubAlbums($club, 1, $count + $offset)), $offset);
|
||||
|
||||
foreach($albums as $album) {
|
||||
if(!$need_system && $album->isCreatedBySystem()) continue;
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$albums = explode(',', $album_ids);
|
||||
|
||||
$res = [
|
||||
"count" => sizeof($albums),
|
||||
"items" => []
|
||||
];
|
||||
|
||||
foreach($albums as $album)
|
||||
{
|
||||
$id = explode("_", $album);
|
||||
|
||||
$album = (new Albums)->getAlbumByOwnerAndId((int)$id[0], (int)$id[1]);
|
||||
if($album && !$album->isDeleted()) {
|
||||
if(!$need_system && $album->isCreatedBySystem()) continue;
|
||||
$res["items"][] = $album->toVkApiStruct($this->getUser(), $need_covers, $photo_sizes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function getAlbumsCount(int $user_id = 0, int $group_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($user_id == 0 && $group_id == 0 || $user_id > 0 && $group_id > 0) {
|
||||
$this->fail(21, "Select user_id or group_id");
|
||||
}
|
||||
|
||||
if($user_id > 0) {
|
||||
|
||||
$us = (new UsersRepo)->get($user_id);
|
||||
if(!$us || $us->isDeleted()) {
|
||||
$this->fail(21, "Invalid user");
|
||||
}
|
||||
|
||||
if(!$us->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
}
|
||||
|
||||
return (new Albums)->getUserAlbumsCount($us);
|
||||
}
|
||||
|
||||
if($group_id > 0)
|
||||
{
|
||||
$cl = (new Clubs)->get($group_id);
|
||||
if(!$cl) {
|
||||
$this->fail(21, "Invalid club");
|
||||
}
|
||||
|
||||
return (new Albums)->getClubAlbumsCount($cl);
|
||||
}
|
||||
}
|
||||
|
||||
function getById(string $photos, bool $extended = false, bool $photo_sizes = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$phts = explode(",", $photos);
|
||||
$res = [];
|
||||
|
||||
foreach($phts as $phota) {
|
||||
$ph = explode("_", $phota);
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID((int)$ph[0], (int)$ph[1]);
|
||||
|
||||
if(!$photo || $photo->isDeleted()) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if($photo->getOwner()->isDeleted()) {
|
||||
$this->fail(21, "Owner of this photo is deleted");
|
||||
}
|
||||
|
||||
if(!$photo->getOwner()->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his photos.");
|
||||
}
|
||||
|
||||
$res[] = $photo->toVkApiStruct($photo_sizes, $extended);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function get(int $owner_id, int $album_id, string $photo_ids = "", bool $extended = false, bool $photo_sizes = false, int $offset = 0, int $count = 10)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$res = [];
|
||||
|
||||
if(empty($photo_ids)) {
|
||||
$album = (new Albums)->getAlbumByOwnerAndId($owner_id, $album_id);
|
||||
|
||||
if(!$album->getOwner()->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
}
|
||||
|
||||
if(!$album || $album->isDeleted()) {
|
||||
$this->fail(21, "Invalid album");
|
||||
}
|
||||
|
||||
$photos = array_slice(iterator_to_array($album->getPhotos(1, $count + $offset)), $offset);
|
||||
$res["count"] = sizeof($photos);
|
||||
|
||||
foreach($photos as $photo) {
|
||||
if(!$photo || $photo->isDeleted()) continue;
|
||||
$res["items"][] = $photo->toVkApiStruct($photo_sizes, $extended);
|
||||
}
|
||||
|
||||
} else {
|
||||
$photos = explode(',', $photo_ids);
|
||||
|
||||
$res = [
|
||||
"count" => sizeof($photos),
|
||||
"items" => []
|
||||
];
|
||||
|
||||
foreach($photos as $photo)
|
||||
{
|
||||
$id = explode("_", $photo);
|
||||
|
||||
$phot = (new PhotosRepo)->getByOwnerAndVID((int)$id[0], (int)$id[1]);
|
||||
if($phot && !$phot->isDeleted()) {
|
||||
$res["items"][] = $phot->toVkApiStruct($photo_sizes, $extended);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function deleteAlbum(int $album_id, int $group_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$album = (new Albums)->get($album_id);
|
||||
|
||||
if(!$album || $album->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(21, "Invalid album");
|
||||
}
|
||||
|
||||
if($album->isDeleted()) {
|
||||
$this->fail(22, "Album already deleted");
|
||||
}
|
||||
|
||||
$album->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function edit(int $owner_id, int $photo_id, string $caption = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $photo_id);
|
||||
|
||||
if(!$photo) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if($photo->isDeleted()) {
|
||||
$this->fail(21, "Photo is deleted");
|
||||
}
|
||||
|
||||
if(!empty($caption)) {
|
||||
$photo->setDescription($caption);
|
||||
$photo->save();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function delete(int $owner_id, int $photo_id, string $photos = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if(empty($photos)) {
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $photo_id);
|
||||
|
||||
if($this->getUser()->getId() !== $photo->getOwner()->getId()) {
|
||||
$this->fail(21, "You can't delete another's photo");
|
||||
}
|
||||
|
||||
if(!$photo) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if($photo->isDeleted()) {
|
||||
$this->fail(21, "Photo already deleted");
|
||||
}
|
||||
|
||||
$photo->delete();
|
||||
} else {
|
||||
$photozs = explode(',', $photos);
|
||||
|
||||
foreach($photozs as $photo)
|
||||
{
|
||||
$id = explode("_", $photo);
|
||||
|
||||
$phot = (new PhotosRepo)->getByOwnerAndVID((int)$id[0], (int)$id[1]);
|
||||
|
||||
if($this->getUser()->getId() !== $phot->getOwner()->getId()) {
|
||||
$this->fail(21, "You can't delete another's photo");
|
||||
}
|
||||
|
||||
if(!$phot) {
|
||||
$this->fail(21, "Invalid photo");
|
||||
}
|
||||
|
||||
if($phot->isDeleted()) {
|
||||
$this->fail(21, "Photo already deleted");
|
||||
}
|
||||
|
||||
$phot->delete();
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function getAllComments(int $owner_id, int $album_id, bool $need_likes = false, int $offset = 0, int $count = 100)
|
||||
{
|
||||
$this->fail(501, "Not implemented");
|
||||
}
|
||||
|
||||
function deleteComment(int $comment_id, int $owner_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id);
|
||||
if(!$comment) {
|
||||
$this->fail(21, "Invalid comment");
|
||||
}
|
||||
|
||||
if(!$comment->canBeModifiedBy($this->getUser())) {
|
||||
$this->fail(21, "Forbidden");
|
||||
}
|
||||
|
||||
if($comment->isDeleted()) {
|
||||
$this->fail(4, "Comment already deleted");
|
||||
}
|
||||
|
||||
$comment->delete();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
function createComment(int $owner_id, int $photo_id, string $message = "", string $attachments = "", bool $from_group = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if(empty($message) && empty($attachments)) {
|
||||
$this->fail(100, "Required parameter 'message' missing.");
|
||||
}
|
||||
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $photo_id);
|
||||
|
||||
if(!$photo->getAlbum()->getOwner()->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
}
|
||||
|
||||
if(!$photo)
|
||||
$this->fail(180, "Photo not found");
|
||||
if($photo->isDeleted())
|
||||
$this->fail(189, "Photo is deleted");
|
||||
|
||||
$comment = new Comment;
|
||||
$comment->setOwner($this->getUser()->getId());
|
||||
$comment->setModel(get_class($photo));
|
||||
$comment->setTarget($photo->getId());
|
||||
$comment->setContent($message);
|
||||
$comment->setCreated(time());
|
||||
$comment->save();
|
||||
|
||||
if(!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
$attachmentType = "video";
|
||||
else
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Photo does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
$this->fail(43, "You do not have access to this photo");
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Video does not exists");
|
||||
if($attacc->getOwner()->getId() != $this->getUser()->getId())
|
||||
$this->fail(43, "You do not have access to this video");
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $comment->getId();
|
||||
}
|
||||
|
||||
function getAll(int $owner_id, bool $extended = false, int $offset = 0, int $count = 100, bool $photo_sizes = false)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($owner_id < 0) {
|
||||
$this->fail(4, "This method doesn't works with clubs");
|
||||
}
|
||||
|
||||
$user = (new UsersRepo)->get($owner_id);
|
||||
|
||||
if(!$user) {
|
||||
$this->fail(4, "Invalid user");
|
||||
}
|
||||
|
||||
if(!$user->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his albums.");
|
||||
}
|
||||
|
||||
$photos = array_slice(iterator_to_array((new PhotosRepo)->getEveryUserPhoto($user, 1, $count + $offset)), $offset);
|
||||
$res = [];
|
||||
|
||||
foreach($photos as $photo) {
|
||||
if(!$photo || $photo->isDeleted()) continue;
|
||||
$res["items"][] = $photo->toVkApiStruct($photo_sizes, $extended);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function getComments(int $owner_id, int $photo_id, bool $need_likes = false, int $offset = 0, int $count = 100, bool $extended = false, string $fields = "")
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$photo = (new PhotosRepo)->getByOwnerAndVID($owner_id, $photo_id);
|
||||
$comms = array_slice(iterator_to_array($photo->getComments(1, $offset + $count)), $offset);
|
||||
|
||||
if(!$photo) {
|
||||
$this->fail(4, "Invalid photo");
|
||||
}
|
||||
|
||||
if(!$photo->getAlbum()->getOwner()->getPrivacyPermission('photos.read', $this->getUser())) {
|
||||
$this->fail(21, "This user chose to hide his photos.");
|
||||
}
|
||||
|
||||
if($photo->isDeleted()) {
|
||||
$this->fail(4, "Photo is deleted");
|
||||
}
|
||||
|
||||
$res = [
|
||||
"count" => sizeof($comms),
|
||||
"items" => []
|
||||
];
|
||||
|
||||
foreach($comms as $comment) {
|
||||
$res["items"][] = $comment->toVkApiStruct($this->getUser(), $need_likes, $extended);
|
||||
if($extended) {
|
||||
if($comment->getOwner() instanceof \openvk\Web\Models\Entities\User) {
|
||||
$res["profiles"][] = $comment->getOwner()->toVkApiStruct();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
|
@ -75,7 +75,7 @@ final class Polls extends VKAPIRequestHandler
|
|||
|
||||
try {
|
||||
$poll->vote($this->getUser(), explode(",", $answers_ids));
|
||||
return 0;
|
||||
return 1;
|
||||
} catch(AlreadyVotedException $ex) {
|
||||
return 0;
|
||||
} catch(PollLockedException $ex) {
|
||||
|
@ -97,7 +97,7 @@ final class Polls extends VKAPIRequestHandler
|
|||
|
||||
try {
|
||||
$poll->revokeVote($this->getUser());
|
||||
return 0;
|
||||
return 1;
|
||||
} catch(PollLockedException $ex) {
|
||||
$this->fail(15, "Access denied: Poll is locked or isn't revotable");
|
||||
} catch(InvalidOptionException $ex) {
|
||||
|
|
35
VKAPI/Handlers/Status.php
Normal file
35
VKAPI/Handlers/Status.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\Users as UsersRepo;
|
||||
|
||||
final class Status extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $user_id = 0, int $group_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
if($user_id == 0 && $group_id == 0) {
|
||||
return $this->getUser()->getStatus();
|
||||
} else {
|
||||
if($group_id > 0)
|
||||
$this->fail(501, "Group statuses are not implemented");
|
||||
else
|
||||
return (new UsersRepo)->get($user_id)->getStatus();
|
||||
}
|
||||
}
|
||||
|
||||
function set(string $text, int $group_id = 0)
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($group_id > 0) {
|
||||
$this->fail(501, "Group statuses are not implemented");
|
||||
} else {
|
||||
$this->getUser()->setStatus($text);
|
||||
$this->getUser()->save();
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,7 +32,15 @@ final class Users extends VKAPIRequestHandler
|
|||
"first_name" => "DELETED",
|
||||
"last_name" => "",
|
||||
"deactivated" => "deleted"
|
||||
];
|
||||
];
|
||||
} else if($usr->isBanned()) {
|
||||
$response[$i] = (object)[
|
||||
"id" => $usr->getId(),
|
||||
"first_name" => $usr->getFirstName(),
|
||||
"last_name" => $usr->getLastName(),
|
||||
"deactivated" => "banned",
|
||||
"ban_reason" => $usr->getBanReason()
|
||||
];
|
||||
} else if($usrs[$i] == NULL) {
|
||||
|
||||
} else {
|
||||
|
@ -150,7 +158,10 @@ final class Users extends VKAPIRequestHandler
|
|||
break;
|
||||
case "interests":
|
||||
$response[$i]->interests = $usr->getInterests();
|
||||
break;
|
||||
break;
|
||||
case "rating":
|
||||
$response[$i]->rating = $usr->getRating();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,19 +199,94 @@ final class Users extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
function search(string $q, string $fields = "", int $offset = 0, int $count = 100)
|
||||
function search(string $q,
|
||||
string $fields = "",
|
||||
int $offset = 0,
|
||||
int $count = 100,
|
||||
string $city = "",
|
||||
string $hometown = "",
|
||||
int $sex = 2,
|
||||
int $status = 0, # это про marital status
|
||||
bool $online = false,
|
||||
# дальше идут параметры которых нету в vkapi но есть на сайте
|
||||
string $profileStatus = "", # а это уже нормальный статус
|
||||
int $sort = 0,
|
||||
int $before = 0,
|
||||
int $politViews = 0,
|
||||
int $after = 0,
|
||||
string $interests = "",
|
||||
string $fav_music = "",
|
||||
string $fav_films = "",
|
||||
string $fav_shows = "",
|
||||
string $fav_books = "",
|
||||
string $fav_quotes = ""
|
||||
)
|
||||
{
|
||||
$users = new UsersRepo;
|
||||
|
||||
$sortg = "id ASC";
|
||||
|
||||
$nfilds = $fields;
|
||||
|
||||
switch($sort) {
|
||||
case 0:
|
||||
$sortg = "id DESC";
|
||||
break;
|
||||
case 1:
|
||||
$sortg = "id ASC";
|
||||
break;
|
||||
case 2:
|
||||
$sortg = "first_name DESC";
|
||||
break;
|
||||
case 3:
|
||||
$sortg = "first_name ASC";
|
||||
break;
|
||||
case 4:
|
||||
$sortg = "rating DESC";
|
||||
|
||||
if(!str_contains($nfilds, "rating")) {
|
||||
$nfilds .= "rating";
|
||||
}
|
||||
|
||||
break;
|
||||
case 5:
|
||||
$sortg = "rating DESC";
|
||||
|
||||
if(!str_contains($nfilds, "rating")) {
|
||||
$nfilds .= "rating";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$array = [];
|
||||
$find = $users->find($q);
|
||||
|
||||
$parameters = [
|
||||
"city" => !empty($city) ? $city : NULL,
|
||||
"hometown" => !empty($hometown) ? $hometown : NULL,
|
||||
"gender" => $sex < 2 ? $sex : NULL,
|
||||
"maritalstatus" => (bool)$status ? $status : NULL,
|
||||
"politViews" => (bool)$politViews ? $politViews : NULL,
|
||||
"is_online" => $online ? 1 : NULL,
|
||||
"status" => !empty($profileStatus) ? $profileStatus : NULL,
|
||||
"before" => $before != 0 ? $before : NULL,
|
||||
"after" => $after != 0 ? $after : NULL,
|
||||
"interests" => !empty($interests) ? $interests : NULL,
|
||||
"fav_music" => !empty($fav_music) ? $fav_music : NULL,
|
||||
"fav_films" => !empty($fav_films) ? $fav_films : NULL,
|
||||
"fav_shows" => !empty($fav_shows) ? $fav_shows : NULL,
|
||||
"fav_books" => !empty($fav_books) ? $fav_books : NULL,
|
||||
"fav_quotes" => !empty($fav_quotes) ? $fav_quotes : NULL,
|
||||
];
|
||||
|
||||
$find = $users->find($q, $parameters, $sortg);
|
||||
|
||||
foreach ($find as $user)
|
||||
$array[] = $user->getId();
|
||||
|
||||
return (object) [
|
||||
"count" => $find->size(),
|
||||
"items" => $this->get(implode(',', $array), $fields, $offset, $count)
|
||||
"items" => $this->get(implode(',', $array), $nfilds, $offset, $count)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\VKAPI\Handlers;
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs};
|
||||
|
||||
final class Utils extends VKAPIRequestHandler
|
||||
{
|
||||
|
@ -7,4 +8,39 @@ final class Utils extends VKAPIRequestHandler
|
|||
{
|
||||
return time();
|
||||
}
|
||||
|
||||
function resolveScreenName(string $screen_name): object
|
||||
{
|
||||
if(\Chandler\MVC\Routing\Router::i()->getMatchingRoute("/$screen_name")[0]->presenter !== "UnknownTextRouteStrategy") {
|
||||
if(substr($screen_name, 0, strlen("id")) === "id") {
|
||||
return (object) [
|
||||
"object_id" => (int) substr($screen_name, strlen("id")),
|
||||
"type" => "user"
|
||||
];
|
||||
} else if(substr($screen_name, 0, strlen("club")) === "club") {
|
||||
return (object) [
|
||||
"object_id" => (int) substr($screen_name, strlen("club")),
|
||||
"type" => "group"
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$user = (new Users)->getByShortURL($screen_name);
|
||||
if($user) {
|
||||
return (object) [
|
||||
"object_id" => $user->getId(),
|
||||
"type" => "user"
|
||||
];
|
||||
}
|
||||
|
||||
$club = (new Clubs)->getByShortURL($screen_name);
|
||||
if($club) {
|
||||
return (object) [
|
||||
"object_id" => $club->getId(),
|
||||
"type" => "group"
|
||||
];
|
||||
}
|
||||
|
||||
return (object) [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,19 @@ use openvk\Web\Models\Entities\Post;
|
|||
use openvk\Web\Models\Repositories\Posts as PostsRepo;
|
||||
use openvk\Web\Models\Entities\Comment;
|
||||
use openvk\Web\Models\Repositories\Comments as CommentsRepo;
|
||||
use openvk\Web\Models\Entities\Photo;
|
||||
use openvk\Web\Models\Repositories\Photos as PhotosRepo;
|
||||
use openvk\Web\Models\Entities\Video;
|
||||
use openvk\Web\Models\Repositories\Videos as VideosRepo;
|
||||
use openvk\Web\Models\Entities\Note;
|
||||
use openvk\Web\Models\Repositories\Notes as NotesRepo;
|
||||
|
||||
final class Wall extends VKAPIRequestHandler
|
||||
{
|
||||
function get(int $owner_id, string $domain = "", int $offset = 0, int $count = 30, int $extended = 0): object
|
||||
{
|
||||
$this->requireUser();
|
||||
|
||||
|
||||
$posts = new PostsRepo;
|
||||
|
||||
$items = [];
|
||||
|
@ -44,12 +50,14 @@ final class Wall extends VKAPIRequestHandler
|
|||
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||
if($attachment->isDeleted())
|
||||
continue;
|
||||
|
||||
|
||||
$attachments[] = $this->getApiPhoto($attachment);
|
||||
} else if($attachment instanceof \openvk\Web\Models\Entities\Poll) {
|
||||
$attachments[] = $this->getApiPoll($attachment, $this->getUser());
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Video) {
|
||||
$attachments[] = $attachment->getApiStructure();
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Note) {
|
||||
$attachments[] = $attachment->toVkApiStruct();
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
|
||||
$repostAttachments = [];
|
||||
|
||||
|
@ -57,7 +65,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
if($repostAttachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||
if($repostAttachment->isDeleted())
|
||||
continue;
|
||||
|
||||
|
||||
$repostAttachments[] = $this->getApiPhoto($repostAttachment);
|
||||
/* Рекурсии, сука! Заказывали? */
|
||||
}
|
||||
|
@ -69,7 +77,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
$profiles[] = $attachment->getOwner()->getId();
|
||||
|
||||
$post_source = [];
|
||||
|
||||
|
||||
if($attachment->getPlatform(true) === NULL) {
|
||||
$post_source = (object)["type" => "vk"];
|
||||
} else {
|
||||
|
@ -93,7 +101,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
}
|
||||
|
||||
$post_source = [];
|
||||
|
||||
|
||||
if($post->getPlatform(true) === NULL) {
|
||||
$post_source = (object)["type" => "vk"];
|
||||
} else {
|
||||
|
@ -117,6 +125,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"can_archive" => false, # TODO MAYBE
|
||||
"is_archived" => false,
|
||||
"is_pinned" => $post->isPinned(),
|
||||
"is_explicit" => $post->isExplicit(),
|
||||
"attachments" => $attachments,
|
||||
"post_source" => $post_source,
|
||||
"comments" => (object)[
|
||||
|
@ -134,7 +143,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"user_reposted" => 0
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
if ($from_id > 0)
|
||||
$profiles[] = $from_id;
|
||||
else
|
||||
|
@ -162,7 +171,8 @@ final class Wall extends VKAPIRequestHandler
|
|||
"screen_name" => $user->getShortCode(),
|
||||
"photo_50" => $user->getAvatarUrl(),
|
||||
"photo_100" => $user->getAvatarUrl(),
|
||||
"online" => $user->isOnline()
|
||||
"online" => $user->isOnline(),
|
||||
"verified" => $user->isVerified()
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -177,6 +187,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"photo_50" => $group->getAvatarUrl(),
|
||||
"photo_100" => $group->getAvatarUrl(),
|
||||
"photo_200" => $group->getAvatarUrl(),
|
||||
"verified" => $group->isVerified()
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -209,7 +220,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
foreach($psts as $pst) {
|
||||
$id = explode("_", $pst);
|
||||
$post = (new PostsRepo)->getPostById(intval($id[0]), intval($id[1]));
|
||||
if($post) {
|
||||
if($post && !$post->isDeleted()) {
|
||||
$from_id = get_class($post->getOwner()) == "openvk\Web\Models\Entities\Club" ? $post->getOwner()->getId() * (-1) : $post->getOwner()->getId();
|
||||
$attachments = [];
|
||||
$repost = []; // чел высрал семь сигарет 😳 помянем 🕯
|
||||
|
@ -220,6 +231,8 @@ final class Wall extends VKAPIRequestHandler
|
|||
$attachments[] = $this->getApiPoll($attachment, $user);
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Video) {
|
||||
$attachments[] = $attachment->getApiStructure();
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Note) {
|
||||
$attachments[] = $attachment->toVkApiStruct();
|
||||
} else if ($attachment instanceof \openvk\Web\Models\Entities\Post) {
|
||||
$repostAttachments = [];
|
||||
|
||||
|
@ -227,19 +240,19 @@ final class Wall extends VKAPIRequestHandler
|
|||
if($repostAttachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||
if($attachment->isDeleted())
|
||||
continue;
|
||||
|
||||
|
||||
$repostAttachments[] = $this->getApiPhoto($repostAttachment);
|
||||
/* Рекурсии, сука! Заказывали? */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($attachment->isPostedOnBehalfOfGroup())
|
||||
$groups[] = $attachment->getOwner()->getId();
|
||||
else
|
||||
$profiles[] = $attachment->getOwner()->getId();
|
||||
|
||||
$post_source = [];
|
||||
|
||||
|
||||
if($attachment->getPlatform(true) === NULL) {
|
||||
$post_source = (object)["type" => "vk"];
|
||||
} else {
|
||||
|
@ -287,6 +300,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"can_archive" => false, # TODO MAYBE
|
||||
"is_archived" => false,
|
||||
"is_pinned" => $post->isPinned(),
|
||||
"is_explicit" => $post->isExplicit(),
|
||||
"post_source" => $post_source,
|
||||
"attachments" => $attachments,
|
||||
"comments" => (object)[
|
||||
|
@ -304,7 +318,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"user_reposted" => 0
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
if ($from_id > 0)
|
||||
$profiles[] = $from_id;
|
||||
else
|
||||
|
@ -334,7 +348,8 @@ final class Wall extends VKAPIRequestHandler
|
|||
"screen_name" => $user->getShortCode(),
|
||||
"photo_50" => $user->getAvatarUrl(),
|
||||
"photo_100" => $user->getAvatarUrl(),
|
||||
"online" => $user->isOnline()
|
||||
"online" => $user->isOnline(),
|
||||
"verified" => $user->isVerified()
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -349,6 +364,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"photo_50" => $group->getAvatarUrl(),
|
||||
"photo_100" => $group->getAvatarUrl(),
|
||||
"photo_200" => $group->getAvatarUrl(),
|
||||
"verified" => $group->isVerified()
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -363,13 +379,13 @@ final class Wall extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
function post(string $owner_id, string $message = "", int $from_group = 0, int $signed = 0): object
|
||||
function post(string $owner_id, string $message = "", int $from_group = 0, int $signed = 0, string $attachments = ""): object
|
||||
{
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$owner_id = intval($owner_id);
|
||||
|
||||
|
||||
$wallOwner = ($owner_id > 0 ? (new UsersRepo)->get($owner_id) : (new ClubsRepo)->get($owner_id * -1))
|
||||
?? $this->fail(18, "User was deleted or banned");
|
||||
if($owner_id > 0)
|
||||
|
@ -380,7 +396,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
else
|
||||
$canPost = $wallOwner->canPost();
|
||||
else
|
||||
$canPost = false;
|
||||
$canPost = false;
|
||||
|
||||
if($canPost == false) $this->fail(15, "Access denied");
|
||||
|
||||
|
@ -401,27 +417,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
if($signed == 1)
|
||||
$flags |= 0b01000000;
|
||||
|
||||
# TODO: Compatible implementation of this
|
||||
try {
|
||||
$photo = NULL;
|
||||
$video = NULL;
|
||||
if($_FILES["photo"]["error"] === UPLOAD_ERR_OK) {
|
||||
$album = NULL;
|
||||
if(!$anon && $owner_id > 0 && $owner_id === $this->getUser()->getId())
|
||||
$album = (new AlbumsRepo)->getUserWallAlbum($wallOwner);
|
||||
|
||||
$photo = Photo::fastMake($this->getUser()->getId(), $message, $_FILES["photo"], $album, $anon);
|
||||
}
|
||||
|
||||
if($_FILES["video"]["error"] === UPLOAD_ERR_OK)
|
||||
$video = Video::fastMake($this->getUser()->getId(), $message, $_FILES["video"], $anon);
|
||||
} catch(\DomainException $ex) {
|
||||
$this->fail(-156, "The media file is corrupted");
|
||||
} catch(ISE $ex) {
|
||||
$this->fail(-156, "The media file is corrupted or too large ");
|
||||
}
|
||||
|
||||
if(empty($message) && !$photo && !$video)
|
||||
if(empty($message) && empty($attachments))
|
||||
$this->fail(100, "Required parameter 'message' missing.");
|
||||
|
||||
try {
|
||||
|
@ -437,11 +433,60 @@ final class Wall extends VKAPIRequestHandler
|
|||
$this->fail(100, "One of the parameters specified was missing or invalid");
|
||||
}
|
||||
|
||||
if(!is_null($photo))
|
||||
$post->attach($photo);
|
||||
if(!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
# Аттачи такого вида: [тип][id владельца]_[id вложения]
|
||||
# Пример: photo1_1
|
||||
|
||||
if(!is_null($video))
|
||||
$post->attach($video);
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
$attachmentType = "video";
|
||||
elseif(str_contains($attac, "note"))
|
||||
$attachmentType = "note";
|
||||
else
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Invalid photo");
|
||||
if(!$attacc->getOwner()->getPrivacyPermission('photos.read', $this->getUser()))
|
||||
$this->fail(43, "Access to photo denied");
|
||||
|
||||
$post->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Video does not exists");
|
||||
if(!$attacc->getOwner()->getPrivacyPermission('videos.read', $this->getUser()))
|
||||
$this->fail(43, "Access to video denied");
|
||||
|
||||
$post->attach($attacc);
|
||||
} elseif($attachmentType == "note") {
|
||||
$attacc = (new NotesRepo)->getNoteById($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Note does not exist");
|
||||
if(!$attacc->getOwner()->getPrivacyPermission('notes.read', $this->getUser()))
|
||||
$this->fail(11, "Access to note denied");
|
||||
|
||||
$post->attach($attacc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($wall > 0 && $wall !== $this->user->identity->getId())
|
||||
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
|
||||
|
@ -449,7 +494,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
return (object)["post_id" => $post->getVirtualId()];
|
||||
}
|
||||
|
||||
function repost(string $object, string $message = "") {
|
||||
function repost(string $object, string $message = "", int $group_id = 0) {
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
|
@ -462,14 +507,27 @@ final class Wall extends VKAPIRequestHandler
|
|||
|
||||
$nPost = new Post;
|
||||
$nPost->setOwner($this->user->getId());
|
||||
$nPost->setWall($this->user->getId());
|
||||
|
||||
if($group_id > 0) {
|
||||
$club = (new ClubsRepo)->get($group_id);
|
||||
if(!$club)
|
||||
$this->fail(42, "Invalid group");
|
||||
|
||||
if(!$club->canBeModifiedBy($this->user))
|
||||
$this->fail(16, "Access to group denied");
|
||||
|
||||
$nPost->setWall($group_id * -1);
|
||||
} else {
|
||||
$nPost->setWall($this->user->getId());
|
||||
}
|
||||
|
||||
$nPost->setContent($message);
|
||||
$nPost->setApi_Source_Name($this->getPlatform());
|
||||
$nPost->save();
|
||||
$nPost->attach($post);
|
||||
|
||||
if($post->getOwner(false)->getId() !== $this->user->getId() && !($post->getOwner() instanceof Club))
|
||||
(new RepostNotification($post->getOwner(false), $post, $this->user->identity))->emit();
|
||||
(new RepostNotification($post->getOwner(false), $post, $this->user))->emit();
|
||||
|
||||
return (object) [
|
||||
"success" => 1, // 👍
|
||||
|
@ -479,6 +537,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
];
|
||||
}
|
||||
|
||||
|
||||
function getComments(int $owner_id, int $post_id, bool $need_likes = true, int $offset = 0, int $count = 10, string $fields = "sex,screen_name,photo_50,photo_100,online_info,online", string $sort = "asc", bool $extended = false) {
|
||||
$this->requireUser();
|
||||
|
||||
|
@ -486,7 +545,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
if(!$post || $post->isDeleted()) $this->fail(100, "One of the parameters specified was missing or invalid");
|
||||
|
||||
$comments = (new CommentsRepo)->getCommentsByTarget($post, $offset+1, $count, $sort == "desc" ? "DESC" : "ASC");
|
||||
|
||||
|
||||
$items = [];
|
||||
$profiles = [];
|
||||
|
||||
|
@ -501,9 +560,11 @@ final class Wall extends VKAPIRequestHandler
|
|||
foreach($comment->getChildren() as $attachment) {
|
||||
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||
$attachments[] = $this->getApiPhoto($attachment);
|
||||
} elseif($attachment instanceof \openvk\Web\Models\Entities\Note) {
|
||||
$attachments[] = $attachment->toVkApiStruct();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$item = [
|
||||
"id" => $comment->getId(),
|
||||
"from_id" => $oid,
|
||||
|
@ -529,7 +590,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"user_likes" => (int) $comment->hasLikeFrom($this->getUser()),
|
||||
"can_publish" => 1
|
||||
];
|
||||
|
||||
|
||||
$items[] = $item;
|
||||
if($extended == true)
|
||||
$profiles[] = $comment->getOwner()->getId();
|
||||
|
@ -558,12 +619,12 @@ final class Wall extends VKAPIRequestHandler
|
|||
function getComment(int $owner_id, int $comment_id, bool $extended = false, string $fields = "sex,screen_name,photo_50,photo_100,online_info,online") {
|
||||
$this->requireUser();
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id); // один хуй айди всех комментов общий
|
||||
|
||||
$comment = (new CommentsRepo)->get($comment_id); # один хуй айди всех комментов общий
|
||||
|
||||
$profiles = [];
|
||||
|
||||
$attachments = [];
|
||||
|
||||
|
||||
foreach($comment->getChildren() as $attachment) {
|
||||
if($attachment instanceof \openvk\Web\Models\Entities\Photo) {
|
||||
$attachments[] = $this->getApiPhoto($attachment);
|
||||
|
@ -593,7 +654,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"groups_can_post" => false,
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
if($extended == true)
|
||||
$profiles[] = $comment->getOwner()->getId();
|
||||
|
||||
|
@ -609,25 +670,29 @@ final class Wall extends VKAPIRequestHandler
|
|||
$response['profiles'] = (!empty($profiles) ? (new Users)->get(implode(',', $profiles), $fields) : []);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function createComment(int $owner_id, int $post_id, string $message, int $from_group = 0) {
|
||||
function createComment(int $owner_id, int $post_id, string $message = "", int $from_group = 0, string $attachments = "") {
|
||||
$this->requireUser();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
|
||||
$post = (new PostsRepo)->getPostById($owner_id, $post_id);
|
||||
if(!$post || $post->isDeleted()) $this->fail(100, "One of the parameters specified was missing or invalid");
|
||||
if(!$post || $post->isDeleted()) $this->fail(100, "Invalid post");
|
||||
|
||||
if($post->getTargetWall() < 0)
|
||||
$club = (new ClubsRepo)->get(abs($post->getTargetWall()));
|
||||
|
||||
|
||||
if(empty($message) && empty($attachments)) {
|
||||
$this->fail(100, "Required parameter 'message' missing.");
|
||||
}
|
||||
|
||||
$flags = 0;
|
||||
if($from_group != 0 && !is_null($club) && $club->canBeModifiedBy($this->user))
|
||||
$flags |= 0b10000000;
|
||||
|
||||
|
||||
try {
|
||||
$comment = new Comment;
|
||||
$comment->setOwner($this->user->getId());
|
||||
|
@ -640,11 +705,54 @@ final class Wall extends VKAPIRequestHandler
|
|||
} catch (\LengthException $ex) {
|
||||
$this->fail(1, "ошибка про то что коммент большой слишком");
|
||||
}
|
||||
|
||||
|
||||
if(!empty($attachments)) {
|
||||
$attachmentsArr = explode(",", $attachments);
|
||||
|
||||
if(sizeof($attachmentsArr) > 10)
|
||||
$this->fail(50, "Error: too many attachments");
|
||||
|
||||
foreach($attachmentsArr as $attac) {
|
||||
$attachmentType = NULL;
|
||||
|
||||
if(str_contains($attac, "photo"))
|
||||
$attachmentType = "photo";
|
||||
elseif(str_contains($attac, "video"))
|
||||
$attachmentType = "video";
|
||||
else
|
||||
$this->fail(205, "Unknown attachment type");
|
||||
|
||||
$attachment = str_replace($attachmentType, "", $attac);
|
||||
|
||||
$attachmentOwner = (int)explode("_", $attachment)[0];
|
||||
$attachmentId = (int)end(explode("_", $attachment));
|
||||
|
||||
$attacc = NULL;
|
||||
|
||||
if($attachmentType == "photo") {
|
||||
$attacc = (new PhotosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Photo does not exists");
|
||||
if(!$attacc->getOwner()->getPrivacyPermission('photos.read', $this->getUser()))
|
||||
$this->fail(11, "Access to photo denied");
|
||||
|
||||
$comment->attach($attacc);
|
||||
} elseif($attachmentType == "video") {
|
||||
$attacc = (new VideosRepo)->getByOwnerAndVID($attachmentOwner, $attachmentId);
|
||||
if(!$attacc || $attacc->isDeleted())
|
||||
$this->fail(100, "Video does not exists");
|
||||
if(!$attacc->getOwner()->getPrivacyPermission('videos.read', $this->getUser()))
|
||||
$this->fail(11, "Access to video denied");
|
||||
|
||||
$comment->attach($attacc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($post->getOwner()->getId() !== $this->user->getId())
|
||||
if(($owner = $post->getOwner()) instanceof User)
|
||||
(new CommentNotification($owner, $comment, $post, $this->user))->emit();
|
||||
|
||||
|
||||
return (object) [
|
||||
"comment_id" => $comment->getId(),
|
||||
"parents_stack" => []
|
||||
|
@ -659,12 +767,12 @@ final class Wall extends VKAPIRequestHandler
|
|||
if(!$comment) $this->fail(100, "One of the parameters specified was missing or invalid");;
|
||||
if(!$comment->canBeDeletedBy($this->user))
|
||||
$this->fail(7, "Access denied");
|
||||
|
||||
|
||||
$comment->delete();
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
private function getApiPhoto($attachment) {
|
||||
return [
|
||||
"type" => "photo",
|
||||
|
@ -690,7 +798,7 @@ final class Wall extends VKAPIRequestHandler
|
|||
"votes" => $answer->votes
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
$userVote = array();
|
||||
foreach($attachment->getUserVote($user) as $vote)
|
||||
$userVote[] = $vote[0];
|
||||
|
|
|
@ -5,7 +5,7 @@ exceptions. It is still a work-in-progress functionality.
|
|||
**Note**: requests to API are routed through
|
||||
openvk.Web.Presenters.VKAPIPresenter, this dir contains only handlers.
|
||||
|
||||
[Documentation for API clients](https://docs.openvk.su/openvk_engine/api/description/)
|
||||
[Documentation for API clients](https://docs.openvk.uk/openvk_engine/api/description/)
|
||||
|
||||
## Implementing API methods
|
||||
|
||||
|
|
|
@ -66,4 +66,31 @@ class Album extends MediaCollection
|
|||
{
|
||||
return $this->has($photo);
|
||||
}
|
||||
|
||||
function toVkApiStruct(?User $user = NULL, bool $need_covers = false, bool $photo_sizes = false): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getPrettyId();
|
||||
$res->thumb_id = !is_null($this->getCoverPhoto()) ? $this->getCoverPhoto()->getPrettyId() : 0;
|
||||
$res->owner_id = $this->getOwner()->getId();
|
||||
$res->title = $this->getName();
|
||||
$res->description = $this->getDescription();
|
||||
$res->created = $this->getCreationTime()->timestamp();
|
||||
$res->updated = $this->getEditTime() ? $this->getEditTime()->timestamp() : NULL;
|
||||
$res->size = $this->size();
|
||||
$res->privacy_comment = 1;
|
||||
$res->upload_by_admins_only = 1;
|
||||
$res->comments_disabled = 0;
|
||||
$res->can_upload = $this->canBeModifiedBy($user); # thisUser недоступен в entities
|
||||
if($need_covers) {
|
||||
$res->thumb_src = $this->getCoverURL();
|
||||
|
||||
if($photo_sizes) {
|
||||
$res->sizes = !is_null($this->getCoverPhoto()) ? $this->getCoverPhoto()->getVkApiSizes() : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -306,11 +306,14 @@ class Application extends RowModel
|
|||
function delete(bool $softly = true): void
|
||||
{
|
||||
if($softly)
|
||||
throw new \UnexpectedValueException("Can't delete apps softly.");
|
||||
throw new \UnexpectedValueException("Can't delete apps softly."); // why
|
||||
|
||||
$cx = DatabaseConnection::i()->getContext();
|
||||
$cx->table("app_users")->where("app", $this->getId())->delete();
|
||||
|
||||
parent::delete(false);
|
||||
}
|
||||
|
||||
function getPublicationTime(): string
|
||||
{ return tr("recently"); }
|
||||
}
|
66
Web/Models/Entities/Ban.php
Normal file
66
Web/Models/Entities/Ban.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Entities;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\Repositories\{Users};
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
|
||||
class Ban extends RowModel
|
||||
{
|
||||
protected $tableName = "bans";
|
||||
|
||||
function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getReason(): ?string
|
||||
{
|
||||
return $this->getRecord()->reason;
|
||||
}
|
||||
|
||||
function getUser(): ?User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->user);
|
||||
}
|
||||
|
||||
function getInitiator(): ?User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->initiator);
|
||||
}
|
||||
|
||||
function getStartTime(): int
|
||||
{
|
||||
return $this->getRecord()->iat;
|
||||
}
|
||||
|
||||
function getEndTime(): int
|
||||
{
|
||||
return $this->getRecord()->exp;
|
||||
}
|
||||
|
||||
function getTime(): int
|
||||
{
|
||||
return $this->getRecord()->time;
|
||||
}
|
||||
|
||||
function isPermanent(): bool
|
||||
{
|
||||
return $this->getEndTime() === 0;
|
||||
}
|
||||
|
||||
function isRemovedManually(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->removed_manually;
|
||||
}
|
||||
|
||||
function isOver(): bool
|
||||
{
|
||||
return $this->isRemovedManually();
|
||||
}
|
||||
|
||||
function whoRemoved(): ?User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->removed_by);
|
||||
}
|
||||
}
|
|
@ -160,7 +160,7 @@ class Club extends RowModel
|
|||
|
||||
function canPost(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->wall;
|
||||
return (bool) $this->getRecord()->wall;
|
||||
}
|
||||
|
||||
|
||||
|
@ -224,7 +224,7 @@ class Club extends RowModel
|
|||
"shape" => "spline",
|
||||
"color" => "#597da3",
|
||||
],
|
||||
"name" => $unique ? "Полный охват" : "Все просмотры",
|
||||
"name" => $unique ? tr("full_coverage") : tr("all_views"),
|
||||
],
|
||||
"subs" => [
|
||||
"x" => array_reverse(range(1, 7)),
|
||||
|
@ -235,7 +235,7 @@ class Club extends RowModel
|
|||
"color" => "#b05c91",
|
||||
],
|
||||
"fill" => "tozeroy",
|
||||
"name" => $unique ? "Охват подписчиков" : "Просмотры подписчиков",
|
||||
"name" => $unique ? tr("subs_coverage") : tr("subs_views"),
|
||||
],
|
||||
"viral" => [
|
||||
"x" => array_reverse(range(1, 7)),
|
||||
|
@ -246,7 +246,7 @@ class Club extends RowModel
|
|||
"color" => "#4d9fab",
|
||||
],
|
||||
"fill" => "tozeroy",
|
||||
"name" => $unique ? "Виральный охват" : "Виральные просмотры",
|
||||
"name" => $unique ? tr("viral_coverage") : tr("viral_views"),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -262,17 +262,17 @@ class Club extends RowModel
|
|||
return $subbed && ($this->getOpennesStatus() === static::CLOSED ? $this->isSubscriptionAccepted($user) : true);
|
||||
}
|
||||
|
||||
function getFollowersQuery(): GroupedSelection
|
||||
function getFollowersQuery(string $sort = "follower ASC"): GroupedSelection
|
||||
{
|
||||
$query = $this->getRecord()->related("subscriptions.target");
|
||||
|
||||
if($this->getOpennesStatus() === static::OPEN) {
|
||||
$query = $query->where("model", "openvk\\Web\\Models\\Entities\\Club");
|
||||
$query = $query->where("model", "openvk\\Web\\Models\\Entities\\Club")->order($sort);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $query;
|
||||
return $query->group("follower");
|
||||
}
|
||||
|
||||
function getFollowersCount(): int
|
||||
|
@ -280,9 +280,9 @@ class Club extends RowModel
|
|||
return sizeof($this->getFollowersQuery());
|
||||
}
|
||||
|
||||
function getFollowers(int $page = 1): \Traversable
|
||||
function getFollowers(int $page = 1, int $perPage = 6, string $sort = "follower ASC"): \Traversable
|
||||
{
|
||||
$rels = $this->getFollowersQuery()->page($page, 6);
|
||||
$rels = $this->getFollowersQuery($sort)->page($page, $perPage);
|
||||
|
||||
foreach($rels as $rel) {
|
||||
$rel = (new Users)->get($rel->follower);
|
||||
|
@ -351,15 +351,56 @@ class Club extends RowModel
|
|||
}
|
||||
|
||||
function getWebsite(): ?string
|
||||
{
|
||||
return $this->getRecord()->website;
|
||||
}
|
||||
{
|
||||
return $this->getRecord()->website;
|
||||
}
|
||||
|
||||
function ban(string $reason): void
|
||||
{
|
||||
$this->setBlock_Reason($reason);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function unban(): void
|
||||
{
|
||||
$this->setBlock_Reason(null);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function getAlert(): ?string
|
||||
{
|
||||
return $this->getRecord()->alert;
|
||||
}
|
||||
|
||||
function toVkApiStruct(?User $user = NULL): object
|
||||
{
|
||||
$res = [];
|
||||
|
||||
$res->id = $this->getId();
|
||||
$res->name = $this->getName();
|
||||
$res->screen_name = $this->getShortCode();
|
||||
$res->is_closed = 0;
|
||||
$res->deactivated = NULL;
|
||||
$res->is_admin = $this->canBeModifiedBy($user);
|
||||
|
||||
if($this->canBeModifiedBy($user)) {
|
||||
$res->admin_level = 3;
|
||||
}
|
||||
|
||||
$res->is_member = $this->getSubscriptionStatus($user) ? 1 : 0;
|
||||
|
||||
$res->type = "group";
|
||||
$res->photo_50 = $this->getAvatarUrl("miniscule");
|
||||
$res->photo_100 = $this->getAvatarUrl("tiny");
|
||||
$res->photo_200 = $this->getAvatarUrl("normal");
|
||||
|
||||
$res->can_create_topic = $this->canBeModifiedBy($user) ? 1 : ($this->isEveryoneCanCreateTopics() ? 1 : 0);
|
||||
|
||||
$res->can_post = $this->canBeModifiedBy($user) ? 1 : ($this->canPost() ? 1 : 0);
|
||||
|
||||
return (object) $res;
|
||||
}
|
||||
|
||||
use Traits\TBackDrops;
|
||||
use Traits\TSubscribable;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
namespace openvk\Web\Models\Entities;
|
||||
use openvk\Web\Models\Repositories\Clubs;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\{Note};
|
||||
|
||||
class Comment extends Post
|
||||
{
|
||||
|
@ -52,4 +53,49 @@ class Comment extends Post
|
|||
$this->getTarget() instanceof Post && $this->getTarget()->getTargetWall() < 0 && (new Clubs)->get(abs($this->getTarget()->getTargetWall()))->canBeModifiedBy($user) ||
|
||||
$this->getTarget() instanceof Topic && $this->getTarget()->canBeModifiedBy($user);
|
||||
}
|
||||
|
||||
function toVkApiStruct(?User $user = NULL, bool $need_likes = false, bool $extended = false, ?Note $note = NULL): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getId();
|
||||
$res->from_id = $this->getOwner()->getId();
|
||||
$res->date = $this->getPublicationTime()->timestamp();
|
||||
$res->text = $this->getText(false);
|
||||
$res->attachments = [];
|
||||
$res->parents_stack = [];
|
||||
|
||||
if(!is_null($note)) {
|
||||
$res->uid = $this->getOwner()->getId();
|
||||
$res->nid = $note->getId();
|
||||
$res->oid = $note->getOwner()->getId();
|
||||
}
|
||||
|
||||
foreach($this->getChildren() as $attachment) {
|
||||
if($attachment->isDeleted())
|
||||
continue;
|
||||
|
||||
$res->attachments[] = $attachment->toVkApiStruct();
|
||||
}
|
||||
|
||||
if($need_likes) {
|
||||
$res->count = $this->getLikesCount();
|
||||
$res->user_likes = (int)$this->hasLikeFrom($user);
|
||||
$res->can_like = 1;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
function getURL(): string
|
||||
{
|
||||
return "/wall" . $this->getTarget()->getPrettyId() . "#_comment" . $this->getId();
|
||||
}
|
||||
|
||||
function canBeEditedBy(?User $user = NULL): bool
|
||||
{
|
||||
if(!$user)
|
||||
return false;
|
||||
|
||||
return $user->getId() == $this->getOwner(false)->getId();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ class IP extends RowModel
|
|||
$this->stateChanges("rate_limit_counter", $aCounter);
|
||||
$this->stateChanges("rate_limit_violation_counter_start", $vCounterSessionStart);
|
||||
$this->stateChanges("rate_limit_violation_counter", $vCounter);
|
||||
$this->save();
|
||||
$this->save(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,11 +105,11 @@ class IP extends RowModel
|
|||
$this->stateChanges("ip", $ip);
|
||||
}
|
||||
|
||||
function save(): void
|
||||
function save($log): void
|
||||
{
|
||||
if(is_null($this->getRecord()))
|
||||
$this->stateChanges("first_seen", time());
|
||||
|
||||
parent::save();
|
||||
parent::save($log);
|
||||
}
|
||||
}
|
||||
|
|
71
Web/Models/Entities/NoSpamLog.php
Normal file
71
Web/Models/Entities/NoSpamLog.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Entities;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\Repositories\{Users};
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
|
||||
class NoSpamLog extends RowModel
|
||||
{
|
||||
protected $tableName = "noSpam_templates";
|
||||
|
||||
function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getUser(): ?User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->user);
|
||||
}
|
||||
|
||||
function getModel(): string
|
||||
{
|
||||
return $this->getRecord()->model;
|
||||
}
|
||||
|
||||
function getRegex(): ?string
|
||||
{
|
||||
return $this->getRecord()->regex;
|
||||
}
|
||||
|
||||
function getRequest(): ?string
|
||||
{
|
||||
return $this->getRecord()->request;
|
||||
}
|
||||
|
||||
function getCount(): int
|
||||
{
|
||||
return $this->getRecord()->count;
|
||||
}
|
||||
|
||||
function getTime(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->time);
|
||||
}
|
||||
|
||||
function getItems(): ?array
|
||||
{
|
||||
return explode(",", $this->getRecord()->items);
|
||||
}
|
||||
|
||||
function getTypeRaw(): int
|
||||
{
|
||||
return $this->getRecord()->ban_type;
|
||||
}
|
||||
|
||||
function getType(): string
|
||||
{
|
||||
switch ($this->getTypeRaw()) {
|
||||
case 1: return "О";
|
||||
case 2: return "Б";
|
||||
case 3: return "ОБ";
|
||||
default: return (string) $this->getTypeRaw();
|
||||
}
|
||||
}
|
||||
|
||||
function isRollbacked(): bool
|
||||
{
|
||||
return !is_null($this->getRecord()->rollback);
|
||||
}
|
||||
}
|
|
@ -118,4 +118,24 @@ class Note extends Postable
|
|||
{
|
||||
return $this->getRecord()->source;
|
||||
}
|
||||
|
||||
function toVkApiStruct(): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->type = "note";
|
||||
$res->id = $this->getVirtualId();
|
||||
$res->owner_id = $this->getOwner()->getId();
|
||||
$res->title = $this->getName();
|
||||
$res->text = $this->getText();
|
||||
$res->date = $this->getPublicationTime()->timestamp();
|
||||
$res->comments = $this->getCommentsCount();
|
||||
$res->read_comments = $this->getCommentsCount();
|
||||
$res->view_url = "/note".$this->getOwner()->getId()."_".$this->getId();
|
||||
$res->privacy_view = 1;
|
||||
$res->can_comment = 1;
|
||||
$res->text_wiki = "r";
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -296,25 +296,35 @@ class Photo extends Media
|
|||
return (new Albums)->getAlbumByPhotoId($this);
|
||||
}
|
||||
|
||||
function toVkApiStruct(): object
|
||||
function toVkApiStruct(bool $photo_sizes = true, bool $extended = false): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $res->pid = $this->getId();
|
||||
$res->owner_id = $res->user_id = $this->getOwner()->getId()->getId();
|
||||
$res->id = $res->pid = $this->getVirtualId();
|
||||
$res->owner_id = $res->user_id = $this->getOwner()->getId();
|
||||
$res->aid = $res->album_id = NULL;
|
||||
$res->width = $this->getDimensions()[0];
|
||||
$res->height = $this->getDimensions()[1];
|
||||
$res->date = $res->created = $this->getPublicationTime()->timestamp();
|
||||
|
||||
$res->sizes = $this->getVkApiSizes();
|
||||
$res->src_small = $res->photo_75 = $this->getURLBySizeId("miniscule");
|
||||
$res->src = $res->photo_130 = $this->getURLBySizeId("tiny");
|
||||
$res->src_big = $res->photo_604 = $this->getURLBySizeId("normal");
|
||||
$res->src_xbig = $res->photo_807 = $this->getURLBySizeId("large");
|
||||
$res->src_xxbig = $res->photo_1280 = $this->getURLBySizeId("larger");
|
||||
$res->src_xxxbig = $res->photo_2560 = $this->getURLBySizeId("original");
|
||||
$res->src_original = $res->url = $this->getURLBySizeId("UPLOADED_MAXRES");
|
||||
if($photo_sizes) {
|
||||
$res->sizes = $this->getVkApiSizes();
|
||||
$res->src_small = $res->photo_75 = $this->getURLBySizeId("miniscule");
|
||||
$res->src = $res->photo_130 = $this->getURLBySizeId("tiny");
|
||||
$res->src_big = $res->photo_604 = $this->getURLBySizeId("normal");
|
||||
$res->src_xbig = $res->photo_807 = $this->getURLBySizeId("large");
|
||||
$res->src_xxbig = $res->photo_1280 = $this->getURLBySizeId("larger");
|
||||
$res->src_xxxbig = $res->photo_2560 = $this->getURLBySizeId("original");
|
||||
$res->src_original = $res->url = $this->getURLBySizeId("UPLOADED_MAXRES");
|
||||
}
|
||||
|
||||
if($extended) {
|
||||
$res->likes = $this->getLikesCount(); # их нету но пусть будут
|
||||
$res->comments = $this->getCommentsCount();
|
||||
$res->tags = 0;
|
||||
$res->can_comment = 1;
|
||||
$res->can_repost = 0;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,11 @@ class Post extends Postable
|
|||
return (($this->getRecord()->flags & 0b00100000) > 0) && ($this->getRecord()->owner > 0);
|
||||
}
|
||||
|
||||
function isUpdateAvatarMessage(): bool
|
||||
{
|
||||
return (($this->getRecord()->flags & 0b00010000) > 0) && ($this->getRecord()->owner > 0);
|
||||
}
|
||||
|
||||
function isExplicit(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->nsfw;
|
||||
|
@ -240,6 +245,20 @@ class Post extends Postable
|
|||
$this->unwire();
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function canBeEditedBy(?User $user = NULL): bool
|
||||
{
|
||||
if(!$user)
|
||||
return false;
|
||||
|
||||
if($this->isDeactivationMessage() || $this->isUpdateAvatarMessage())
|
||||
return false;
|
||||
|
||||
if($this->getTargetWall() > 0)
|
||||
return $this->getPublicationTime()->timestamp() + WEEK > time() && $user->getId() == $this->getOwner(false)->getId();
|
||||
|
||||
return $user->getId() == $this->getOwner(false)->getId();
|
||||
}
|
||||
|
||||
use Traits\TRichText;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,8 @@ abstract class Postable extends Attachable
|
|||
$oid = (int) $this->getRecord()->owner;
|
||||
if(!$real && $this->isAnonymous())
|
||||
$oid = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["account"];
|
||||
|
||||
|
||||
$oid = abs($oid);
|
||||
if($oid > 0)
|
||||
return (new Users)->get($oid);
|
||||
else
|
||||
|
@ -84,7 +85,7 @@ abstract class Postable extends Attachable
|
|||
return sizeof(DB::i()->getContext()->table("likes")->where([
|
||||
"model" => static::class,
|
||||
"target" => $this->getRecord()->id,
|
||||
]));
|
||||
])->group("origin"));
|
||||
}
|
||||
|
||||
# TODO add pagination
|
||||
|
@ -166,9 +167,9 @@ abstract class Postable extends Attachable
|
|||
$this->stateChanges("created", time());
|
||||
|
||||
$this->stateChanges("virtual_id", $pCount + 1);
|
||||
} else {
|
||||
} /*else {
|
||||
$this->stateChanges("edited", time());
|
||||
}
|
||||
}*/
|
||||
|
||||
parent::save();
|
||||
}
|
||||
|
|
154
Web/Models/Entities/Report.php
Normal file
154
Web/Models/Entities/Report.php
Normal file
|
@ -0,0 +1,154 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Entities;
|
||||
use openvk\Web\Util\DateTime;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\Club;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Repositories\{Applications, Comments, Notes, Reports, Users, Posts, Photos, Videos, Clubs};
|
||||
use Chandler\Database\DatabaseConnection as DB;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
use Nette\Database\Table\Selection;
|
||||
|
||||
class Report extends RowModel
|
||||
{
|
||||
protected $tableName = "reports";
|
||||
|
||||
function getId(): int
|
||||
{
|
||||
return $this->getRecord()->id;
|
||||
}
|
||||
|
||||
function getStatus(): int
|
||||
{
|
||||
return $this->getRecord()->status;
|
||||
}
|
||||
|
||||
function getContentType(): string
|
||||
{
|
||||
return $this->getRecord()->type;
|
||||
}
|
||||
|
||||
function getReason(): string
|
||||
{
|
||||
return $this->getRecord()->reason;
|
||||
}
|
||||
|
||||
function getTime(): DateTime
|
||||
{
|
||||
return new DateTime($this->getRecord()->date);
|
||||
}
|
||||
|
||||
function isDeleted(): bool
|
||||
{
|
||||
if ($this->getRecord()->deleted === 0)
|
||||
{
|
||||
return false;
|
||||
} elseif ($this->getRecord()->deleted === 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function authorId(): int
|
||||
{
|
||||
return $this->getRecord()->user_id;
|
||||
}
|
||||
|
||||
function getUser(): User
|
||||
{
|
||||
return (new Users)->get((int) $this->getRecord()->user_id);
|
||||
}
|
||||
|
||||
function getContentId(): int
|
||||
{
|
||||
return (int) $this->getRecord()->target_id;
|
||||
}
|
||||
|
||||
function getContentObject()
|
||||
{
|
||||
if ($this->getContentType() == "post") return (new Posts)->get($this->getContentId());
|
||||
else if ($this->getContentType() == "photo") return (new Photos)->get($this->getContentId());
|
||||
else if ($this->getContentType() == "video") return (new Videos)->get($this->getContentId());
|
||||
else if ($this->getContentType() == "group") return (new Clubs)->get($this->getContentId());
|
||||
else if ($this->getContentType() == "comment") return (new Comments)->get($this->getContentId());
|
||||
else if ($this->getContentType() == "note") return (new Notes)->get($this->getContentId());
|
||||
else if ($this->getContentType() == "app") return (new Applications)->get($this->getContentId());
|
||||
else if ($this->getContentType() == "user") return (new Users)->get($this->getContentId());
|
||||
else return null;
|
||||
}
|
||||
|
||||
function getAuthor(): RowModel
|
||||
{
|
||||
return (new Posts)->get($this->getContentId())->getOwner();
|
||||
}
|
||||
|
||||
function getReportAuthor(): User
|
||||
{
|
||||
return (new Users)->get($this->getRecord()->user_id);
|
||||
}
|
||||
|
||||
function banUser($initiator)
|
||||
{
|
||||
$reason = $this->getContentType() !== "user" ? ("**content-" . $this->getContentType() . "-" . $this->getContentId() . "**") : ("Подозрительная активность");
|
||||
$this->getAuthor()->ban($reason, false, time() + $this->getAuthor()->getNewBanTime(), $initiator);
|
||||
}
|
||||
|
||||
function deleteContent()
|
||||
{
|
||||
if ($this->getContentType() !== "user") {
|
||||
$pubTime = $this->getContentObject()->getPublicationTime();
|
||||
if (method_exists($this->getContentObject(), "getName")) {
|
||||
$name = $this->getContentObject()->getName();
|
||||
$placeholder = "$pubTime ($name)";
|
||||
} else {
|
||||
$placeholder = "$pubTime";
|
||||
}
|
||||
|
||||
if ($this->getAuthor() instanceof Club) {
|
||||
$name = $this->getAuthor()->getName();
|
||||
$this->getAuthor()->getOwner()->adminNotify("Ваш контент, который опубликовали $placeholder в созданной вами группе \"$name\" был удалён модераторами инстанса. За повторные или серьёзные нарушения группу могут заблокировать.");
|
||||
} else {
|
||||
$this->getAuthor()->adminNotify("Ваш контент, который вы опубликовали $placeholder был удалён модераторами инстанса. За повторные или серьёзные нарушения вас могут заблокировать.");
|
||||
}
|
||||
$this->getContentObject()->delete($this->getContentType() !== "app");
|
||||
}
|
||||
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
function getDuplicates(): \Traversable
|
||||
{
|
||||
return (new Reports)->getDuplicates($this->getContentType(), $this->getContentId(), $this->getId());
|
||||
}
|
||||
|
||||
function getDuplicatesCount(): int
|
||||
{
|
||||
return count(iterator_to_array($this->getDuplicates()));
|
||||
}
|
||||
|
||||
function hasDuplicates(): bool
|
||||
{
|
||||
return $this->getDuplicatesCount() > 0;
|
||||
}
|
||||
|
||||
function getContentName(): string
|
||||
{
|
||||
if (method_exists($this->getContentObject(), "getCanonicalName"))
|
||||
return $this->getContentObject()->getCanonicalName();
|
||||
|
||||
return $this->getContentType() . " #" . $this->getContentId();
|
||||
}
|
||||
|
||||
public function delete(bool $softly = true): void
|
||||
{
|
||||
if ($this->hasDuplicates()) {
|
||||
foreach ($this->getDuplicates() as $duplicate) {
|
||||
$duplicate->setDeleted(1);
|
||||
$duplicate->save();
|
||||
}
|
||||
}
|
||||
|
||||
$this->setDeleted(1);
|
||||
$this->save();
|
||||
}
|
||||
}
|
|
@ -68,6 +68,12 @@ class Topic extends Postable
|
|||
return isset($array[0]) ? $array[0] : NULL;
|
||||
}
|
||||
|
||||
function getFirstComment(): ?Comment
|
||||
{
|
||||
$array = iterator_to_array($this->getComments(1));
|
||||
return $array[0] ?? NULL;
|
||||
}
|
||||
|
||||
function getUpdateTime(): DateTime
|
||||
{
|
||||
$lastComment = $this->getLastComment();
|
||||
|
@ -83,4 +89,40 @@ class Topic extends Postable
|
|||
$this->unwire();
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function toVkApiStruct(int $preview = 0, int $preview_length = 90): object
|
||||
{
|
||||
$res = (object)[];
|
||||
|
||||
$res->id = $this->getId();
|
||||
$res->title = $this->getTitle();
|
||||
$res->created = $this->getPublicationTime()->timestamp();
|
||||
|
||||
if($this->getOwner() instanceof User) {
|
||||
$res->created_by = $this->getOwner()->getId();
|
||||
} else {
|
||||
$res->created_by = $this->getOwner()->getId() * -1;
|
||||
}
|
||||
|
||||
$res->updated = $this->getUpdateTime()->timestamp();
|
||||
|
||||
if($this->getLastComment()) {
|
||||
if($this->getLastComment()->getOwner() instanceof User) {
|
||||
$res->updated_by = $this->getLastComment()->getOwner()->getId();
|
||||
} else {
|
||||
$res->updated_by = $this->getLastComment()->getOwner()->getId() * -1;
|
||||
}
|
||||
}
|
||||
|
||||
$res->is_closed = (int)$this->isClosed();
|
||||
$res->is_fixed = (int)$this->isPinned();
|
||||
$res->comments = $this->getCommentsCount();
|
||||
|
||||
if($preview == 1) {
|
||||
$res->first_comment = $this->getFirstComment() ? ovk_proc_strtr($this->getFirstComment()->getText(false), $preview_length) : NULL;
|
||||
$res->last_comment = $this->getLastComment() ? ovk_proc_strtr($this->getLastComment()->getText(false), $preview_length) : NULL;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use openvk\Web\Themes\{Themepack, Themepacks};
|
|||
use openvk\Web\Util\DateTime;
|
||||
use openvk\Web\Models\RowModel;
|
||||
use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift};
|
||||
use openvk\Web\Models\Repositories\{Photos, Users, Clubs, Albums, Gifts, Notifications};
|
||||
use openvk\Web\Models\Repositories\{Applications, Bans, Comments, Notes, Posts, Users, Clubs, Albums, Gifts, Notifications, Videos, Photos};
|
||||
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
@ -39,11 +39,14 @@ class User extends RowModel
|
|||
$query = "SELECT id FROM\n" . file_get_contents(__DIR__ . "/../sql/$filename.tsql");
|
||||
$query .= "\n LIMIT " . $limit . " OFFSET " . ( ($page - 1) * $limit );
|
||||
|
||||
$ids = [];
|
||||
$rels = DatabaseConnection::i()->getConnection()->query($query, $id, $id);
|
||||
foreach($rels as $rel) {
|
||||
$rel = (new Users)->get($rel->id);
|
||||
if(!$rel) continue;
|
||||
|
||||
if(in_array($rel->getId(), $ids)) continue;
|
||||
$ids[] = $rel->getId();
|
||||
|
||||
yield $rel;
|
||||
}
|
||||
}
|
||||
|
@ -238,11 +241,60 @@ class User extends RowModel
|
|||
return $this->getRecord()->alert;
|
||||
}
|
||||
|
||||
function getBanReason(): ?string
|
||||
function getTextForContentBan(string $type): string
|
||||
{
|
||||
switch ($type) {
|
||||
case "post": return "за размещение от Вашего лица таких <b>записей</b>:";
|
||||
case "photo": return "за размещение от Вашего лица таких <b>фотографий</b>:";
|
||||
case "video": return "за размещение от Вашего лица таких <b>видеозаписей</b>:";
|
||||
case "group": return "за подозрительное вступление от Вашего лица <b>в группу:</b>";
|
||||
case "comment": return "за размещение от Вашего лица таких <b>комментариев</b>:";
|
||||
case "note": return "за размещение от Вашего лица таких <b>заметок</b>:";
|
||||
case "app": return "за создание от Вашего имени <b>подозрительных приложений</b>.";
|
||||
default: return "за размещение от Вашего лица такого <b>контента</b>:";
|
||||
}
|
||||
}
|
||||
|
||||
function getRawBanReason(): ?string
|
||||
{
|
||||
return $this->getRecord()->block_reason;
|
||||
}
|
||||
|
||||
function getBanReason(?string $for = null)
|
||||
{
|
||||
$ban = (new Bans)->get((int) $this->getRecord()->block_reason);
|
||||
if (!$ban || $ban->isOver()) return null;
|
||||
|
||||
$reason = $ban->getReason();
|
||||
|
||||
preg_match('/\*\*content-(post|photo|video|group|comment|note|app|noSpamTemplate|user)-(\d+)\*\*$/', $reason, $matches);
|
||||
if (sizeof($matches) === 3) {
|
||||
$content_type = $matches[1]; $content_id = (int) $matches[2];
|
||||
if (in_array($content_type, ["noSpamTemplate", "user"])) {
|
||||
$reason = "Подозрительная активность";
|
||||
} else {
|
||||
if ($for !== "banned") {
|
||||
$reason = "Подозрительная активность";
|
||||
} else {
|
||||
$reason = [$this->getTextForContentBan($content_type), $content_type];
|
||||
switch ($content_type) {
|
||||
case "post": $reason[] = (new Posts)->get($content_id); break;
|
||||
case "photo": $reason[] = (new Photos)->get($content_id); break;
|
||||
case "video": $reason[] = (new Videos)->get($content_id); break;
|
||||
case "group": $reason[] = (new Clubs)->get($content_id); break;
|
||||
case "comment": $reason[] = (new Comments)->get($content_id); break;
|
||||
case "note": $reason[] = (new Notes)->get($content_id); break;
|
||||
case "app": $reason[] = (new Applications)->get($content_id); break;
|
||||
case "user": $reason[] = (new Users)->get($content_id); break;
|
||||
default: $reason[] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $reason;
|
||||
}
|
||||
|
||||
function getBanInSupportReason(): ?string
|
||||
{
|
||||
return $this->getRecord()->block_in_support_reason;
|
||||
|
@ -410,6 +462,7 @@ class User extends RowModel
|
|||
"news",
|
||||
"links",
|
||||
"poster",
|
||||
"apps"
|
||||
],
|
||||
])->get($id);
|
||||
}
|
||||
|
@ -830,7 +883,7 @@ class User extends RowModel
|
|||
]);
|
||||
}
|
||||
|
||||
function ban(string $reason, bool $deleteSubscriptions = true, ?int $unban_time = NULL): void
|
||||
function ban(string $reason, bool $deleteSubscriptions = true, $unban_time = NULL, ?int $initiator = NULL): void
|
||||
{
|
||||
if($deleteSubscriptions) {
|
||||
$subs = DatabaseConnection::i()->getContext()->table("subscriptions");
|
||||
|
@ -843,8 +896,33 @@ class User extends RowModel
|
|||
$subs->delete();
|
||||
}
|
||||
|
||||
$this->setBlock_Reason($reason);
|
||||
$this->setUnblock_time($unban_time);
|
||||
$iat = time();
|
||||
$ban = new Ban;
|
||||
$ban->setUser($this->getId());
|
||||
$ban->setReason($reason);
|
||||
$ban->setInitiator($initiator);
|
||||
$ban->setIat($iat);
|
||||
$ban->setExp($unban_time !== "permanent" ? $unban_time : 0);
|
||||
$ban->setTime($unban_time === "permanent" ? 0 : ($unban_time ? ($unban_time - $iat) : 0));
|
||||
$ban->save();
|
||||
|
||||
$this->setBlock_Reason($ban->getId());
|
||||
// $this->setUnblock_time($unban_time);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
function unban(int $removed_by): void
|
||||
{
|
||||
$ban = (new Bans)->get((int) $this->getRawBanReason());
|
||||
if (!$ban || $ban->isOver())
|
||||
return;
|
||||
|
||||
$ban->setRemoved_Manually(true);
|
||||
$ban->setRemoved_By($removed_by);
|
||||
$ban->save();
|
||||
|
||||
$this->setBlock_Reason(NULL);
|
||||
// $user->setUnblock_time(NULL);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
|
@ -949,6 +1027,7 @@ class User extends RowModel
|
|||
"news",
|
||||
"links",
|
||||
"poster",
|
||||
"apps"
|
||||
],
|
||||
])->set($id, (int) $status)->toInteger();
|
||||
|
||||
|
@ -1013,7 +1092,7 @@ class User extends RowModel
|
|||
{
|
||||
$this->setOnline(time());
|
||||
$this->setClient_name($platform);
|
||||
$this->save();
|
||||
$this->save(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1031,7 +1110,7 @@ class User extends RowModel
|
|||
|
||||
function adminNotify(string $message): bool
|
||||
{
|
||||
$admId = OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"];
|
||||
$admId = (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"];
|
||||
if(!$admId)
|
||||
return false;
|
||||
else if(is_null($admin = (new Users)->get($admId)))
|
||||
|
@ -1096,7 +1175,11 @@ class User extends RowModel
|
|||
|
||||
function getUnbanTime(): ?string
|
||||
{
|
||||
return !is_null($this->getRecord()->unblock_time) ? date('d.m.Y', $this->getRecord()->unblock_time) : NULL;
|
||||
$ban = (new Bans)->get((int) $this->getRecord()->block_reason);
|
||||
if (!$ban || $ban->isOver() || $ban->isPermanent()) return null;
|
||||
if ($this->canUnbanThemself()) return tr("today");
|
||||
|
||||
return date('d.m.Y', $ban->getEndTime());
|
||||
}
|
||||
|
||||
function canUnbanThemself(): bool
|
||||
|
@ -1104,10 +1187,57 @@ class User extends RowModel
|
|||
if (!$this->isBanned())
|
||||
return false;
|
||||
|
||||
if ($this->getRecord()->unblock_time > time() || $this->getRecord()->unblock_time == 0)
|
||||
return false;
|
||||
$ban = (new Bans)->get((int) $this->getRecord()->block_reason);
|
||||
if (!$ban || $ban->isOver() || $ban->isPermanent()) return false;
|
||||
|
||||
return true;
|
||||
return $ban->getEndTime() <= time() && !$ban->isPermanent();
|
||||
}
|
||||
|
||||
function getNewBanTime()
|
||||
{
|
||||
$bans = iterator_to_array((new Bans)->getByUser($this->getid()));
|
||||
if (!$bans || count($bans) === 0)
|
||||
return 0;
|
||||
|
||||
$last_ban = end($bans);
|
||||
if (!$last_ban) return 0;
|
||||
|
||||
if ($last_ban->isPermanent()) return "permanent";
|
||||
|
||||
$values = [0, 3600, 7200, 86400, 172800, 604800, 1209600, 3024000, 9072000];
|
||||
$response = 0;
|
||||
$i = 0;
|
||||
|
||||
foreach ($values as $value) {
|
||||
$i++;
|
||||
if ($last_ban->getTime() === 0 && $value === 0) continue;
|
||||
if ($last_ban->getTime() < $value) {
|
||||
$response = $value;
|
||||
break;
|
||||
} else if ($last_ban->getTime() >= $value) {
|
||||
if ($i < count($values)) continue;
|
||||
$response = "permanent";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
function toVkApiStruct(): object
|
||||
{
|
||||
$res = (object) [];
|
||||
|
||||
$res->id = $this->getId();
|
||||
$res->first_name = $this->getFirstName();
|
||||
$res->last_name = $this->getLastName();
|
||||
$res->deactivated = $this->isDeactivated();
|
||||
$res->photo_50 = $this->getAvatarURL();
|
||||
$res->photo_100 = $this->getAvatarURL("tiny");
|
||||
$res->photo_200 = $this->getAvatarURL("normal");
|
||||
$res->photo_id = !is_null($this->getAvatarPhoto()) ? $this->getAvatarPhoto()->getPrettyId() : NULL;
|
||||
# TODO: Perenesti syuda vsyo ostalnoyie
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
use Traits\TBackDrops;
|
||||
|
|
|
@ -117,6 +117,7 @@ class Video extends Media
|
|||
|
||||
function getApiStructure(): object
|
||||
{
|
||||
$fromYoutube = $this->getType() == Video::TYPE_EMBED;
|
||||
return (object)[
|
||||
"type" => "video",
|
||||
"video" => [
|
||||
|
@ -145,10 +146,11 @@ class Video extends Media
|
|||
"user_id" => $this->getOwner()->getId(),
|
||||
"title" => $this->getName(),
|
||||
"is_favorite" => false,
|
||||
"player" => $this->getURL(),
|
||||
"files" => [
|
||||
"player" => !$fromYoutube ? $this->getURL() : $this->getVideoDriver()->getURL(),
|
||||
"files" => !$fromYoutube ? [
|
||||
"mp4_480" => $this->getURL()
|
||||
],
|
||||
] : NULL,
|
||||
"platform" => $fromYoutube ? "youtube" : NULL,
|
||||
"added" => 0,
|
||||
"repeat" => 0,
|
||||
"type" => "video",
|
||||
|
@ -165,6 +167,11 @@ class Video extends Media
|
|||
];
|
||||
}
|
||||
|
||||
function toVkApiStruct(): object
|
||||
{
|
||||
return $this->getApiStructure();
|
||||
}
|
||||
|
||||
function setLink(string $link): string
|
||||
{
|
||||
if(preg_match(file_get_contents(__DIR__ . "/../VideoDrivers/regex/youtube.txt"), $link, $matches)) {
|
||||
|
@ -195,11 +202,14 @@ class Video extends Media
|
|||
$this->save();
|
||||
}
|
||||
|
||||
static function fastMake(int $owner, string $description = "", array $file, bool $unlisted = true, bool $anon = false): Video
|
||||
static function fastMake(int $owner, string $name = "Unnamed Video.ogv", string $description = "", array $file, bool $unlisted = true, bool $anon = false): Video
|
||||
{
|
||||
if(OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading'])
|
||||
exit(VIDEOS_FRIENDLY_ERROR);
|
||||
|
||||
$video = new Video;
|
||||
$video->setOwner($owner);
|
||||
$video->setName("Unnamed Video.ogv");
|
||||
$video->setName(ovk_proc_strtr($name, 61));
|
||||
$video->setDescription(ovk_proc_strtr($description, 300));
|
||||
$video->setAnonymous($anon);
|
||||
$video->setCreated(time());
|
||||
|
|
|
@ -123,4 +123,14 @@ class Albums
|
|||
|
||||
return $dbalbum->collection ? $this->get($dbalbum->collection) : null;
|
||||
}
|
||||
|
||||
function getAlbumByOwnerAndId(int $owner, int $id)
|
||||
{
|
||||
$album = $this->albums->where([
|
||||
"owner" => $owner,
|
||||
"id" => $id
|
||||
])->fetch();
|
||||
|
||||
return new Album($album);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,4 +66,12 @@ class Applications
|
|||
{
|
||||
return sizeof($this->appRels->where("user", $user->getId()));
|
||||
}
|
||||
|
||||
function find(string $query, array $pars = [], string $sort = "id"): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->apps->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("enabled", 1);
|
||||
|
||||
return new Util\EntityStream("Application", $result->order("$sort"));
|
||||
}
|
||||
}
|
33
Web/Models/Repositories/Bans.php
Normal file
33
Web/Models/Repositories/Bans.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Repositories;
|
||||
use Chandler\Database\DatabaseConnection as DB;
|
||||
use Nette\Database\Table\{ActiveRow, Selection};
|
||||
use openvk\Web\Models\Entities\Ban;
|
||||
|
||||
class Bans
|
||||
{
|
||||
private $context;
|
||||
private $bans;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->context = DB::i()->getContext();
|
||||
$this->bans = $this->context->table("bans");
|
||||
}
|
||||
|
||||
function toBan(?ActiveRow $ar): ?Ban
|
||||
{
|
||||
return is_null($ar) ? NULL : new Ban($ar);
|
||||
}
|
||||
|
||||
function get(int $id): ?Ban
|
||||
{
|
||||
return $this->toBan($this->bans->get($id));
|
||||
}
|
||||
|
||||
function getByUser(int $user_id): \Traversable
|
||||
{
|
||||
foreach ($this->bans->where("user", $user_id) as $ban)
|
||||
yield new Ban($ban);
|
||||
}
|
||||
}
|
|
@ -28,7 +28,8 @@ class ChandlerUsers
|
|||
|
||||
function getById(string $UUID): ?ChandlerUser
|
||||
{
|
||||
return new ChandlerUser($this->users->where("id", $UUID)->fetch());
|
||||
$user = $this->users->where("id", $UUID)->fetch();
|
||||
return $user ? new ChandlerUser($user) : NULL;
|
||||
}
|
||||
|
||||
function getList(int $page = 1): \Traversable
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Repositories;
|
||||
use openvk\Web\Models\Entities\Club;
|
||||
use openvk\Web\Models\Repositories\Aliases;
|
||||
use openvk\Web\Models\Entities\{Club, Manager};
|
||||
use openvk\Web\Models\Repositories\{Aliases, Users};
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
|
@ -9,11 +9,13 @@ class Clubs
|
|||
{
|
||||
private $context;
|
||||
private $clubs;
|
||||
private $coadmins;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->context = DatabaseConnection::i()->getContext();
|
||||
$this->clubs = $this->context->table("groups");
|
||||
$this->context = DatabaseConnection::i()->getContext();
|
||||
$this->clubs = $this->context->table("groups");
|
||||
$this->coadmins = $this->context->table("group_coadmins");
|
||||
}
|
||||
|
||||
private function toClub(?ActiveRow $ar): ?Club
|
||||
|
@ -41,12 +43,12 @@ class Clubs
|
|||
return $this->toClub($this->clubs->get($id));
|
||||
}
|
||||
|
||||
function find(string $query, int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
function find(string $query, array $pars = [], string $sort = "id DESC", int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->clubs->where("name LIKE ? OR about LIKE ?", $query, $query);
|
||||
|
||||
return new Util\EntityStream("Club", $result);
|
||||
return new Util\EntityStream("Club", $result->order($sort));
|
||||
}
|
||||
|
||||
function getCount(): int
|
||||
|
@ -70,6 +72,26 @@ class Clubs
|
|||
];
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
function getWriteableClubs(int $id): \Traversable
|
||||
{
|
||||
$result = $this->clubs->where("owner", $id);
|
||||
$coadmins = $this->coadmins->where("user", $id);
|
||||
|
||||
foreach($result as $entry) {
|
||||
yield new Club($entry);
|
||||
}
|
||||
|
||||
foreach($coadmins as $coadmin) {
|
||||
$cl = new Manager($coadmin);
|
||||
yield $cl->getClub();
|
||||
}
|
||||
}
|
||||
|
||||
function getWriteableClubsCount(int $id): int
|
||||
{
|
||||
return sizeof($this->clubs->where("owner", $id)) + sizeof($this->coadmins->where("user", $id));
|
||||
}
|
||||
|
||||
use \Nette\SmartObject;
|
||||
}
|
||||
|
|
|
@ -59,4 +59,35 @@ class Comments
|
|||
"deleted" => false,
|
||||
]));
|
||||
}
|
||||
|
||||
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
|
||||
$notNullParams = [];
|
||||
|
||||
foreach($pars as $paramName => $paramValue)
|
||||
if($paramName != "before" && $paramName != "after")
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
|
||||
else
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
|
||||
|
||||
$result = $this->comments->where("content LIKE ?", $query)->where("deleted", 0);
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
foreach($notNullParams as $paramName => $paramValue) {
|
||||
switch($paramName) {
|
||||
case "before":
|
||||
$result->where("created < ?", $paramValue);
|
||||
break;
|
||||
case "after":
|
||||
$result->where("created > ?", $paramValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Util\EntityStream("Comment", $result->order("$sort"));
|
||||
}
|
||||
}
|
||||
|
|
49
Web/Models/Repositories/CurrentUser.php
Normal file
49
Web/Models/Repositories/CurrentUser.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Repositories;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
|
||||
class CurrentUser
|
||||
{
|
||||
private static $instance = null;
|
||||
private $user;
|
||||
private $ip;
|
||||
private $useragent;
|
||||
|
||||
public function __construct(?User $user = NULL, ?string $ip = NULL, ?string $useragent = NULL)
|
||||
{
|
||||
if ($user)
|
||||
$this->user = $user;
|
||||
|
||||
if ($ip)
|
||||
$this->ip = $ip;
|
||||
|
||||
if ($useragent)
|
||||
$this->useragent = $useragent;
|
||||
}
|
||||
|
||||
public static function get($user, $ip, $useragent)
|
||||
{
|
||||
if (self::$instance === null) self::$instance = new self($user, $ip, $useragent);
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function getUser(): User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function getIP(): string
|
||||
{
|
||||
return $this->ip;
|
||||
}
|
||||
|
||||
public function getUserAgent(): string
|
||||
{
|
||||
return $this->useragent;
|
||||
}
|
||||
|
||||
public static function i()
|
||||
{
|
||||
return self::$instance;
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ class IPs
|
|||
if(!$res) {
|
||||
$res = new IP;
|
||||
$res->setIp($ip);
|
||||
$res->save();
|
||||
$res->save(false);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
|
34
Web/Models/Repositories/NoSpamLogs.php
Normal file
34
Web/Models/Repositories/NoSpamLogs.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Repositories;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Entities\NoSpamLog;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
|
||||
class NoSpamLogs
|
||||
{
|
||||
private $context;
|
||||
private $noSpamLogs;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->context = DatabaseConnection::i()->getContext();
|
||||
$this->noSpamLogs = $this->context->table("noSpam_templates");
|
||||
}
|
||||
|
||||
private function toNoSpamLog(?ActiveRow $ar): ?NoSpamLog
|
||||
{
|
||||
return is_null($ar) ? NULL : new NoSpamLog($ar);
|
||||
}
|
||||
|
||||
function get(int $id): ?NoSpamLog
|
||||
{
|
||||
return $this->toNoSpamLog($this->noSpamLogs->get($id));
|
||||
}
|
||||
|
||||
function getList(array $filter = []): \Traversable
|
||||
{
|
||||
foreach ($this->noSpamLogs->where($filter)->order("`id` DESC") as $log)
|
||||
yield new NoSpamLog($log);
|
||||
}
|
||||
}
|
|
@ -26,10 +26,10 @@ class Notes
|
|||
return $this->toNote($this->notes->get($id));
|
||||
}
|
||||
|
||||
function getUserNotes(User $user, int $page = 1, ?int $perPage = NULL): \Traversable
|
||||
function getUserNotes(User $user, int $page = 1, ?int $perPage = NULL, string $sort = "DESC"): \Traversable
|
||||
{
|
||||
$perPage = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
|
||||
foreach($this->notes->where("owner", $user->getId())->where("deleted", 0)->order("created DESC")->page($page, $perPage) as $album)
|
||||
foreach($this->notes->where("owner", $user->getId())->where("deleted", 0)->order("created $sort")->page($page, $perPage) as $album)
|
||||
yield new Note($album);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Repositories;
|
||||
use openvk\Web\Models\Entities\Photo;
|
||||
use openvk\Web\Models\Entities\{Photo, User};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
class Photos
|
||||
|
@ -32,4 +32,15 @@ class Photos
|
|||
|
||||
return new Photo($photo);
|
||||
}
|
||||
|
||||
function getEveryUserPhoto(User $user): \Traversable
|
||||
{
|
||||
$photos = $this->photos->where([
|
||||
"owner" => $user->getId()
|
||||
]);
|
||||
|
||||
foreach($photos as $photo) {
|
||||
yield new Photo($photo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,7 +99,39 @@ class Posts
|
|||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
|
||||
$notNullParams = [];
|
||||
|
||||
foreach($pars as $paramName => $paramValue)
|
||||
if($paramName != "before" && $paramName != "after")
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
|
||||
else
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
|
||||
|
||||
$result = $this->posts->where("content LIKE ?", $query)->where("deleted", 0);
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
foreach($notNullParams as $paramName => $paramValue) {
|
||||
switch($paramName) {
|
||||
case "before":
|
||||
$result->where("created < ?", $paramValue);
|
||||
break;
|
||||
case "after":
|
||||
$result->where("created > ?", $paramValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new Util\EntityStream("Post", $result->order("$sort"));
|
||||
}
|
||||
|
||||
function getPostCountOnUserWall(int $user): int
|
||||
{
|
||||
return sizeof($this->posts->where(["wall" => $user, "deleted" => 0]));
|
||||
|
|
67
Web/Models/Repositories/Reports.php
Normal file
67
Web/Models/Repositories/Reports.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Models\Repositories;
|
||||
use openvk\Web\Models\Entities\Report;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
class Reports
|
||||
{
|
||||
private $context;
|
||||
private $reports;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->context = DatabaseConnection::i()->getContext();
|
||||
$this->reports = $this->context->table("reports");
|
||||
}
|
||||
|
||||
private function toReport(?ActiveRow $ar): ?Report
|
||||
{
|
||||
return is_null($ar) ? NULL : new Report($ar);
|
||||
}
|
||||
|
||||
function getReports(int $state = 0, int $page = 1, ?string $type = NULL, ?bool $pagination = true): \Traversable
|
||||
{
|
||||
$filter = ["deleted" => 0];
|
||||
if ($type) $filter["type"] = $type;
|
||||
|
||||
$reports = $this->reports->where($filter)->order("created DESC")->group("target_id, type");
|
||||
if ($pagination)
|
||||
$reports = $reports->page($page, 15);
|
||||
|
||||
foreach($reports as $t)
|
||||
yield new Report($t);
|
||||
}
|
||||
|
||||
function getReportsCount(int $state = 0): int
|
||||
{
|
||||
return sizeof($this->reports->where(["deleted" => 0, "type" => $state])->group("target_id, type"));
|
||||
}
|
||||
|
||||
function get(int $id): ?Report
|
||||
{
|
||||
return $this->toReport($this->reports->get($id));
|
||||
}
|
||||
|
||||
function getByContentId(int $id): ?Report
|
||||
{
|
||||
$post = $this->reports->where(["deleted" => 0, "content_id" => $id])->fetch();
|
||||
|
||||
if($post)
|
||||
return new Report($post);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
function getDuplicates(string $type, int $target_id, ?int $orig = NULL, ?int $user_id = NULL): \Traversable
|
||||
{
|
||||
$filter = ["deleted" => 0, "type" => $type, "target_id" => $target_id];
|
||||
if ($orig) $filter[] = "id != $orig";
|
||||
if ($user_id) $filter["user_id"] = $user_id;
|
||||
|
||||
foreach ($this->reports->where($filter) as $report)
|
||||
yield new Report($report);
|
||||
}
|
||||
|
||||
use \Nette\SmartObject;
|
||||
}
|
|
@ -44,17 +44,96 @@ class Users
|
|||
return $alias->getUser();
|
||||
}
|
||||
|
||||
function getByChandlerUser(ChandlerUser $user): ?User
|
||||
function getByChandlerUser(?ChandlerUser $user): ?User
|
||||
{
|
||||
return $this->toUser($this->users->where("user", $user->getId())->fetch());
|
||||
return $user ? $this->toUser($this->users->where("user", $user->getId())->fetch()) : NULL;
|
||||
}
|
||||
|
||||
function find(string $query): Util\EntityStream
|
||||
function find(string $query, array $pars = [], string $sort = "id DESC"): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name, pseudo, shortcode) LIKE ?", $query)->where("deleted", 0);
|
||||
|
||||
return new Util\EntityStream("User", $result);
|
||||
$notNullParams = [];
|
||||
$nnparamsCount = 0;
|
||||
|
||||
foreach($pars as $paramName => $paramValue)
|
||||
if($paramName != "before" && $paramName != "after" && $paramName != "gender" && $paramName != "maritalstatus" && $paramName != "politViews" && $paramName != "doNotSearchMe")
|
||||
$paramValue != NULL ? $notNullParams += ["$paramName" => "%$paramValue%"] : NULL;
|
||||
else
|
||||
$paramValue != NULL ? $notNullParams += ["$paramName" => "$paramValue"] : NULL;
|
||||
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
foreach($notNullParams as $paramName => $paramValue) {
|
||||
switch($paramName) {
|
||||
case "hometown":
|
||||
$result->where("hometown LIKE ?", $paramValue);
|
||||
break;
|
||||
case "city":
|
||||
$result->where("city LIKE ?", $paramValue);
|
||||
break;
|
||||
case "maritalstatus":
|
||||
$result->where("marital_status ?", $paramValue);
|
||||
break;
|
||||
case "status":
|
||||
$result->where("status LIKE ?", $paramValue);
|
||||
break;
|
||||
case "politViews":
|
||||
$result->where("polit_views ?", $paramValue);
|
||||
break;
|
||||
case "email":
|
||||
$result->where("email_contact LIKE ?", $paramValue);
|
||||
break;
|
||||
case "telegram":
|
||||
$result->where("telegram LIKE ?", $paramValue);
|
||||
break;
|
||||
case "site":
|
||||
$result->where("telegram LIKE ?", $paramValue);
|
||||
break;
|
||||
case "address":
|
||||
$result->where("address LIKE ?", $paramValue);
|
||||
break;
|
||||
case "is_online":
|
||||
$result->where("online >= ?", time() - 900);
|
||||
break;
|
||||
case "interests":
|
||||
$result->where("interests LIKE ?", $paramValue);
|
||||
break;
|
||||
case "fav_mus":
|
||||
$result->where("fav_music LIKE ?", $paramValue);
|
||||
break;
|
||||
case "fav_films":
|
||||
$result->where("fav_films LIKE ?", $paramValue);
|
||||
break;
|
||||
case "fav_shows":
|
||||
$result->where("fav_shows LIKE ?", $paramValue);
|
||||
break;
|
||||
case "fav_books":
|
||||
$result->where("fav_books LIKE ?", $paramValue);
|
||||
break;
|
||||
case "fav_quote":
|
||||
$result->where("fav_quote LIKE ?", $paramValue);
|
||||
break;
|
||||
case "before":
|
||||
$result->where("UNIX_TIMESTAMP(since) < ?", $paramValue);
|
||||
break;
|
||||
case "after":
|
||||
$result->where("UNIX_TIMESTAMP(since) > ?", $paramValue);
|
||||
break;
|
||||
case "gender":
|
||||
$result->where("sex ?", $paramValue);
|
||||
break;
|
||||
case "doNotSearchMe":
|
||||
$result->where("id !=", $paramValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new Util\EntityStream("User", $result->order($sort));
|
||||
}
|
||||
|
||||
function getStatistics(): object
|
||||
|
|
|
@ -45,4 +45,36 @@ class Videos
|
|||
{
|
||||
return sizeof($this->videos->where("owner", $user->getId())->where(["deleted" => 0, "unlisted" => 0]));
|
||||
}
|
||||
|
||||
function find(string $query = "", array $pars = [], string $sort = "id"): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
|
||||
$notNullParams = [];
|
||||
|
||||
foreach($pars as $paramName => $paramValue)
|
||||
if($paramName != "before" && $paramName != "after")
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "%$paramValue%"] : NULL;
|
||||
else
|
||||
$paramValue != NULL ? $notNullParams+=["$paramName" => "$paramValue"] : NULL;
|
||||
|
||||
$result = $this->videos->where("CONCAT_WS(' ', name, description) LIKE ?", $query)->where("deleted", 0);
|
||||
$nnparamsCount = sizeof($notNullParams);
|
||||
|
||||
if($nnparamsCount > 0) {
|
||||
foreach($notNullParams as $paramName => $paramValue) {
|
||||
switch($paramName) {
|
||||
case "before":
|
||||
$result->where("created < ?", $paramValue);
|
||||
break;
|
||||
case "after":
|
||||
$result->where("created > ?", $paramValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new Util\EntityStream("Video", $result->order("$sort"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(SELECT follower AS __id FROM
|
||||
(SELECT DISTINCT(follower) AS __id FROM
|
||||
(SELECT follower FROM subscriptions WHERE target=? AND model="openvk\\Web\\Models\\Entities\\User") u0
|
||||
LEFT JOIN
|
||||
(SELECT target FROM subscriptions WHERE follower=? AND model="openvk\\Web\\Models\\Entities\\User") u1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(SELECT follower AS __id FROM
|
||||
(SELECT DISTINCT(follower) AS __id FROM
|
||||
(SELECT follower FROM subscriptions WHERE target=? AND model="openvk\\Web\\Models\\Entities\\User") u0
|
||||
INNER JOIN
|
||||
(SELECT target FROM subscriptions WHERE follower=? AND model="openvk\\Web\\Models\\Entities\\User") u1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(SELECT follower AS __id FROM
|
||||
(SELECT DISTINCT(follower) AS __id FROM
|
||||
(SELECT follower FROM subscriptions WHERE target=? AND model="openvk\\Web\\Models\\Entities\\User") u0
|
||||
INNER JOIN
|
||||
(SELECT target FROM subscriptions WHERE follower=? AND model="openvk\\Web\\Models\\Entities\\User") u1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
(SELECT target AS __id FROM
|
||||
(SELECT DISTINCT(target) AS __id FROM
|
||||
(SELECT follower FROM subscriptions WHERE target=? AND model="openvk\\Web\\Models\\Entities\\User") u0
|
||||
RIGHT JOIN
|
||||
(SELECT target FROM subscriptions WHERE follower=? AND model="openvk\\Web\\Models\\Entities\\User") u1
|
||||
|
|
|
@ -141,6 +141,6 @@ final class AboutPresenter extends OpenVKPresenter
|
|||
|
||||
function renderDev(): void
|
||||
{
|
||||
$this->redirect("https://docs.openvk.su/");
|
||||
$this->redirect("https://docs.openvk.uk/");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Presenters;
|
||||
use Chandler\Database\Log;
|
||||
use Chandler\Database\Logs;
|
||||
use openvk\Web\Models\Entities\{Voucher, Gift, GiftCategory, User, BannedLink};
|
||||
use openvk\Web\Models\Repositories\{ChandlerGroups, ChandlerUsers, Users, Clubs, Vouchers, Gifts, BannedLinks};
|
||||
use openvk\Web\Models\Repositories\{Bans, ChandlerGroups, ChandlerUsers, Photos, Posts, Users, Clubs, Videos, Vouchers, Gifts, BannedLinks};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
final class AdminPresenter extends OpenVKPresenter
|
||||
|
@ -12,6 +14,7 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
private $gifts;
|
||||
private $bannedLinks;
|
||||
private $chandlerGroups;
|
||||
private $logs;
|
||||
|
||||
function __construct(Users $users, Clubs $clubs, Vouchers $vouchers, Gifts $gifts, BannedLinks $bannedLinks, ChandlerGroups $chandlerGroups)
|
||||
{
|
||||
|
@ -21,6 +24,7 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$this->gifts = $gifts;
|
||||
$this->bannedLinks = $bannedLinks;
|
||||
$this->chandlerGroups = $chandlerGroups;
|
||||
$this->logs = DatabaseConnection::i()->getContext()->table("ChandlerLogs");
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
@ -86,6 +90,9 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$query = "INSERT INTO `ChandlerACLRelations` (`user`, `group`) VALUES ('" . $user->getChandlerGUID() . "', '" . $this->postParam("add-to-group") . "')";
|
||||
DatabaseConnection::i()->getConnection()->query($query);
|
||||
}
|
||||
if($this->postParam("password")) {
|
||||
$user->getChandlerUser()->updatePassword($this->postParam("password"));
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
|
@ -125,7 +132,8 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$club->save();
|
||||
break;
|
||||
case "ban":
|
||||
$club->setBlock_reason($this->postParam("ban_reason"));
|
||||
$reason = mb_strlen(trim($this->postParam("ban_reason"))) > 0 ? $this->postParam("ban_reason") : NULL;
|
||||
$club->setBlock_reason($reason);
|
||||
$club->save();
|
||||
break;
|
||||
}
|
||||
|
@ -275,7 +283,7 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$this->notFound();
|
||||
|
||||
$gift->delete();
|
||||
$this->flashFail("succ", "Gift moved successfully", "This gift will now be in <b>Recycle Bin</b>.");
|
||||
$this->flashFail("succ", tr("admin_gift_moved_successfully"), tr("admin_gift_moved_to_recycle"));
|
||||
break;
|
||||
case "copy":
|
||||
case "move":
|
||||
|
@ -294,7 +302,7 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$catTo->addGift($gift);
|
||||
|
||||
$name = $catTo->getName();
|
||||
$this->flash("succ", "Gift moved successfully", "This gift will now be in <b>$name</b>.");
|
||||
$this->flash("succ", tr("admin_gift_moved_successfully"), "This gift will now be in <b>$name</b>.");
|
||||
$this->redirect("/admin/gifts/" . $catTo->getSlug() . "." . $catTo->getId() . "/");
|
||||
break;
|
||||
default:
|
||||
|
@ -325,10 +333,10 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$gift->setUsages((int) $this->postParam("usages"));
|
||||
if(isset($_FILES["pic"]) && $_FILES["pic"]["error"] === UPLOAD_ERR_OK) {
|
||||
if(!$gift->setImage($_FILES["pic"]["tmp_name"]))
|
||||
$this->flashFail("err", "Не удалось сохранить подарок", "Изображение подарка кривое.");
|
||||
$this->flashFail("err", tr("error_when_saving_gift"), tr("error_when_saving_gift_bad_image"));
|
||||
} else if($gen) {
|
||||
# If there's no gift pic but it's newly created
|
||||
$this->flashFail("err", "Не удалось сохранить подарок", "Пожалуйста, загрузите изображение подарка.");
|
||||
$this->flashFail("err", tr("error_when_saving_gift"), tr("error_when_saving_gift_no_image"));
|
||||
}
|
||||
|
||||
$gift->save();
|
||||
|
@ -352,13 +360,19 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
{
|
||||
$this->assertNoCSRF();
|
||||
|
||||
$unban_time = strtotime($this->queryParam("date")) ?: NULL;
|
||||
if (str_contains($this->queryParam("reason"), "*"))
|
||||
exit(json_encode([ "error" => "Incorrect reason" ]));
|
||||
|
||||
$unban_time = strtotime($this->queryParam("date")) ?: "permanent";
|
||||
|
||||
$user = $this->users->get($id);
|
||||
if(!$user)
|
||||
exit(json_encode([ "error" => "User does not exist" ]));
|
||||
|
||||
$user->ban($this->queryParam("reason"), true, $unban_time);
|
||||
|
||||
if ($this->queryParam("incr"))
|
||||
$unban_time = time() + $user->getNewBanTime();
|
||||
|
||||
$user->ban($this->queryParam("reason"), true, $unban_time, $this->user->identity->getId());
|
||||
exit(json_encode([ "success" => true, "reason" => $this->queryParam("reason") ]));
|
||||
}
|
||||
|
||||
|
@ -369,9 +383,17 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$user = $this->users->get($id);
|
||||
if(!$user)
|
||||
exit(json_encode([ "error" => "User does not exist" ]));
|
||||
|
||||
|
||||
$ban = (new Bans)->get((int)$user->getRawBanReason());
|
||||
if (!$ban || $ban->isOver())
|
||||
exit(json_encode([ "error" => "User is not banned" ]));
|
||||
|
||||
$ban->setRemoved_Manually(true);
|
||||
$ban->setRemoved_By($this->user->identity->getId());
|
||||
$ban->save();
|
||||
|
||||
$user->setBlock_Reason(NULL);
|
||||
$user->setUnblock_time(NULL);
|
||||
// $user->setUnblock_time(NULL);
|
||||
$user->save();
|
||||
exit(json_encode([ "success" => true ]));
|
||||
}
|
||||
|
@ -457,6 +479,14 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
$this->redirect("/admin/bannedLinks");
|
||||
}
|
||||
|
||||
function renderBansHistory(int $user_id) :void
|
||||
{
|
||||
$user = (new Users)->get($user_id);
|
||||
if (!$user) $this->notFound();
|
||||
|
||||
$this->template->bans = (new Bans)->getByUser($user_id);
|
||||
}
|
||||
|
||||
function renderChandlerGroups(): void
|
||||
{
|
||||
$this->template->groups = (new ChandlerGroups)->getList();
|
||||
|
@ -547,4 +577,38 @@ final class AdminPresenter extends OpenVKPresenter
|
|||
|
||||
$this->redirect("/admin/users/id" . $user->getId());
|
||||
}
|
||||
|
||||
function renderLogs(): void
|
||||
{
|
||||
$filter = [];
|
||||
|
||||
if ($this->queryParam("id")) {
|
||||
$id = (int) $this->queryParam("id");
|
||||
$filter["id"] = $id;
|
||||
$this->template->id = $id;
|
||||
}
|
||||
if ($this->queryParam("type") !== NULL && $this->queryParam("type") !== "any") {
|
||||
$type = in_array($this->queryParam("type"), [0, 1, 2, 3]) ? (int) $this->queryParam("type") : 0;
|
||||
$filter["type"] = $type;
|
||||
$this->template->type = $type;
|
||||
}
|
||||
if ($this->queryParam("uid")) {
|
||||
$user = $this->queryParam("uid");
|
||||
$filter["user"] = $user;
|
||||
$this->template->user = $user;
|
||||
}
|
||||
if ($this->queryParam("obj_id")) {
|
||||
$obj_id = (int) $this->queryParam("obj_id");
|
||||
$filter["object_id"] = $obj_id;
|
||||
$this->template->obj_id = $obj_id;
|
||||
}
|
||||
if ($this->queryParam("obj_type") !== NULL && $this->queryParam("obj_type") !== "any") {
|
||||
$obj_type = "openvk\\Web\\Models\\Entities\\" . $this->queryParam("obj_type");
|
||||
$filter["object_model"] = $obj_type;
|
||||
$this->template->obj_type = $obj_type;
|
||||
}
|
||||
|
||||
$this->template->logs = (new Logs)->search($filter);
|
||||
$this->template->object_types = (new Logs)->getTypes();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Presenters;
|
||||
use openvk\Web\Models\Entities\{IP, User, PasswordReset, EmailVerification};
|
||||
use openvk\Web\Models\Repositories\{IPs, Users, Restores, Verifications};
|
||||
use openvk\Web\Models\Repositories\{Bans, IPs, Users, Restores, Verifications, Logs};
|
||||
use openvk\Web\Models\Exceptions\InvalidUserNameException;
|
||||
use openvk\Web\Util\Validator;
|
||||
use Chandler\Session\Session;
|
||||
|
@ -110,7 +110,7 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
$this->flashFail("err", tr("failed_to_register"), tr("user_already_exists"));
|
||||
|
||||
$user->setUser($chUser->getId());
|
||||
$user->save();
|
||||
$user->save(false);
|
||||
|
||||
if(!is_null($referer)) {
|
||||
$user->toggleSubscription($referer);
|
||||
|
@ -130,7 +130,9 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
$this->authenticator->authenticate($chUser->getId());
|
||||
(new Logs)->create($user->getId(), "profiles", "openvk\\Web\\Models\\Entities\\User", 0, $user, $user, $_SERVER["REMOTE_ADDR"], $_SERVER["HTTP_USER_AGENT"]);
|
||||
$this->redirect("/id" . $user->getId());
|
||||
$user->save();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,6 +209,9 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
|
||||
function renderFinishRestoringPassword(): void
|
||||
{
|
||||
if(OPENVK_ROOT_CONF['openvk']['preferences']['security']['disablePasswordRestoring'])
|
||||
$this->notFound();
|
||||
|
||||
$request = $this->restores->getByToken(str_replace(" ", "+", $this->queryParam("key")));
|
||||
if(!$request || !$request->isStillValid()) {
|
||||
$this->flash("err", tr("token_manipulation_error"), tr("token_manipulation_error_comment"));
|
||||
|
@ -241,6 +246,9 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
|
||||
function renderRestore(): void
|
||||
{
|
||||
if(OPENVK_ROOT_CONF['openvk']['preferences']['security']['disablePasswordRestoring'])
|
||||
$this->notFound();
|
||||
|
||||
if(!is_null($this->user))
|
||||
$this->redirect($this->user->identity->getURL());
|
||||
|
||||
|
@ -339,9 +347,16 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
$user = $this->users->get($this->user->id);
|
||||
$ban = (new Bans)->get((int)$user->getRawBanReason());
|
||||
if (!$ban || $ban->isOver() || $ban->isPermanent())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
$ban->setRemoved_Manually(2);
|
||||
$ban->setRemoved_By($this->user->identity->getId());
|
||||
$ban->save();
|
||||
|
||||
$user->setBlock_Reason(NULL);
|
||||
$user->setUnblock_Time(NULL);
|
||||
// $user->setUnblock_Time(NULL);
|
||||
$user->save();
|
||||
|
||||
$this->flashFail("succ", tr("banned_unban_title"), tr("banned_unban_description"));
|
||||
|
|
|
@ -3,6 +3,8 @@ namespace openvk\Web\Presenters;
|
|||
|
||||
final class BlobPresenter extends OpenVKPresenter
|
||||
{
|
||||
protected $banTolerant = true;
|
||||
|
||||
private function getDirName($dir): string
|
||||
{
|
||||
if(gettype($dir) === "integer") {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
namespace openvk\Web\Presenters;
|
||||
use openvk\Web\Models\Entities\{Comment, Notifications\MentionNotification, Photo, Video, User, Topic, Post};
|
||||
use openvk\Web\Models\Entities\Notifications\CommentNotification;
|
||||
use openvk\Web\Models\Repositories\{Comments, Clubs};
|
||||
use openvk\Web\Models\Repositories\{Comments, Clubs, Videos};
|
||||
|
||||
final class CommentPresenter extends OpenVKPresenter
|
||||
{
|
||||
|
@ -22,6 +22,9 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
|
||||
$comment = (new Comments)->get($id);
|
||||
if(!$comment || $comment->isDeleted()) $this->notFound();
|
||||
|
||||
if ($comment->getTarget() instanceof Post && $comment->getTarget()->getWallOwner()->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
if(!is_null($this->user)) $comment->toggleLike($this->user->identity);
|
||||
|
||||
|
@ -47,6 +50,12 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
$club = (new Clubs)->get(abs($entity->getTargetWall()));
|
||||
else if($entity instanceof Topic)
|
||||
$club = $entity->getClub();
|
||||
|
||||
if ($entity instanceof Post && $entity->getWallOwner()->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
if($_FILES["_vid_attachment"] && OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading'])
|
||||
$this->flashFail("err", tr("error"), tr("video_uploads_disabled"));
|
||||
|
||||
$flags = 0;
|
||||
if($this->postParam("as_group") === "on" && !is_null($club) && $club->canBeModifiedBy($this->user->identity))
|
||||
|
@ -57,14 +66,13 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
try {
|
||||
$photo = Photo::fastMake($this->user->id, $this->postParam("text"), $_FILES["_pic_attachment"]);
|
||||
} catch(ISE $ex) {
|
||||
$this->flashFail("err", "Не удалось опубликовать пост", "Файл изображения повреждён, слишком велик или одна сторона изображения в разы больше другой.");
|
||||
$this->flashFail("err", tr("error_when_publishing_comment"), tr("error_when_publishing_comment_description"));
|
||||
}
|
||||
}
|
||||
|
||||
# TODO move to trait
|
||||
try {
|
||||
$photo = NULL;
|
||||
$video = NULL;
|
||||
if($_FILES["_pic_attachment"]["error"] === UPLOAD_ERR_OK) {
|
||||
$album = NULL;
|
||||
if($wall > 0 && $wall === $this->user->id)
|
||||
|
@ -72,16 +80,31 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
|
||||
$photo = Photo::fastMake($this->user->id, $this->postParam("text"), $_FILES["_pic_attachment"], $album);
|
||||
}
|
||||
|
||||
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK) {
|
||||
$video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"]);
|
||||
}
|
||||
} catch(ISE $ex) {
|
||||
$this->flashFail("err", "Не удалось опубликовать комментарий", "Файл медиаконтента повреждён или слишком велик.");
|
||||
$this->flashFail("err", tr("error_when_publishing_comment"), tr("error_comment_file_too_big"));
|
||||
}
|
||||
|
||||
$videos = [];
|
||||
|
||||
if(!empty($this->postParam("videos"))) {
|
||||
$un = rtrim($this->postParam("videos"), ",");
|
||||
$arr = explode(",", $un);
|
||||
|
||||
if(sizeof($arr) < 11) {
|
||||
foreach($arr as $dat) {
|
||||
$ids = explode("_", $dat);
|
||||
$video = (new Videos)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
|
||||
|
||||
if(!$video || $video->isDeleted())
|
||||
continue;
|
||||
|
||||
$videos[] = $video;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($this->postParam("text")) && !$photo && !$video)
|
||||
$this->flashFail("err", "Не удалось опубликовать комментарий", "Комментарий пустой или слишком большой.");
|
||||
$this->flashFail("err", tr("error_when_publishing_comment"), tr("error_comment_empty"));
|
||||
|
||||
try {
|
||||
$comment = new Comment;
|
||||
|
@ -93,14 +116,15 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
$comment->setFlags($flags);
|
||||
$comment->save();
|
||||
} catch (\LengthException $ex) {
|
||||
$this->flashFail("err", "Не удалось опубликовать комментарий", "Комментарий слишком большой.");
|
||||
$this->flashFail("err", tr("error_when_publishing_comment"), tr("error_comment_too_big"));
|
||||
}
|
||||
|
||||
if(!is_null($photo))
|
||||
$comment->attach($photo);
|
||||
|
||||
if(!is_null($video))
|
||||
$comment->attach($video);
|
||||
if(sizeof($videos) > 0)
|
||||
foreach($videos as $vid)
|
||||
$comment->attach($vid);
|
||||
|
||||
if($entity->getOwner()->getId() !== $this->user->identity->getId())
|
||||
if(($owner = $entity->getOwner()) instanceof User)
|
||||
|
@ -115,7 +139,7 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
if($mentionee instanceof User)
|
||||
(new MentionNotification($mentionee, $entity, $comment->getOwner(), strip_tags($comment->getText())))->emit();
|
||||
|
||||
$this->flashFail("succ", "Комментарий добавлен", "Ваш комментарий появится на странице.");
|
||||
$this->flashFail("succ", tr("comment_is_added"), tr("comment_is_added_desc"));
|
||||
}
|
||||
|
||||
function renderDeleteComment(int $id): void
|
||||
|
@ -126,13 +150,15 @@ final class CommentPresenter extends OpenVKPresenter
|
|||
$comment = (new Comments)->get($id);
|
||||
if(!$comment) $this->notFound();
|
||||
if(!$comment->canBeDeletedBy($this->user->identity))
|
||||
$this->throwError(403, "Forbidden", "У вас недостаточно прав чтобы редактировать этот ресурс.");
|
||||
|
||||
$this->throwError(403, "Forbidden", tr("error_access_denied"));
|
||||
if ($comment->getTarget() instanceof Post && $comment->getTarget()->getWallOwner()->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
$comment->delete();
|
||||
$this->flashFail(
|
||||
"succ",
|
||||
"Успешно",
|
||||
"Этот комментарий больше не будет показыватся.<br/><a href='/al_comments/spam?$id'>Отметить как спам</a>?"
|
||||
tr("success"),
|
||||
tr("comment_will_not_appear")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ final class GiftsPresenter extends OpenVKPresenter
|
|||
$user = $this->users->get((int) ($this->queryParam("user") ?? 0));
|
||||
$cat = $this->gifts->getCat((int) ($this->queryParam("pack") ?? 0));
|
||||
if(!$user || !$cat)
|
||||
$this->flashFail("err", "Не удалось подарить", "Пользователь или набор не существуют.");
|
||||
$this->flashFail("err", tr("error_when_gifting"), tr("error_user_not_exists"));
|
||||
|
||||
$this->template->page = $page = (int) ($this->queryParam("p") ?? 1);
|
||||
$gifts = $cat->getGifts($page, null, $this->template->count);
|
||||
|
@ -66,14 +66,14 @@ final class GiftsPresenter extends OpenVKPresenter
|
|||
$gift = $this->gifts->get((int) ($this->queryParam("elid") ?? 0));
|
||||
$cat = $this->gifts->getCat((int) ($this->queryParam("pack") ?? 0));
|
||||
if(!$user || !$cat || !$gift || !$cat->hasGift($gift))
|
||||
$this->flashFail("err", "Не удалось подарить", "Не удалось подтвердить права на подарок.");
|
||||
$this->flashFail("err", tr("error_when_gifting"), tr("error_no_rights_gifts"));
|
||||
|
||||
if(!$gift->canUse($this->user->identity))
|
||||
$this->flashFail("err", "Не удалось подарить", "У вас больше не осталось таких подарков.");
|
||||
$this->flashFail("err", tr("error_when_gifting"), tr("error_no_more_gifts"));
|
||||
|
||||
$coinsLeft = $this->user->identity->getCoins() - $gift->getPrice();
|
||||
if($coinsLeft < 0)
|
||||
$this->flashFail("err", "Не удалось подарить", "Ору нищ не пук.");
|
||||
$this->flashFail("err", tr("error_when_gifting"), tr("error_no_money"));
|
||||
|
||||
$this->template->_template = "Gifts/Confirm.xml";
|
||||
if($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
|
@ -91,7 +91,7 @@ final class GiftsPresenter extends OpenVKPresenter
|
|||
$user->gift($this->user->identity, $gift, $comment, !is_null($this->postParam("anonymous")));
|
||||
$gift->used();
|
||||
|
||||
$this->flash("succ", "Подарок отправлен", "Вы отправили подарок <b>" . $user->getFirstName() . "</b> за " . $gift->getPrice() . " голосов.");
|
||||
$this->flash("succ", tr("gift_sent"), tr("gift_sent_desc", $user->getFirstName(), $gift->getPrice()));
|
||||
$this->redirect($user->getURL());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Presenters;
|
||||
use openvk\Web\Models\Entities\{Club, Photo};
|
||||
use openvk\Web\Models\Entities\{Club, Photo, Post};
|
||||
use Nette\InvalidStateException;
|
||||
use openvk\Web\Models\Entities\Notifications\ClubModeratorNotification;
|
||||
use openvk\Web\Models\Repositories\{Clubs, Users, Albums, Managers, Topics};
|
||||
|
@ -24,10 +24,14 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
if(!$club) {
|
||||
$this->notFound();
|
||||
} else {
|
||||
$this->template->albums = (new Albums)->getClubAlbums($club, 1, 3);
|
||||
$this->template->albumsCount = (new Albums)->getClubAlbumsCount($club);
|
||||
$this->template->topics = (new Topics)->getLastTopics($club, 3);
|
||||
$this->template->topicsCount = (new Topics)->getClubTopicsCount($club);
|
||||
if ($club->isBanned()) {
|
||||
$this->template->_template = "Group/Banned.xml";
|
||||
} else {
|
||||
$this->template->albums = (new Albums)->getClubAlbums($club, 1, 3);
|
||||
$this->template->albumsCount = (new Albums)->getClubAlbumsCount($club);
|
||||
$this->template->topics = (new Topics)->getLastTopics($club, 3);
|
||||
$this->template->topicsCount = (new Topics)->getClubTopicsCount($club);
|
||||
}
|
||||
|
||||
$this->template->club = $club;
|
||||
}
|
||||
|
@ -39,7 +43,7 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$this->willExecuteWriteAction();
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
if(!empty($this->postParam("name")))
|
||||
if(!empty($this->postParam("name")) && mb_strlen(trim($this->postParam("name"))) > 0)
|
||||
{
|
||||
$club = new Club;
|
||||
$club->setName($this->postParam("name"));
|
||||
|
@ -50,7 +54,7 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$club->save();
|
||||
} catch(\PDOException $ex) {
|
||||
if($ex->getCode() == 23000)
|
||||
$this->flashFail("err", "Ошибка", "Произошла ошибка на стороне сервера. Обратитесь к системному администратору.");
|
||||
$this->flashFail("err", tr("error"), tr("error_on_server_side"));
|
||||
else
|
||||
throw $ex;
|
||||
}
|
||||
|
@ -58,7 +62,7 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$club->toggleSubscription($this->user->identity);
|
||||
$this->redirect("/club" . $club->getId());
|
||||
}else{
|
||||
$this->flashFail("err", "Ошибка", "Вы не ввели название группы.");
|
||||
$this->flashFail("err", tr("error"), tr("error_no_group_name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,6 +76,7 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
|
||||
$club = $this->clubs->get((int) $this->postParam("id"));
|
||||
if(!$club) exit("Invalid state");
|
||||
if ($club->isBanned()) $this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
$club->toggleSubscription($this->user->identity);
|
||||
|
||||
|
@ -83,6 +88,8 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$this->assertUserLoggedIn();
|
||||
|
||||
$this->template->club = $this->clubs->get($id);
|
||||
if ($this->template->club->isBanned()) $this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
$this->template->onlyShowManagers = $this->queryParam("onlyAdmins") == "1";
|
||||
if($this->template->onlyShowManagers) {
|
||||
$this->template->followers = NULL;
|
||||
|
@ -118,12 +125,14 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$this->badRequest();
|
||||
|
||||
$club = $this->clubs->get($id);
|
||||
if ($club->isBanned()) $this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
$user = (new Users)->get((int) $user);
|
||||
if(!$user || !$club)
|
||||
$this->notFound();
|
||||
|
||||
if(!$club->canBeModifiedBy($this->user->identity ?? NULL))
|
||||
$this->flashFail("err", "Ошибка доступа", "У вас недостаточно прав, чтобы изменять этот ресурс.");
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
|
||||
if(!is_null($hidden)) {
|
||||
if($club->getOwner()->getId() == $user->getId()) {
|
||||
|
@ -141,9 +150,9 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
if($hidden) {
|
||||
$this->flashFail("succ", "Операция успешна", "Теперь " . $user->getCanonicalName() . " будет показываться как обычный подписчик всем кроме других администраторов");
|
||||
$this->flashFail("succ", tr("success_action"), tr("x_is_now_hidden", $user->getCanonicalName()));
|
||||
} else {
|
||||
$this->flashFail("succ", "Операция успешна", "Теперь все будут знать про то что " . $user->getCanonicalName() . " - администратор");
|
||||
$this->flashFail("succ", tr("success_action"), tr("x_is_now_showed", $user->getCanonicalName()));
|
||||
}
|
||||
} elseif($removeComment) {
|
||||
if($club->getOwner()->getId() == $user->getId()) {
|
||||
|
@ -155,11 +164,11 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$manager->save();
|
||||
}
|
||||
|
||||
$this->flashFail("succ", "Операция успешна", "Комментарий к администратору удален");
|
||||
$this->flashFail("succ", tr("success_action"), tr("comment_is_deleted"));
|
||||
} elseif($comment) {
|
||||
if(mb_strlen($comment) > 36) {
|
||||
$commentLength = (string) mb_strlen($comment);
|
||||
$this->flashFail("err", "Ошибка", "Комментарий слишком длинный ($commentLength символов вместо 36 символов)");
|
||||
$this->flashFail("err", tr("error"), tr("comment_is_too_long", $commentLength));
|
||||
}
|
||||
|
||||
if($club->getOwner()->getId() == $user->getId()) {
|
||||
|
@ -171,16 +180,16 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$manager->save();
|
||||
}
|
||||
|
||||
$this->flashFail("succ", "Операция успешна", "Комментарий к администратору изменён");
|
||||
$this->flashFail("succ", tr("success_action"), tr("comment_is_changed"));
|
||||
}else{
|
||||
if($club->canBeModifiedBy($user)) {
|
||||
$club->removeManager($user);
|
||||
$this->flashFail("succ", "Операция успешна", $user->getCanonicalName() . " более не администратор.");
|
||||
$this->flashFail("succ", tr("success_action"), tr("x_no_more_admin", $user->getCanonicalName()));
|
||||
} else {
|
||||
$club->addManager($user);
|
||||
|
||||
(new ClubModeratorNotification($user, $club, $this->user->identity))->emit();
|
||||
$this->flashFail("succ", "Операция успешна", $user->getCanonicalName() . " назначен(а) администратором.");
|
||||
$this->flashFail("succ", tr("success_action"), tr("x_is_admin", $user->getCanonicalName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,6 +203,8 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$club = $this->clubs->get($id);
|
||||
if(!$club || !$club->canBeModifiedBy($this->user->identity))
|
||||
$this->notFound();
|
||||
else if ($club->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
else
|
||||
$this->template->club = $club;
|
||||
|
||||
|
@ -201,7 +212,7 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
if(!$club->setShortcode( empty($this->postParam("shortcode")) ? NULL : $this->postParam("shortcode") ))
|
||||
$this->flashFail("err", tr("error"), tr("error_shorturl_incorrect"));
|
||||
|
||||
$club->setName(empty($this->postParam("name")) ? $club->getName() : $this->postParam("name"));
|
||||
$club->setName((empty($this->postParam("name")) || mb_strlen(trim($this->postParam("name"))) === 0) ? $club->getName() : $this->postParam("name"));
|
||||
$club->setAbout(empty($this->postParam("about")) ? NULL : $this->postParam("about"));
|
||||
$club->setWall(empty($this->postParam("wall")) ? 0 : 1);
|
||||
$club->setAdministrators_List_Display(empty($this->postParam("administrators_list_display")) ? 0 : $this->postParam("administrators_list_display"));
|
||||
|
@ -234,7 +245,7 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
(new Albums)->getClubAvatarAlbum($club)->addPhoto($photo);
|
||||
} catch(ISE $ex) {
|
||||
$name = $album->getName();
|
||||
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию.");
|
||||
$this->flashFail("err", tr("error"), tr("error_when_uploading_photo"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,15 +253,59 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$club->save();
|
||||
} catch(\PDOException $ex) {
|
||||
if($ex->getCode() == 23000)
|
||||
$this->flashFail("err", "Ошибка", "Произошла ошибка на стороне сервера. Обратитесь к системному администратору.");
|
||||
$this->flashFail("err", tr("error"), tr("error_on_server_side"));
|
||||
else
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$this->flash("succ", "Изменения сохранены", "Новые данные появятся в вашей группе.");
|
||||
$this->flash("succ", tr("changes_saved"), tr("new_changes_desc"));
|
||||
}
|
||||
}
|
||||
|
||||
function renderSetAvatar(int $id)
|
||||
{
|
||||
$photo = new Photo;
|
||||
$club = $this->clubs->get($id);
|
||||
if ($club->isBanned()) $this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST" && $_FILES["ava"]["error"] === UPLOAD_ERR_OK) {
|
||||
try {
|
||||
$anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
|
||||
if($anon && $this->user->id === $club->getOwner()->getId())
|
||||
$anon = $club->isOwnerHidden();
|
||||
else if($anon)
|
||||
$anon = $club->getManager($this->user->identity)->isHidden();
|
||||
$photo->setOwner($this->user->id);
|
||||
$photo->setDescription("Club image");
|
||||
$photo->setFile($_FILES["ava"]);
|
||||
$photo->setCreated(time());
|
||||
$photo->setAnonymous($anon);
|
||||
$photo->save();
|
||||
|
||||
(new Albums)->getClubAvatarAlbum($club)->addPhoto($photo);
|
||||
|
||||
$flags = 0;
|
||||
$flags |= 0b00010000;
|
||||
$flags |= 0b10000000;
|
||||
|
||||
$post = new Post;
|
||||
$post->setOwner($this->user->id);
|
||||
$post->setWall($club->getId()*-1);
|
||||
$post->setCreated(time());
|
||||
$post->setContent("");
|
||||
$post->setFlags($flags);
|
||||
$post->save();
|
||||
$post->attach($photo);
|
||||
|
||||
} catch(ISE $ex) {
|
||||
$name = $album->getName();
|
||||
$this->flashFail("err", tr("error"), tr("error_when_uploading_photo"));
|
||||
}
|
||||
}
|
||||
$this->returnJson([
|
||||
"url" => $photo->getURL(),
|
||||
"id" => $photo->getPrettyId()
|
||||
]);
|
||||
}
|
||||
function renderEditBackdrop(int $id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
|
@ -295,11 +350,13 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$this->assertUserLoggedIn();
|
||||
|
||||
if(!eventdb())
|
||||
$this->flashFail("err", "Ошибка подключения", "Не удалось подключится к службе телеметрии.");
|
||||
$this->flashFail("err", tr("connection_error"), tr("connection_error_desc"));
|
||||
|
||||
$club = $this->clubs->get($id);
|
||||
if(!$club->canBeModifiedBy($this->user->identity))
|
||||
$this->notFound();
|
||||
else if ($club->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
else
|
||||
$this->template->club = $club;
|
||||
|
||||
|
@ -332,6 +389,7 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$this->flashFail("err", tr("error"), tr("incorrect_password"));
|
||||
|
||||
$club = $this->clubs->get($id);
|
||||
if ($club->isBanned()) $this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
$newOwner = (new Users)->get($newOwnerId);
|
||||
if($this->user->id !== $club->getOwner()->getId())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
|
384
Web/Presenters/NoSpamPresenter.php
Normal file
384
Web/Presenters/NoSpamPresenter.php
Normal file
|
@ -0,0 +1,384 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
namespace openvk\Web\Presenters;
|
||||
|
||||
use Nette\Database\DriverException;
|
||||
use Nette\Utils\Finder;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use openvk\Web\Models\Entities\Club;
|
||||
use openvk\Web\Models\Entities\Comment;
|
||||
use Chandler\Database\Log;
|
||||
use openvk\Web\Models\Entities\NoSpamLog;
|
||||
use openvk\Web\Models\Entities\User;
|
||||
use openvk\Web\Models\Repositories\ChandlerUsers;
|
||||
use Chandler\Database\Logs;
|
||||
use openvk\Web\Models\Repositories\NoSpamLogs;
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
|
||||
final class NoSpamPresenter extends OpenVKPresenter
|
||||
{
|
||||
protected $banTolerant = true;
|
||||
protected $deactivationTolerant = true;
|
||||
protected $presenterName = "nospam";
|
||||
|
||||
const ENTITIES_NAMESPACE = "openvk\\Web\\Models\\Entities";
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function renderIndex(): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->assertPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0);
|
||||
|
||||
$targetDir = __DIR__ . '/../Models/Entities/';
|
||||
$mode = in_array($this->queryParam("act"), ["form", "templates", "rollback", "reports"]) ? $this->queryParam("act") : "form";
|
||||
|
||||
if ($mode === "form") {
|
||||
$this->template->_template = "NoSpam/Index";
|
||||
$foundClasses = [];
|
||||
foreach (Finder::findFiles('*.php')->from($targetDir) as $file) {
|
||||
$content = file_get_contents($file->getPathname());
|
||||
$namespacePattern = '/namespace\s+([^\s;]+)/';
|
||||
$classPattern = '/class\s+([^\s{]+)/';
|
||||
preg_match($namespacePattern, $content, $namespaceMatches);
|
||||
preg_match($classPattern, $content, $classMatches);
|
||||
|
||||
if (isset($namespaceMatches[1]) && isset($classMatches[1])) {
|
||||
$classNamespace = trim($namespaceMatches[1]);
|
||||
$className = trim($classMatches[1]);
|
||||
$fullClassName = $classNamespace . '\\' . $className;
|
||||
|
||||
if ($classNamespace === NoSpamPresenter::ENTITIES_NAMESPACE && class_exists($fullClassName)) {
|
||||
$foundClasses[] = $className;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$models = [];
|
||||
|
||||
foreach ($foundClasses as $class) {
|
||||
$r = new \ReflectionClass(NoSpamPresenter::ENTITIES_NAMESPACE . "\\$class");
|
||||
if (!$r->isAbstract() && $r->getName() !== NoSpamPresenter::ENTITIES_NAMESPACE . "\\Correspondence")
|
||||
$models[] = $class;
|
||||
}
|
||||
$this->template->models = $models;
|
||||
} else if ($mode === "templates") {
|
||||
$this->template->_template = "NoSpam/Templates.xml";
|
||||
$filter = [];
|
||||
if ($this->queryParam("id")) {
|
||||
$filter["id"] = (int)$this->queryParam("id");
|
||||
}
|
||||
$this->template->templates = iterator_to_array((new NoSpamLogs)->getList($filter));
|
||||
} else if ($mode === "reports") {
|
||||
$this->redirect("/scumfeed");
|
||||
} else {
|
||||
$template = (new NoSpamLogs)->get((int)$this->postParam("id"));
|
||||
if (!$template || $template->isRollbacked())
|
||||
$this->returnJson(["success" => false, "error" => "Шаблон не найден"]);
|
||||
|
||||
$model = NoSpamPresenter::ENTITIES_NAMESPACE . "\\" . $template->getModel();
|
||||
$items = $template->getItems();
|
||||
if (count($items) > 0) {
|
||||
$db = DatabaseConnection::i()->getContext();
|
||||
|
||||
$unbanned_ids = [];
|
||||
foreach ($items as $_item) {
|
||||
try {
|
||||
$item = new $model;
|
||||
$table_name = $item->getTableName();
|
||||
$item = $db->table($table_name)->get((int)$_item);
|
||||
if (!$item) continue;
|
||||
|
||||
$item = new $model($item);
|
||||
|
||||
if (key_exists("deleted", $item->unwrap()) && $item->isDeleted()) {
|
||||
$item->setDeleted(0);
|
||||
$item->save();
|
||||
}
|
||||
|
||||
if (in_array($template->getTypeRaw(), [2, 3])) {
|
||||
$owner = NULL;
|
||||
$methods = ["getOwner", "getUser", "getRecipient", "getInitiator"];
|
||||
|
||||
if (method_exists($item, "ban")) {
|
||||
$owner = $item;
|
||||
} else {
|
||||
foreach ($methods as $method) {
|
||||
if (method_exists($item, $method)) {
|
||||
$owner = $item->$method();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$_id = ($owner instanceof Club ? $owner->getId() * -1 : $owner->getId());
|
||||
|
||||
if (!in_array($_id, $unbanned_ids)) {
|
||||
$owner->unban($this->user->id);
|
||||
$unbanned_ids[] = $_id;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$this->returnJson(["success" => false, "error" => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->returnJson(["success" => false, "error" => "Объекты не найдены"]);
|
||||
}
|
||||
|
||||
$template->setRollback(true);
|
||||
$template->save();
|
||||
|
||||
$this->returnJson(["success" => true]);
|
||||
}
|
||||
}
|
||||
|
||||
function renderSearch(): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->assertPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0);
|
||||
$this->assertNoCSRF();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
function searchByAdditionalParams(?string $table = NULL, ?string $where = NULL, ?string $ip = NULL, ?string $useragent = NULL, ?int $ts = NULL, ?int $te = NULL, $user = NULL)
|
||||
{
|
||||
$db = DatabaseConnection::i()->getContext();
|
||||
if ($table && ($ip || $useragent || $ts || $te || $user)) {
|
||||
$conditions = [];
|
||||
|
||||
if ($ip) $conditions[] = "`ip` REGEXP '$ip'";
|
||||
if ($useragent) $conditions[] = "`useragent` REGEXP '$useragent'";
|
||||
if ($ts) $conditions[] = "`ts` < $ts";
|
||||
if ($te) $conditions[] = "`ts` > $te";
|
||||
if ($user) {
|
||||
$users = new Users;
|
||||
|
||||
$_user = $users->getByChandlerUser((new ChandlerUsers)->getById($user))
|
||||
?? $users->get((int)$user)
|
||||
?? $users->getByAddress($user)
|
||||
?? NULL;
|
||||
|
||||
if ($_user) {
|
||||
$conditions[] = "`user` = '" . $_user->getChandlerGUID() . "'";
|
||||
}
|
||||
}
|
||||
|
||||
$whereStart = "WHERE `object_table` = '$table'";
|
||||
if ($table === "profiles") {
|
||||
$whereStart .= "AND `type` = 0";
|
||||
}
|
||||
|
||||
$conditions = count($conditions) > 0 ? "AND (" . implode(" AND ", $conditions) . ")" : "";
|
||||
$response = [];
|
||||
|
||||
if ($conditions) {
|
||||
$logs = $db->query("SELECT * FROM `ChandlerLogs` $whereStart $conditions GROUP BY `object_id`, `object_model`");
|
||||
|
||||
foreach ($logs as $log) {
|
||||
$log = (new Logs)->get($log->id);
|
||||
$object = $log->getObject()->unwrap();
|
||||
|
||||
if (!$object) continue;
|
||||
if ($where) {
|
||||
if (str_starts_with($where, " AND")) {
|
||||
$where = substr_replace($where, "", 0, strlen(" AND"));
|
||||
}
|
||||
|
||||
$a = $db->query("SELECT * FROM `$table` WHERE $where")->fetchAll();
|
||||
foreach ($a as $o) {
|
||||
if ($object->id == $o["id"]) {
|
||||
$response[] = $object;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$response[] = $object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$response = [];
|
||||
$processed = 0;
|
||||
|
||||
$where = $this->postParam("where");
|
||||
$ip = addslashes($this->postParam("ip"));
|
||||
$useragent = addslashes($this->postParam("useragent"));
|
||||
$searchTerm = addslashes($this->postParam("q"));
|
||||
$ts = (int)$this->postParam("ts");
|
||||
$te = (int)$this->postParam("te");
|
||||
$user = addslashes($this->postParam("user"));
|
||||
|
||||
if ($where) {
|
||||
$where = explode(";", $where)[0];
|
||||
}
|
||||
|
||||
if (!$ip && !$useragent && !$searchTerm && !$ts && !$te && !$where && !$searchTerm && !$user)
|
||||
$this->returnJson(["success" => false, "error" => "Нет запроса. Заполните поле \"подстрока\" или введите запрос \"WHERE\" в поле под ним."]);
|
||||
|
||||
$models = explode(",", $this->postParam("models"));
|
||||
|
||||
foreach ($models as $_model) {
|
||||
$model_name = NoSpamPresenter::ENTITIES_NAMESPACE . "\\" . $_model;
|
||||
if (!class_exists($model_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$model = new $model_name;
|
||||
|
||||
$c = new \ReflectionClass($model_name);
|
||||
if ($c->isAbstract() || $c->getName() == NoSpamPresenter::ENTITIES_NAMESPACE . "\\Correspondence") {
|
||||
continue;
|
||||
}
|
||||
|
||||
$db = DatabaseConnection::i()->getContext();
|
||||
$table = $model->getTableName();
|
||||
$columns = $db->getStructure()->getColumns($table);
|
||||
|
||||
if ($searchTerm) {
|
||||
$conditions = [];
|
||||
$need_deleted = false;
|
||||
foreach ($columns as $column) {
|
||||
if ($column["name"] == "deleted") {
|
||||
$need_deleted = true;
|
||||
} else {
|
||||
$conditions[] = "`$column[name]` REGEXP '$searchTerm'";
|
||||
}
|
||||
}
|
||||
$conditions = implode(" OR ", $conditions);
|
||||
|
||||
$where = ($this->postParam("where") ? " AND ($conditions)" : "($conditions)");
|
||||
if ($need_deleted) $where .= " AND (`deleted` = 0)";
|
||||
}
|
||||
|
||||
$rows = [];
|
||||
|
||||
if (str_starts_with($where, " AND")) {
|
||||
if ($searchTerm && !$this->postParam("where")) {
|
||||
$where = substr_replace($where, "", 0, strlen(" AND"));
|
||||
} else {
|
||||
$where = "(" . $this->postParam("where") . ")" . $where;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ip || $useragent || $ts || $te || $user) {
|
||||
$rows = searchByAdditionalParams($table, $where, $ip, $useragent, $ts, $te, $user);
|
||||
} else {
|
||||
if (!$where) {
|
||||
$rows = [];
|
||||
} else {
|
||||
$result = $db->query("SELECT * FROM `$table` WHERE $where");
|
||||
$rows = $result->fetchAll();
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_array((int)$this->postParam("ban"), [1, 2, 3])) {
|
||||
foreach ($rows as $key => $object) {
|
||||
$object = (array)$object;
|
||||
$_obj = [];
|
||||
foreach ($object as $key => $value) {
|
||||
foreach ($columns as $column) {
|
||||
if ($column["name"] === $key && in_array(strtoupper($column["nativetype"]), ["BLOB", "BINARY", "VARBINARY", "TINYBLOB", "MEDIUMBLOB", "LONGBLOB"])) {
|
||||
$value = "[BINARY]";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$_obj[$key] = $value;
|
||||
$_obj["__model_name"] = $_model;
|
||||
}
|
||||
$response[] = $_obj;
|
||||
}
|
||||
} else {
|
||||
$ids = [];
|
||||
|
||||
foreach ($rows as $object) {
|
||||
$object = new $model_name($db->table($table)->get($object->id));
|
||||
if (!$object) continue;
|
||||
$ids[] = $object->getId();
|
||||
}
|
||||
|
||||
$log = new NoSpamLog;
|
||||
$log->setUser($this->user->id);
|
||||
$log->setModel($_model);
|
||||
if ($searchTerm) {
|
||||
$log->setRegex($searchTerm);
|
||||
} else {
|
||||
$log->setRequest($where);
|
||||
}
|
||||
$log->setBan_Type((int)$this->postParam("ban"));
|
||||
$log->setCount(count($rows));
|
||||
$log->setTime(time());
|
||||
$log->setItems(implode(",", $ids));
|
||||
$log->save();
|
||||
|
||||
$banned_ids = [];
|
||||
foreach ($rows as $object) {
|
||||
$object = new $model_name($db->table($table)->get($object->id));
|
||||
if (!$object) continue;
|
||||
|
||||
$owner = NULL;
|
||||
$methods = ["getOwner", "getUser", "getRecipient", "getInitiator"];
|
||||
|
||||
if (method_exists($object, "ban")) {
|
||||
$owner = $object;
|
||||
} else {
|
||||
foreach ($methods as $method) {
|
||||
if (method_exists($object, $method)) {
|
||||
$owner = $object->$method();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($owner instanceof User && $owner->getId() === $this->user->id) {
|
||||
if (count($rows) === 1) {
|
||||
$this->returnJson(["success" => false, "error" => "\"Производственная травма\" — Вы не можете блокировать или удалять свой же контент"]);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array((int)$this->postParam("ban"), [2, 3])) {
|
||||
$reason = mb_strlen(trim($this->postParam("ban_reason"))) > 0 ? addslashes($this->postParam("ban_reason")) : ("**content-noSpamTemplate-" . $log->getId() . "**");
|
||||
$is_forever = (string)$this->postParam("is_forever") === "true";
|
||||
$unban_time = $is_forever ? 0 : (int)$this->postParam("unban_time") ?? NULL;
|
||||
|
||||
if ($owner) {
|
||||
$_id = ($owner instanceof Club ? $owner->getId() * -1 : $owner->getId());
|
||||
if (!in_array($_id, $banned_ids)) {
|
||||
if ($owner instanceof User) {
|
||||
if (!$unban_time && !$is_forever)
|
||||
$unban_time = time() + $owner->getNewBanTime();
|
||||
|
||||
$owner->ban($reason, false, $unban_time, $this->user->id);
|
||||
} else {
|
||||
$owner->ban("Подозрительная активность");
|
||||
}
|
||||
|
||||
$banned_ids[] = $_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array((int)$this->postParam("ban"), [1, 3]))
|
||||
$object->delete();
|
||||
}
|
||||
|
||||
$processed++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->returnJson(["success" => true, "processed" => $processed, "count" => count($response), "list" => $response]);
|
||||
} catch (\Throwable $e) {
|
||||
$this->returnJson(["success" => false, "error" => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -107,7 +107,7 @@ final class NotesPresenter extends OpenVKPresenter
|
|||
if(!$note || $note->getOwner()->getId() !== $owner || $note->isDeleted())
|
||||
$this->notFound();
|
||||
if(is_null($this->user) || !$note->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
$this->template->note = $note;
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
|
@ -135,11 +135,11 @@ final class NotesPresenter extends OpenVKPresenter
|
|||
if(!$note) $this->notFound();
|
||||
if($note->getOwner()->getId() . "_" . $note->getId() !== $owner . "_" . $id || $note->isDeleted()) $this->notFound();
|
||||
if(is_null($this->user) || !$note->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
|
||||
$name = $note->getName();
|
||||
$note->delete();
|
||||
$this->flash("succ", "Заметка удалена", "Заметка \"$name\" была успешно удалена.");
|
||||
$this->flash("succ", tr("note_is_deleted"), tr("note_x_is_now_deleted", $name));
|
||||
$this->redirect("/notes" . $this->user->id);
|
||||
}
|
||||
}
|
||||
|
|
9
Web/Presenters/OpenVKPresenter.php
Executable file → Normal file
9
Web/Presenters/OpenVKPresenter.php
Executable file → Normal file
|
@ -7,7 +7,7 @@ use Chandler\Security\Authenticator;
|
|||
use Latte\Engine as TemplatingEngine;
|
||||
use openvk\Web\Models\Entities\IP;
|
||||
use openvk\Web\Themes\Themepacks;
|
||||
use openvk\Web\Models\Repositories\{IPs, Users, APITokens, Tickets};
|
||||
use openvk\Web\Models\Repositories\{IPs, Users, APITokens, Tickets, Reports, CurrentUser};
|
||||
use WhichBrowser;
|
||||
|
||||
abstract class OpenVKPresenter extends SimplePresenter
|
||||
|
@ -211,6 +211,7 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
$this->user->id = $this->user->identity->getId();
|
||||
$this->template->thisUser = $this->user->identity;
|
||||
$this->template->userTainted = $user->isTainted();
|
||||
CurrentUser::get($this->user->identity, $_SERVER["REMOTE_ADDR"], $_SERVER["HTTP_USER_AGENT"]);
|
||||
|
||||
if($this->user->identity->isDeleted() && !$this->deactivationTolerant) {
|
||||
if($this->user->identity->isDeactivated()) {
|
||||
|
@ -255,12 +256,14 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
if($this->user->identity->onlineStatus() == 0 && !($this->user->identity->isDeleted() || $this->user->identity->isBanned())) {
|
||||
$this->user->identity->setOnline(time());
|
||||
$this->user->identity->setClient_name(NULL);
|
||||
$this->user->identity->save();
|
||||
$this->user->identity->save(false);
|
||||
}
|
||||
|
||||
$this->template->ticketAnsweredCount = (new Tickets)->getTicketsCountByUserId($this->user->id, 1);
|
||||
if($user->can("write")->model("openvk\Web\Models\Entities\TicketReply")->whichBelongsTo(0))
|
||||
if($user->can("write")->model("openvk\Web\Models\Entities\TicketReply")->whichBelongsTo(0)) {
|
||||
$this->template->helpdeskTicketNotAnsweredCount = (new Tickets)->getTicketCount(0);
|
||||
$this->template->reportNotAnsweredCount = (new Reports)->getReportsCount(0);
|
||||
}
|
||||
}
|
||||
|
||||
header("X-OpenVK-User-Validated: $userValidated");
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Presenters;
|
||||
use openvk\Web\Models\Entities\{Club, Photo, Album};
|
||||
use openvk\Web\Models\Entities\{Club, Photo, Album, User};
|
||||
use openvk\Web\Models\Repositories\{Photos, Albums, Users, Clubs};
|
||||
use Nette\InvalidStateException as ISE;
|
||||
|
||||
|
@ -27,7 +27,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
if(!$user) $this->notFound();
|
||||
if (!$user->getPrivacyPermission('photos.read', $this->user->identity ?? NULL))
|
||||
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
|
||||
$this->template->albums = $this->albums->getUserAlbums($user, $this->queryParam("p") ?? 1);
|
||||
$this->template->albums = $this->albums->getUserAlbums($user, (int)($this->queryParam("p") ?? 1));
|
||||
$this->template->count = $this->albums->getUserAlbumsCount($user);
|
||||
$this->template->owner = $user;
|
||||
$this->template->canEdit = false;
|
||||
|
@ -36,7 +36,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
} else {
|
||||
$club = (new Clubs)->get(abs($owner));
|
||||
if(!$club) $this->notFound();
|
||||
$this->template->albums = $this->albums->getClubAlbums($club, $this->queryParam("p") ?? 1);
|
||||
$this->template->albums = $this->albums->getClubAlbums($club, (int)($this->queryParam("p") ?? 1));
|
||||
$this->template->count = $this->albums->getClubAlbumsCount($club);
|
||||
$this->template->owner = $club;
|
||||
$this->template->canEdit = false;
|
||||
|
@ -46,7 +46,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
|
||||
$this->template->paginatorConf = (object) [
|
||||
"count" => $this->template->count,
|
||||
"page" => $this->queryParam("p") ?? 1,
|
||||
"page" => (int)($this->queryParam("p") ?? 1),
|
||||
"amount" => NULL,
|
||||
"perPage" => OPENVK_DEFAULT_PER_PAGE,
|
||||
];
|
||||
|
@ -66,7 +66,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
if(empty($this->postParam("name")))
|
||||
if(empty($this->postParam("name")) || mb_strlen(trim($this->postParam("name"))) === 0)
|
||||
$this->flashFail("err", tr("error"), tr("error_segmentation"));
|
||||
else if(strlen($this->postParam("name")) > 36)
|
||||
$this->flashFail("err", tr("error"), tr("error_data_too_big", "name", 36, "bytes"));
|
||||
|
@ -94,19 +94,19 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
if(!$album) $this->notFound();
|
||||
if($album->getPrettyId() !== $owner . "_" . $id || $album->isDeleted()) $this->notFound();
|
||||
if(is_null($this->user) || !$album->canBeModifiedBy($this->user->identity) || $album->isDeleted())
|
||||
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
$this->template->album = $album;
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
if(strlen($this->postParam("name")) > 36)
|
||||
$this->flashFail("err", tr("error"), tr("error_data_too_big", "name", 36, "bytes"));
|
||||
|
||||
$album->setName(empty($this->postParam("name")) ? $album->getName() : $this->postParam("name"));
|
||||
$album->setName((empty($this->postParam("name")) || mb_strlen(trim($this->postParam("name"))) === 0) ? $album->getName() : $this->postParam("name"));
|
||||
$album->setDescription(empty($this->postParam("desc")) ? NULL : $this->postParam("desc"));
|
||||
$album->setEdited(time());
|
||||
$album->save();
|
||||
|
||||
$this->flash("succ", "Изменения сохранены", "Новые данные приняты.");
|
||||
$this->flash("succ", tr("changes_saved"), tr("new_data_accepted"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,13 +120,13 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
if(!$album) $this->notFound();
|
||||
if($album->getPrettyId() !== $owner . "_" . $id || $album->isDeleted()) $this->notFound();
|
||||
if(is_null($this->user) || !$album->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
|
||||
$name = $album->getName();
|
||||
$owner = $album->getOwner();
|
||||
$album->delete();
|
||||
|
||||
$this->flash("succ", "Альбом удалён", "Альбом $name был успешно удалён.");
|
||||
$this->flash("succ", tr("album_is_deleted"), tr("album_x_is_deleted", $name));
|
||||
$this->redirect("/albums" . ($owner instanceof Club ? "-" : "") . $owner->getId());
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
$this->template->photos = iterator_to_array( $album->getPhotos( (int) ($this->queryParam("p") ?? 1), 20) );
|
||||
$this->template->paginatorConf = (object) [
|
||||
"count" => $album->getPhotosCount(),
|
||||
"page" => $this->queryParam("p") ?? 1,
|
||||
"page" => (int)($this->queryParam("p") ?? 1),
|
||||
"amount" => sizeof($this->template->photos),
|
||||
"perPage" => 20,
|
||||
"atBottom" => true
|
||||
|
@ -205,13 +205,13 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
$photo = $this->photos->getByOwnerAndVID($ownerId, $photoId);
|
||||
if(!$photo) $this->notFound();
|
||||
if(is_null($this->user) || $this->user->id != $ownerId)
|
||||
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$photo->setDescription(empty($this->postParam("desc")) ? NULL : $this->postParam("desc"));
|
||||
$photo->save();
|
||||
|
||||
$this->flash("succ", "Изменения сохранены", "Обновлённое описание появится на странице с фоткой.");
|
||||
$this->flash("succ", tr("changes_saved"), tr("new_description_will_appear"));
|
||||
$this->redirect("/photo" . $photo->getPrettyId());
|
||||
}
|
||||
|
||||
|
@ -221,39 +221,74 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
function renderUploadPhoto(): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
$this->willExecuteWriteAction(true);
|
||||
|
||||
if(is_null($this->queryParam("album")))
|
||||
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в <b>DELETED</b>.");
|
||||
$this->flashFail("err", tr("error"), tr("error_adding_to_deleted"), 500, true);
|
||||
|
||||
[$owner, $id] = explode("_", $this->queryParam("album"));
|
||||
$album = $this->albums->get((int) $id);
|
||||
if(!$album)
|
||||
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в <b>DELETED</b>.");
|
||||
$this->flashFail("err", tr("error"), tr("error_adding_to_deleted"), 500, true);
|
||||
if(is_null($this->user) || !$album->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"), 500, true);
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
if(!isset($_FILES["blob"]))
|
||||
$this->flashFail("err", "Нету фотографии", "Выберите файл.");
|
||||
|
||||
try {
|
||||
$photo = new Photo;
|
||||
$photo->setOwner($this->user->id);
|
||||
$photo->setDescription($this->postParam("desc"));
|
||||
$photo->setFile($_FILES["blob"]);
|
||||
$photo->setCreated(time());
|
||||
$photo->save();
|
||||
} catch(ISE $ex) {
|
||||
$name = $album->getName();
|
||||
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в <b>$name</b>.");
|
||||
}
|
||||
|
||||
$album->addPhoto($photo);
|
||||
$album->setEdited(time());
|
||||
$album->save();
|
||||
if($this->queryParam("act") == "finish") {
|
||||
$result = json_decode($this->postParam("photos"), true);
|
||||
|
||||
foreach($result as $photoId => $description) {
|
||||
$phot = $this->photos->get($photoId);
|
||||
|
||||
$this->redirect("/photo" . $photo->getPrettyId() . "?from=album" . $album->getId());
|
||||
if(!$phot || $phot->isDeleted() || $phot->getOwner()->getId() != $this->user->id)
|
||||
continue;
|
||||
|
||||
if(iconv_strlen($description) > 255)
|
||||
$this->flashFail("err", tr("error"), tr("description_too_long"), 500, true);
|
||||
|
||||
$phot->setDescription($description);
|
||||
$phot->save();
|
||||
|
||||
$album = $phot->getAlbum();
|
||||
}
|
||||
|
||||
$this->returnJson(["success" => true,
|
||||
"album" => $album->getId(),
|
||||
"owner" => $album->getOwner() instanceof User ? $album->getOwner()->getId() : $album->getOwner()->getId() * -1]);
|
||||
}
|
||||
|
||||
if(!isset($_FILES))
|
||||
$this->flashFail("err", tr("no_photo"), tr("select_file"), 500, true);
|
||||
|
||||
$photos = [];
|
||||
for($i = 0; $i < $this->postParam("count"); $i++) {
|
||||
try {
|
||||
$photo = new Photo;
|
||||
$photo->setOwner($this->user->id);
|
||||
$photo->setDescription("");
|
||||
$photo->setFile($_FILES["photo_".$i]);
|
||||
$photo->setCreated(time());
|
||||
$photo->save();
|
||||
|
||||
$photos[] = [
|
||||
"url" => $photo->getURLBySizeId("tiny"),
|
||||
"id" => $photo->getId(),
|
||||
"vid" => $photo->getVirtualId(),
|
||||
"owner" => $photo->getOwner()->getId(),
|
||||
"link" => $photo->getURL()
|
||||
];
|
||||
} catch(ISE $ex) {
|
||||
$name = $album->getName();
|
||||
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в $name.", 500, true);
|
||||
}
|
||||
|
||||
$album->addPhoto($photo);
|
||||
$album->setEdited(time());
|
||||
$album->save();
|
||||
}
|
||||
|
||||
$this->returnJson(["success" => true,
|
||||
"photos" => $photos]);
|
||||
} else {
|
||||
$this->template->album = $album;
|
||||
}
|
||||
|
@ -269,7 +304,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
if(!$album || !$photo) $this->notFound();
|
||||
if(!$album->hasPhoto($photo)) $this->notFound();
|
||||
if(is_null($this->user) || !$album->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$this->assertNoCSRF();
|
||||
|
@ -277,7 +312,7 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
$album->setEdited(time());
|
||||
$album->save();
|
||||
|
||||
$this->flash("succ", "Фотография удалена", "Эта фотография была успешно удалена.");
|
||||
$this->flash("succ", tr("photo_is_deleted"), tr("photo_is_deleted_desc"));
|
||||
$this->redirect("/album" . $album->getPrettyId());
|
||||
}
|
||||
}
|
||||
|
@ -285,18 +320,23 @@ final class PhotosPresenter extends OpenVKPresenter
|
|||
function renderDeletePhoto(int $ownerId, int $photoId): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
$this->willExecuteWriteAction($_SERVER["REQUEST_METHOD"] === "POST");
|
||||
$this->assertNoCSRF();
|
||||
|
||||
$photo = $this->photos->getByOwnerAndVID($ownerId, $photoId);
|
||||
if(!$photo) $this->notFound();
|
||||
if(is_null($this->user) || $this->user->id != $ownerId)
|
||||
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
|
||||
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
|
||||
$redirect = $photo->getAlbum()->getOwner() instanceof User ? "/id0" : "/club" . $ownerId;
|
||||
|
||||
$photo->isolate();
|
||||
$photo->delete();
|
||||
|
||||
$this->flash("succ", "Фотография удалена", "Эта фотография была успешно удалена.");
|
||||
$this->redirect("/id0");
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST")
|
||||
$this->returnJson(["success" => true]);
|
||||
|
||||
$this->flash("succ", tr("photo_is_deleted"), tr("photo_is_deleted_desc"));
|
||||
$this->redirect($redirect);
|
||||
}
|
||||
}
|
||||
|
|
151
Web/Presenters/ReportPresenter.php
Normal file
151
Web/Presenters/ReportPresenter.php
Normal file
|
@ -0,0 +1,151 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Presenters;
|
||||
use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\Repositories\Reports;
|
||||
use openvk\Web\Models\Repositories\Posts;
|
||||
use openvk\Web\Models\Entities\Report;
|
||||
|
||||
final class ReportPresenter extends OpenVKPresenter
|
||||
{
|
||||
private $reports;
|
||||
|
||||
function __construct(Reports $reports)
|
||||
{
|
||||
$this->reports = $reports;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function renderList(): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->assertPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0);
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST")
|
||||
$this->assertNoCSRF();
|
||||
|
||||
$act = in_array($this->queryParam("act"), ["post", "photo", "video", "group", "comment", "note", "app", "user"]) ? $this->queryParam("act") : NULL;
|
||||
|
||||
if (!$this->queryParam("orig")) {
|
||||
$this->template->reports = $this->reports->getReports(0, (int)($this->queryParam("p") ?? 1), $act, $_SERVER["REQUEST_METHOD"] !== "POST");
|
||||
$this->template->count = $this->reports->getReportsCount();
|
||||
} else {
|
||||
$orig = $this->reports->get((int) $this->queryParam("orig"));
|
||||
if (!$orig) $this->redirect("/scumfeed");
|
||||
|
||||
$this->template->reports = $orig->getDuplicates();
|
||||
$this->template->count = $orig->getDuplicatesCount();
|
||||
$this->template->orig = $orig->getId();
|
||||
}
|
||||
$this->template->paginatorConf = (object) [
|
||||
"count" => $this->template->count,
|
||||
"page" => $this->queryParam("p") ?? 1,
|
||||
"amount" => NULL,
|
||||
"perPage" => 15,
|
||||
];
|
||||
$this->template->mode = $act ?? "all";
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$reports = [];
|
||||
foreach ($this->reports->getReports(0, 0, $act, false) as $report) {
|
||||
$reports[] = [
|
||||
"id" => $report->getId(),
|
||||
"author" => [
|
||||
"id" => $report->getReportAuthor()->getId(),
|
||||
"url" => $report->getReportAuthor()->getURL(),
|
||||
"name" => $report->getReportAuthor()->getCanonicalName(),
|
||||
"is_female" => $report->getReportAuthor()->isFemale()
|
||||
],
|
||||
"content" => [
|
||||
"name" => $report->getContentName(),
|
||||
"type" => $report->getContentType(),
|
||||
"id" => $report->getContentId(),
|
||||
"url" => $report->getContentType() === "user" ? (new Users)->get((int) $report->getContentId())->getURL() : NULL
|
||||
],
|
||||
"duplicates" => $report->getDuplicatesCount(),
|
||||
];
|
||||
}
|
||||
$this->returnJson(["reports" => $reports]);
|
||||
}
|
||||
}
|
||||
|
||||
function renderView(int $id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->assertPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0);
|
||||
|
||||
$report = $this->reports->get($id);
|
||||
if(!$report || $report->isDeleted())
|
||||
$this->notFound();
|
||||
|
||||
$this->template->report = $report;
|
||||
}
|
||||
|
||||
function renderCreate(int $id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if(!$id)
|
||||
exit(json_encode([ "error" => tr("error_segmentation") ]));
|
||||
|
||||
if(in_array($this->queryParam("type"), ["post", "photo", "video", "group", "comment", "note", "app", "user"])) {
|
||||
if (count(iterator_to_array($this->reports->getDuplicates($this->queryParam("type"), $id, NULL, $this->user->id))) <= 0) {
|
||||
$report = new Report;
|
||||
$report->setUser_id($this->user->id);
|
||||
$report->setTarget_id($id);
|
||||
$report->setType($this->queryParam("type"));
|
||||
$report->setReason($this->queryParam("reason"));
|
||||
$report->setCreated(time());
|
||||
$report->save();
|
||||
}
|
||||
|
||||
exit(json_encode([ "reason" => $this->queryParam("reason") ]));
|
||||
} else {
|
||||
exit(json_encode([ "error" => "Unable to submit a report on this content type" ]));
|
||||
}
|
||||
}
|
||||
|
||||
function renderAction(int $id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
$this->assertPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0);
|
||||
|
||||
$report = $this->reports->get($id);
|
||||
if(!$report || $report->isDeleted()) $this->notFound();
|
||||
|
||||
if ($this->postParam("ban")) {
|
||||
$report->deleteContent();
|
||||
$report->banUser($this->user->identity->getId());
|
||||
|
||||
$this->flash("suc", tr("death"), tr("user_successfully_banned"));
|
||||
} else if ($this->postParam("delete")) {
|
||||
$report->deleteContent();
|
||||
|
||||
$this->flash("suc", tr("nehay"), tr("content_is_deleted"));
|
||||
} else if ($this->postParam("ignore")) {
|
||||
$report->delete();
|
||||
|
||||
$this->flash("suc", tr("nehay"), tr("report_is_ignored"));
|
||||
} else if ($this->postParam("banClubOwner") || $this->postParam("banClub")) {
|
||||
if ($report->getContentType() !== "group")
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
|
||||
$club = $report->getContentObject();
|
||||
if (!$club || $club->isBanned())
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
|
||||
if ($this->postParam("banClubOwner")) {
|
||||
$club->getOwner()->ban("**content-" . $report->getContentType() . "-" . $report->getContentId() . "**", false, $club->getOwner()->getNewBanTime(), $this->user->identity->getId());
|
||||
} else {
|
||||
$club->ban("**content-" . $report->getContentType() . "-" . $report->getContentId() . "**");
|
||||
}
|
||||
|
||||
$report->delete();
|
||||
|
||||
$this->flash("suc", tr("death"), ($this->postParam("banClubOwner") ? tr("group_owner_is_banned") : tr("group_is_banned")));
|
||||
}
|
||||
|
||||
$this->redirect("/scumfeed");
|
||||
}
|
||||
}
|
|
@ -1,18 +1,28 @@
|
|||
<?php declare(strict_types=1);
|
||||
namespace openvk\Web\Presenters;
|
||||
use openvk\Web\Models\Entities\{User, Club};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs};
|
||||
use openvk\Web\Models\Repositories\{Users, Clubs, Posts, Comments, Videos, Applications, Notes};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
final class SearchPresenter extends OpenVKPresenter
|
||||
{
|
||||
private $users;
|
||||
private $clubs;
|
||||
private $posts;
|
||||
private $comments;
|
||||
private $videos;
|
||||
private $apps;
|
||||
private $notes;
|
||||
|
||||
function __construct(Users $users, Clubs $clubs)
|
||||
{
|
||||
$this->users = $users;
|
||||
$this->clubs = $clubs;
|
||||
$this->users = $users;
|
||||
$this->clubs = $clubs;
|
||||
$this->posts = new Posts;
|
||||
$this->comments = new Comments;
|
||||
$this->videos = new Videos;
|
||||
$this->apps = new Applications;
|
||||
$this->notes = new Notes;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
@ -21,6 +31,8 @@ final class SearchPresenter extends OpenVKPresenter
|
|||
{
|
||||
$query = $this->queryParam("query") ?? "";
|
||||
$type = $this->queryParam("type") ?? "users";
|
||||
$sorter = $this->queryParam("sort") ?? "id";
|
||||
$invert = $this->queryParam("invert") == 1 ? "ASC" : "DESC";
|
||||
$page = (int) ($this->queryParam("p") ?? 1);
|
||||
|
||||
$this->willExecuteWriteAction();
|
||||
|
@ -28,11 +40,58 @@ final class SearchPresenter extends OpenVKPresenter
|
|||
$this->assertUserLoggedIn();
|
||||
|
||||
# https://youtu.be/pSAWM5YuXx8
|
||||
|
||||
$repos = [ "groups" => "clubs", "users" => "users" ];
|
||||
|
||||
$repos = [
|
||||
"groups" => "clubs",
|
||||
"users" => "users",
|
||||
"posts" => "posts",
|
||||
"comments" => "comments",
|
||||
"videos" => "videos",
|
||||
"audios" => "posts",
|
||||
"apps" => "apps",
|
||||
"notes" => "notes"
|
||||
];
|
||||
|
||||
switch($sorter) {
|
||||
default:
|
||||
case "id":
|
||||
$sort = "id " . $invert;
|
||||
break;
|
||||
case "name":
|
||||
$sort = "first_name " . $invert;
|
||||
break;
|
||||
case "rating":
|
||||
$sort = "rating " . $invert;
|
||||
break;
|
||||
}
|
||||
|
||||
$parameters = [
|
||||
"type" => $this->queryParam("type"),
|
||||
"city" => $this->queryParam("city") != "" ? $this->queryParam("city") : NULL,
|
||||
"maritalstatus" => $this->queryParam("maritalstatus") != 0 ? $this->queryParam("maritalstatus") : NULL,
|
||||
"with_photo" => $this->queryParam("with_photo"),
|
||||
"status" => $this->queryParam("status") != "" ? $this->queryParam("status") : NULL,
|
||||
"politViews" => $this->queryParam("politViews") != 0 ? $this->queryParam("politViews") : NULL,
|
||||
"email" => $this->queryParam("email"),
|
||||
"telegram" => $this->queryParam("telegram"),
|
||||
"site" => $this->queryParam("site") != "" ? "https://".$this->queryParam("site") : NULL,
|
||||
"address" => $this->queryParam("address"),
|
||||
"is_online" => $this->queryParam("is_online") == 1 ? 1 : NULL,
|
||||
"interests" => $this->queryParam("interests") != "" ? $this->queryParam("interests") : NULL,
|
||||
"fav_mus" => $this->queryParam("fav_mus") != "" ? $this->queryParam("fav_mus") : NULL,
|
||||
"fav_films" => $this->queryParam("fav_films") != "" ? $this->queryParam("fav_films") : NULL,
|
||||
"fav_shows" => $this->queryParam("fav_shows") != "" ? $this->queryParam("fav_shows") : NULL,
|
||||
"fav_books" => $this->queryParam("fav_books") != "" ? $this->queryParam("fav_books") : NULL,
|
||||
"fav_quote" => $this->queryParam("fav_quote") != "" ? $this->queryParam("fav_quote") : NULL,
|
||||
"hometown" => $this->queryParam("hometown") != "" ? $this->queryParam("hometown") : NULL,
|
||||
"before" => $this->queryParam("datebefore") != "" ? strtotime($this->queryParam("datebefore")) : NULL,
|
||||
"after" => $this->queryParam("dateafter") != "" ? strtotime($this->queryParam("dateafter")) : NULL,
|
||||
"gender" => $this->queryParam("gender") != "" && $this->queryParam("gender") != 2 ? $this->queryParam("gender") : NULL
|
||||
];
|
||||
|
||||
$repo = $repos[$type] or $this->throwError(400, "Bad Request", "Invalid search entity $type.");
|
||||
|
||||
$results = $this->{$repo}->find($query);
|
||||
$results = $this->{$repo}->find($query, $parameters, $sort);
|
||||
$iterator = $results->page($page);
|
||||
$count = $results->size();
|
||||
|
||||
|
|
|
@ -385,7 +385,7 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$agent->setNumerate((int) $this->postParam("number") ?? NULL);
|
||||
$agent->setIcon($this->postParam("avatar"));
|
||||
$agent->save();
|
||||
$this->flashFail("succ", "Успех", "Профиль отредактирован.");
|
||||
$this->flashFail("succ", tr("agent_profile_edited"));
|
||||
} else {
|
||||
$agent = new SupportAgent;
|
||||
$agent->setAgent($this->user->identity->getId());
|
||||
|
@ -393,7 +393,27 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$agent->setNumerate((int) $this->postParam("number") ?? NULL);
|
||||
$agent->setIcon($this->postParam("avatar"));
|
||||
$agent->save();
|
||||
$this->flashFail("succ", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера.");
|
||||
$this->flashFail("succ", tr("agent_profile_created_1"), tr("agent_profile_created_2"));
|
||||
}
|
||||
}
|
||||
|
||||
function renderCloseTicket(int $id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->assertNoCSRF();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$ticket = $this->tickets->get($id);
|
||||
|
||||
if($ticket->isDeleted() === 1 || $ticket->getType() === 2 || $ticket->getUserId() !== $this->user->id) {
|
||||
header("HTTP/1.1 403 Forbidden");
|
||||
header("Location: /support/view/" . $id);
|
||||
exit;
|
||||
}
|
||||
|
||||
$ticket->setType(2);
|
||||
$ticket->save();
|
||||
|
||||
$this->flashFail("succ", tr("ticket_changed"), tr("ticket_changed_comment"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,9 @@ final class TopicsPresenter extends OpenVKPresenter
|
|||
if($this->postParam("as_group") === "on" && $club->canBeModifiedBy($this->user->identity))
|
||||
$flags |= 0b10000000;
|
||||
|
||||
if($_FILES["_vid_attachment"] && OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading'])
|
||||
$this->flashFail("err", tr("error"), "Video uploads are disabled by the system administrator.");
|
||||
|
||||
$topic = new Topic;
|
||||
$topic->setGroup($club->getId());
|
||||
$topic->setOwner($this->user->id);
|
||||
|
@ -105,10 +108,10 @@ final class TopicsPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK) {
|
||||
$video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"]);
|
||||
$video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"]);
|
||||
}
|
||||
} catch(ISE $ex) {
|
||||
$this->flash("err", "Не удалось опубликовать комментарий", "Файл медиаконтента повреждён или слишком велик.");
|
||||
$this->flash("err", tr("error_when_publishing_comment"), tr("error_comment_file_too_big"));
|
||||
$this->redirect("/topic" . $topic->getPrettyId());
|
||||
}
|
||||
|
||||
|
@ -123,7 +126,7 @@ final class TopicsPresenter extends OpenVKPresenter
|
|||
$comment->setFlags($flags);
|
||||
$comment->save();
|
||||
} catch (\LengthException $ex) {
|
||||
$this->flash("err", "Не удалось опубликовать комментарий", "Комментарий слишком большой.");
|
||||
$this->flash("err", tr("error_when_publishing_comment"), tr("error_comment_too_big"));
|
||||
$this->redirect("/topic" . $topic->getPrettyId());
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
}
|
||||
} else {
|
||||
$this->template->albums = (new Albums)->getUserAlbums($user);
|
||||
$this->template->avatarAlbum = (new Albums)->getUserAvatarAlbum($user);
|
||||
$this->template->albumsCount = (new Albums)->getUserAlbumsCount($user);
|
||||
$this->template->videos = (new Videos)->getByUser($user, 1, 2);
|
||||
$this->template->videosCount = (new Videos)->getUserVideosCount($user);
|
||||
|
@ -71,7 +72,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
if(!is_null($this->user)) {
|
||||
if($this->template->mode !== "friends" && $this->user->id !== $id) {
|
||||
$name = $user->getFullName();
|
||||
$this->flash("err", "Ошибка доступа", "Вы не можете просматривать полный список подписок $name.");
|
||||
$this->flash("err", tr("error_access_denied_short"), tr("error_viewing_subs", $name));
|
||||
|
||||
$this->redirect($user->getURL());
|
||||
}
|
||||
|
@ -106,11 +107,11 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$this->notFound();
|
||||
|
||||
if(!$club->canBeModifiedBy($this->user->identity ?? NULL))
|
||||
$this->flashFail("err", "Ошибка доступа", "У вас недостаточно прав, чтобы изменять этот ресурс.", NULL, true);
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"), NULL, true);
|
||||
|
||||
$isClubPinned = $this->user->identity->isClubPinned($club);
|
||||
if(!$isClubPinned && $this->user->identity->getPinnedClubCount() > 10)
|
||||
$this->flashFail("err", "Ошибка", "Находится в левом меню могут максимум 10 групп", NULL, true);
|
||||
$this->flashFail("err", tr("error"), tr("error_max_pinned_clubs"), NULL, true);
|
||||
|
||||
if($club->getOwner()->getId() === $this->user->identity->getId()) {
|
||||
$club->setOwner_Club_Pinned(!$isClubPinned);
|
||||
|
@ -236,7 +237,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
} elseif($_GET['act'] === "status") {
|
||||
if(mb_strlen($this->postParam("status")) > 255) {
|
||||
$statusLength = (string) mb_strlen($this->postParam("status"));
|
||||
$this->flashFail("err", "Ошибка", "Статус слишком длинный ($statusLength символов вместо 255 символов)", NULL, true);
|
||||
$this->flashFail("err", tr("error"), tr("error_status_too_long", $statusLength), NULL, true);
|
||||
}
|
||||
|
||||
$user->setStatus(empty($this->postParam("status")) ? NULL : $this->postParam("status"));
|
||||
|
@ -280,7 +281,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
if(!$user->verifyNumber($this->postParam("code") ?? 0))
|
||||
$this->flashFail("err", "Ошибка", "Не удалось подтвердить номер телефона: неверный код.");
|
||||
$this->flashFail("err", tr("error"), tr("invalid_code"));
|
||||
|
||||
$this->flash("succ", tr("changes_saved"), tr("changes_saved_comment"));
|
||||
}
|
||||
|
@ -301,7 +302,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$this->redirect($user->getURL());
|
||||
}
|
||||
|
||||
function renderSetAvatar(): void
|
||||
function renderSetAvatar()
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
@ -321,8 +322,26 @@ final class UserPresenter extends OpenVKPresenter
|
|||
$album->addPhoto($photo);
|
||||
$album->setEdited(time());
|
||||
$album->save();
|
||||
|
||||
$this->flashFail("succ", tr("photo_saved"), tr("photo_saved_comment"));
|
||||
|
||||
$flags = 0;
|
||||
$flags |= 0b00010000;
|
||||
|
||||
$post = new Post;
|
||||
$post->setOwner($this->user->id);
|
||||
$post->setWall($this->user->id);
|
||||
$post->setCreated(time());
|
||||
$post->setContent("");
|
||||
$post->setFlags($flags);
|
||||
$post->save();
|
||||
$post->attach($photo);
|
||||
if($this->postParam("ava", true) == (int)1) {
|
||||
$this->returnJson([
|
||||
"url" => $photo->getURL(),
|
||||
"id" => $photo->getPrettyId()
|
||||
]);
|
||||
} else {
|
||||
$this->flashFail("succ", tr("photo_saved"), tr("photo_saved_comment"));
|
||||
}
|
||||
}
|
||||
|
||||
function renderSettings(): void
|
||||
|
@ -462,6 +481,7 @@ final class UserPresenter extends OpenVKPresenter
|
|||
"menu_novajoj" => "news",
|
||||
"menu_ligiloj" => "links",
|
||||
"menu_standardo" => "poster",
|
||||
"menu_aplikoj" => "apps"
|
||||
];
|
||||
foreach($settings as $checkbox => $setting)
|
||||
$user->setLeftMenuItemStatus($setting, $this->checkbox($checkbox));
|
||||
|
|
|
@ -6,6 +6,7 @@ use openvk\VKAPI\Exceptions\APIErrorException;
|
|||
use openvk\Web\Models\Entities\{User, APIToken};
|
||||
use openvk\Web\Models\Repositories\{Users, APITokens};
|
||||
use lfkeitel\phptotp\{Base32, Totp};
|
||||
use WhichBrowser;
|
||||
|
||||
final class VKAPIPresenter extends OpenVKPresenter
|
||||
{
|
||||
|
@ -98,20 +99,21 @@ final class VKAPIPresenter extends OpenVKPresenter
|
|||
|
||||
function renderPhotoUpload(string $signature): void
|
||||
{
|
||||
$secret = CHANDLER_ROOT_CONF["security"]["secret"];
|
||||
$computedSignature = hash_hmac("sha3-224", $_SERVER["QUERY_STRING"], $secret);
|
||||
$secret = CHANDLER_ROOT_CONF["security"]["secret"];
|
||||
$queryString = rawurldecode($_SERVER["QUERY_STRING"]);
|
||||
$computedSignature = hash_hmac("sha3-224", $queryString, $secret);
|
||||
if(!(strlen($signature) == 56 && sodium_memcmp($signature, $computedSignature) == 0)) {
|
||||
header("HTTP/1.1 422 Unprocessable Entity");
|
||||
exit("Try harder <3");
|
||||
}
|
||||
|
||||
$data = unpack("vDOMAIN/Z10FIELD/vMF/vMP/PTIME/PUSER/PGROUP", base64_decode($_SERVER["QUERY_STRING"]));
|
||||
$data = unpack("vDOMAIN/Z10FIELD/vMF/vMP/PTIME/PUSER/PGROUP", base64_decode($queryString));
|
||||
if((time() - $data["TIME"]) > 600) {
|
||||
header("HTTP/1.1 422 Unprocessable Entity");
|
||||
exit("Expired");
|
||||
}
|
||||
|
||||
$folder = __DIR__ . "../../tmp/api-storage/photos";
|
||||
$folder = __DIR__ . "/../../tmp/api-storage/photos";
|
||||
$maxSize = OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["api"]["maxFileSize"];
|
||||
$maxFiles = OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["api"]["maxFilesPerDomain"];
|
||||
$usrFiles = sizeof(glob("$folder/$data[USER]_*.oct"));
|
||||
|
@ -283,7 +285,7 @@ final class VKAPIPresenter extends OpenVKPresenter
|
|||
|
||||
$token = new APIToken;
|
||||
$token->setUser($user);
|
||||
$token->setPlatform(is_null($platform) ? "api" : $platform);
|
||||
$token->setPlatform($platform ?? (new WhichBrowser\Parser(getallheaders()))->toString());
|
||||
$token->save();
|
||||
|
||||
$payload = json_encode([
|
||||
|
|
|
@ -56,6 +56,9 @@ final class VideosPresenter extends OpenVKPresenter
|
|||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if(OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading'])
|
||||
$this->flashFail("err", tr("error"), tr("video_uploads_disabled"));
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
if(!empty($this->postParam("name"))) {
|
||||
|
@ -71,18 +74,18 @@ final class VideosPresenter extends OpenVKPresenter
|
|||
else if(!empty($this->postParam("link")))
|
||||
$video->setLink($this->postParam("link"));
|
||||
else
|
||||
$this->flashFail("err", "Нету видеозаписи", "Выберите файл или укажите ссылку.");
|
||||
$this->flashFail("err", tr("no_video"), tr("no_video_desc"));
|
||||
} catch(\DomainException $ex) {
|
||||
$this->flashFail("err", "Произошла ошибка", "Файл повреждён или не содержит видео." );
|
||||
$this->flashFail("err", tr("error_occured"), tr("error_video_damaged_file"));
|
||||
} catch(ISE $ex) {
|
||||
$this->flashFail("err", "Произошла ошибка", "Возможно, ссылка некорректна.");
|
||||
$this->flashFail("err", tr("error_occured"), tr("error_video_incorrect_link"));
|
||||
}
|
||||
|
||||
$video->save();
|
||||
|
||||
$this->redirect("/video" . $video->getPrettyId());
|
||||
} else {
|
||||
$this->flashFail("err", "Произошла ошибка", "Видео не может быть опубликовано без названия.");
|
||||
$this->flashFail("err", tr("error_occured"), tr("error_video_no_title"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,14 +99,14 @@ final class VideosPresenter extends OpenVKPresenter
|
|||
if(!$video)
|
||||
$this->notFound();
|
||||
if(is_null($this->user) || $this->user->id !== $owner)
|
||||
$this->flashFail("err", "Ошибка доступа", "Вы не имеете права редактировать этот ресурс.");
|
||||
$this->flashFail("err", tr("error_access_denied_short"), tr("error_access_denied"));
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$video->setName(empty($this->postParam("name")) ? NULL : $this->postParam("name"));
|
||||
$video->setDescription(empty($this->postParam("desc")) ? NULL : $this->postParam("desc"));
|
||||
$video->save();
|
||||
|
||||
$this->flash("succ", "Изменения сохранены", "Обновлённое описание появится на странице с видосиком.");
|
||||
$this->flash("succ", tr("changes_saved"), tr("new_data_video"));
|
||||
$this->redirect("/video" . $video->getPrettyId());
|
||||
}
|
||||
|
||||
|
@ -125,7 +128,7 @@ final class VideosPresenter extends OpenVKPresenter
|
|||
$video->deleteVideo($owner, $vid);
|
||||
}
|
||||
} else {
|
||||
$this->flashFail("err", "Не удалось удалить пост", "Вы не вошли в аккаунт.");
|
||||
$this->flashFail("err", tr("error_deleting_video"), tr("login_please"));
|
||||
}
|
||||
|
||||
$this->redirect("/videos" . $owner);
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace openvk\Web\Presenters;
|
|||
use openvk\Web\Models\Exceptions\TooMuchOptionsException;
|
||||
use openvk\Web\Models\Entities\{Poll, Post, Photo, Video, Club, User};
|
||||
use openvk\Web\Models\Entities\Notifications\{MentionNotification, RepostNotification, WallPostNotification};
|
||||
use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums};
|
||||
use openvk\Web\Models\Repositories\{Posts, Users, Clubs, Albums, Notes, Videos, Comments};
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
use Nette\InvalidStateException as ISE;
|
||||
use Bhaktaraz\RSSGenerator\Item;
|
||||
|
@ -46,13 +46,13 @@ final class WallPresenter extends OpenVKPresenter
|
|||
function renderWall(int $user, bool $embedded = false): void
|
||||
{
|
||||
$owner = ($user < 0 ? (new Clubs) : (new Users))->get(abs($user));
|
||||
if ($owner->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
if(is_null($this->user)) {
|
||||
$canPost = false;
|
||||
} else if($user > 0) {
|
||||
if(!$owner->isBanned())
|
||||
$canPost = $owner->getPrivacyPermission("wall.write", $this->user->identity);
|
||||
else
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
$canPost = $owner->getPrivacyPermission("wall.write", $this->user->identity);
|
||||
} else if($user < 0) {
|
||||
if($owner->canBeModifiedBy($this->user->identity))
|
||||
$canPost = true;
|
||||
|
@ -100,6 +100,8 @@ final class WallPresenter extends OpenVKPresenter
|
|||
} else if($user < 0) {
|
||||
if($owner->canBeModifiedBy($this->user->identity))
|
||||
$canPost = true;
|
||||
else if ($owner->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
else
|
||||
$canPost = $owner->canPost();
|
||||
} else {
|
||||
|
@ -212,11 +214,12 @@ final class WallPresenter extends OpenVKPresenter
|
|||
|
||||
$wallOwner = ($wall > 0 ? (new Users)->get($wall) : (new Clubs)->get($wall * -1))
|
||||
?? $this->flashFail("err", tr("failed_to_publish_post"), tr("error_4"));
|
||||
|
||||
if ($wallOwner->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
if($wall > 0) {
|
||||
if(!$wallOwner->isBanned())
|
||||
$canPost = $wallOwner->getPrivacyPermission("wall.write", $this->user->identity);
|
||||
else
|
||||
$this->flashFail("err", tr("not_enough_permissions"), tr("not_enough_permissions_comment"));
|
||||
$canPost = $wallOwner->getPrivacyPermission("wall.write", $this->user->identity);
|
||||
} else if($wall < 0) {
|
||||
if($wallOwner->canBeModifiedBy($this->user->identity))
|
||||
$canPost = true;
|
||||
|
@ -228,7 +231,7 @@ final class WallPresenter extends OpenVKPresenter
|
|||
|
||||
if(!$canPost)
|
||||
$this->flashFail("err", tr("not_enough_permissions"), tr("not_enough_permissions_comment"));
|
||||
|
||||
|
||||
$anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
|
||||
if($wallOwner instanceof Club && $this->postParam("as_group") === "on" && $this->postParam("force_sign") !== "on" && $anon) {
|
||||
$manager = $wallOwner->getManager($this->user->identity);
|
||||
|
@ -269,8 +272,8 @@ final class WallPresenter extends OpenVKPresenter
|
|||
$photos[] = Photo::fastMake($this->user->id, $this->postParam("text"), $file, $album, $anon);
|
||||
}
|
||||
|
||||
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK)
|
||||
$video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"], $anon);
|
||||
/*if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK)
|
||||
$video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"], $anon);*/
|
||||
} catch(\DomainException $ex) {
|
||||
$this->flashFail("err", tr("failed_to_publish_post"), tr("media_file_corrupted"));
|
||||
} catch(ISE $ex) {
|
||||
|
@ -287,8 +290,41 @@ final class WallPresenter extends OpenVKPresenter
|
|||
} catch(\UnexpectedValueException $e) {
|
||||
$this->flashFail("err", tr("failed_to_publish_post"), "Poll format invalid");
|
||||
}
|
||||
|
||||
$note = NULL;
|
||||
|
||||
if(!is_null($this->postParam("note")) && $this->postParam("note") != "none") {
|
||||
$note = (new Notes)->get((int)$this->postParam("note"));
|
||||
|
||||
if(!$note || $note->isDeleted() || $note->getOwner()->getId() != $this->user->id) {
|
||||
$this->flashFail("err", tr("error"), tr("error_attaching_note"));
|
||||
}
|
||||
|
||||
if($note->getOwner()->getPrivacySetting("notes.read") < 1) {
|
||||
$this->flashFail("err", " ");
|
||||
}
|
||||
}
|
||||
|
||||
$videos = [];
|
||||
|
||||
if(!empty($this->postParam("videos"))) {
|
||||
$un = rtrim($this->postParam("videos"), ",");
|
||||
$arr = explode(",", $un);
|
||||
|
||||
if(sizeof($arr) < 11) {
|
||||
foreach($arr as $dat) {
|
||||
$ids = explode("_", $dat);
|
||||
$video = (new Videos)->getByOwnerAndVID((int)$ids[0], (int)$ids[1]);
|
||||
|
||||
if(!$video || $video->isDeleted())
|
||||
continue;
|
||||
|
||||
$videos[] = $video;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($this->postParam("text")) && !$photos && !$video && !$poll)
|
||||
if(empty($this->postParam("text")) && !$photos && sizeof($videos) < 1 && !$poll && !$note)
|
||||
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big"));
|
||||
|
||||
try {
|
||||
|
@ -308,11 +344,15 @@ final class WallPresenter extends OpenVKPresenter
|
|||
foreach($photos as $photo)
|
||||
$post->attach($photo);
|
||||
|
||||
if(!is_null($video))
|
||||
$post->attach($video);
|
||||
if(sizeof($videos) > 0)
|
||||
foreach($videos as $vid)
|
||||
$post->attach($vid);
|
||||
|
||||
if(!is_null($poll))
|
||||
$post->attach($poll);
|
||||
|
||||
if(!is_null($note))
|
||||
$post->attach($note);
|
||||
|
||||
if($wall > 0 && $wall !== $this->user->identity->getId())
|
||||
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
|
||||
|
@ -346,6 +386,9 @@ final class WallPresenter extends OpenVKPresenter
|
|||
} else {
|
||||
$this->template->wallOwner = (new Clubs)->get(abs($post->getTargetWall()));
|
||||
$this->template->isWallOfGroup = true;
|
||||
|
||||
if ($this->template->wallOwner->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
}
|
||||
$this->template->cCount = $post->getCommentsCount();
|
||||
$this->template->cPage = (int) ($_GET["p"] ?? 1);
|
||||
|
@ -360,7 +403,10 @@ final class WallPresenter extends OpenVKPresenter
|
|||
|
||||
$post = $this->posts->getPostById($wall, $post_id);
|
||||
if(!$post || $post->isDeleted()) $this->notFound();
|
||||
|
||||
|
||||
if ($post->getWallOwner()->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
if(!is_null($this->user)) {
|
||||
$post->toggleLike($this->user->identity);
|
||||
}
|
||||
|
@ -375,21 +421,55 @@ final class WallPresenter extends OpenVKPresenter
|
|||
$this->assertNoCSRF();
|
||||
|
||||
$post = $this->posts->getPostById($wall, $post_id);
|
||||
if(!$post || $post->isDeleted()) $this->notFound();
|
||||
|
||||
if(!$post || $post->isDeleted())
|
||||
$this->notFound();
|
||||
|
||||
if ($post->getWallOwner()->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
$where = $this->postParam("type") ?? "wall";
|
||||
$groupId = NULL;
|
||||
$flags = 0;
|
||||
|
||||
if($where == "group")
|
||||
$groupId = $this->postParam("groupId");
|
||||
|
||||
if(!is_null($this->user)) {
|
||||
$nPost = new Post;
|
||||
$nPost->setOwner($this->user->id);
|
||||
$nPost->setWall($this->user->id);
|
||||
|
||||
if($where == "wall") {
|
||||
$nPost->setOwner($this->user->id);
|
||||
$nPost->setWall($this->user->id);
|
||||
} elseif($where == "group") {
|
||||
$nPost->setOwner($this->user->id);
|
||||
$club = (new Clubs)->get((int)$groupId);
|
||||
|
||||
if(!$club || !$club->canBeModifiedBy($this->user->identity))
|
||||
$this->notFound();
|
||||
|
||||
if($this->postParam("asGroup") == 1)
|
||||
$flags |= 0b10000000;
|
||||
|
||||
if($this->postParam("signed") == 1)
|
||||
$flags |= 0b01000000;
|
||||
|
||||
$nPost->setWall($groupId * -1);
|
||||
}
|
||||
|
||||
$nPost->setContent($this->postParam("text"));
|
||||
$nPost->setFlags($flags);
|
||||
$nPost->save();
|
||||
|
||||
$nPost->attach($post);
|
||||
|
||||
if($post->getOwner(false)->getId() !== $this->user->identity->getId() && !($post->getOwner() instanceof Club))
|
||||
(new RepostNotification($post->getOwner(false), $post, $this->user->identity))->emit();
|
||||
};
|
||||
|
||||
$this->returnJson(["wall_owner" => $this->user->identity->getId()]);
|
||||
|
||||
$this->returnJson([
|
||||
"wall_owner" => $where == "wall" ? $this->user->identity->getId() : $groupId * -1
|
||||
]);
|
||||
}
|
||||
|
||||
function renderDelete(int $wall, int $post_id): void
|
||||
|
@ -405,6 +485,9 @@ final class WallPresenter extends OpenVKPresenter
|
|||
$wallOwner = ($wall > 0 ? (new Users)->get($wall) : (new Clubs)->get($wall * -1))
|
||||
?? $this->flashFail("err", tr("failed_to_delete_post"), tr("error_4"));
|
||||
|
||||
if ($wallOwner->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
if($wall < 0) $canBeDeletedByOtherUser = $wallOwner->canBeModifiedBy($this->user->identity);
|
||||
else $canBeDeletedByOtherUser = false;
|
||||
|
||||
|
@ -428,6 +511,9 @@ final class WallPresenter extends OpenVKPresenter
|
|||
$post = $this->posts->getPostById($wall, $post_id);
|
||||
if(!$post)
|
||||
$this->notFound();
|
||||
|
||||
if ($post->getWallOwner()->isBanned())
|
||||
$this->flashFail("err", tr("error"), tr("forbidden"));
|
||||
|
||||
if(!$post->canBePinnedBy($this->user->identity))
|
||||
$this->flashFail("err", tr("not_enough_permissions"), tr("not_enough_permissions_comment"));
|
||||
|
@ -441,4 +527,64 @@ final class WallPresenter extends OpenVKPresenter
|
|||
# TODO localize message based on language and ?act=(un)pin
|
||||
$this->flashFail("succ", tr("information_-1"), tr("changes_saved_comment"));
|
||||
}
|
||||
|
||||
function renderEdit()
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] !== "POST")
|
||||
$this->redirect("/id0");
|
||||
|
||||
if($this->postParam("type") == "post")
|
||||
$post = $this->posts->get((int)$this->postParam("postid"));
|
||||
else
|
||||
$post = (new Comments)->get((int)$this->postParam("postid"));
|
||||
|
||||
if(!$post || $post->isDeleted())
|
||||
$this->returnJson(["error" => "Invalid post"]);
|
||||
|
||||
if(!$post->canBeEditedBy($this->user->identity))
|
||||
$this->returnJson(["error" => "Access denied"]);
|
||||
|
||||
$attachmentsCount = sizeof(iterator_to_array($post->getChildren()));
|
||||
|
||||
if(empty($this->postParam("newContent")) && $attachmentsCount < 1)
|
||||
$this->returnJson(["error" => "Empty post"]);
|
||||
|
||||
$post->setEdited(time());
|
||||
|
||||
try {
|
||||
$post->setContent($this->postParam("newContent"));
|
||||
} catch(\LengthException $e) {
|
||||
$this->returnJson(["error" => $e->getMessage()]);
|
||||
}
|
||||
|
||||
if($this->postParam("type") === "post") {
|
||||
$post->setNsfw($this->postParam("nsfw") == "true");
|
||||
$flags = 0;
|
||||
|
||||
if($post->getTargetWall() < 0 && $post->getWallOwner()->canBeModifiedBy($this->user->identity)) {
|
||||
if($this->postParam("fromgroup") == "true") {
|
||||
$flags |= 0b10000000;
|
||||
$post->setFlags($flags);
|
||||
} else
|
||||
$post->setFlags($flags);
|
||||
}
|
||||
}
|
||||
|
||||
$post->save(true);
|
||||
|
||||
$this->returnJson(["error" => "no",
|
||||
"new_content" => $post->getText(),
|
||||
"new_edited" => (string)$post->getEditTime(),
|
||||
"nsfw" => $this->postParam("type") === "post" ? (int)$post->isExplicit() : 0,
|
||||
"from_group" => $this->postParam("type") === "post" && $post->getTargetWall() < 0 ?
|
||||
((int)$post->isPostedOnBehalfOfGroup()) : "false",
|
||||
"new_text" => $post->getText(false),
|
||||
"author" => [
|
||||
"name" => $post->getOwner()->getCanonicalName(),
|
||||
"avatar" => $post->getOwner()->getAvatarUrl()
|
||||
]]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,19 @@
|
|||
<img src="/assets/packages/static/openvk/img/oof.apng" alt="{_banned_alt}" style="width: 20%;" />
|
||||
</center>
|
||||
<p>
|
||||
{tr("banned_1", htmlentities($thisUser->getCanonicalName()))|noescape}<br/>
|
||||
{tr("banned_2", htmlentities($thisUser->getBanReason()))|noescape}
|
||||
{var $ban = $thisUser->getBanReason("banned")}
|
||||
{if is_string($ban)}
|
||||
{tr("banned_1", htmlentities($thisUser->getCanonicalName()))|noescape}<br/>
|
||||
{tr("banned_2", htmlentities($thisUser->getBanReason()))|noescape}
|
||||
{else}
|
||||
{tr("banned_1", htmlentities($thisUser->getCanonicalName()))|noescape}
|
||||
<div>
|
||||
Эта страница была заморожена {$ban[0]|noescape}
|
||||
{if $ban[1] !== "app"}
|
||||
{include "Report/ViewContent.xml", type => $ban[1], object => $ban[2]}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{if !$thisUser->getUnbanTime()}
|
||||
{_banned_perm}
|
||||
|
|
|
@ -38,9 +38,8 @@
|
|||
<body>
|
||||
<div id="sudo-banner" n:if="isset($thisUser) && $userTainted">
|
||||
<p>
|
||||
Вы вошли как <b>{$thisUser->getCanonicalName()}</b>. Пожалуйста, уважайте
|
||||
право на тайну переписки других людей и не злоупотребляйте подменой пользователя.
|
||||
Нажмите <a href="/setSID/unset?hash={rawurlencode($csrfToken)}">здесь</a>, чтобы выйти.
|
||||
{_you_entered_as} <b>{$thisUser->getCanonicalName()}</b>. {_please_rights}
|
||||
{_click_on} <a href="/setSID/unset?hash={rawurlencode($csrfToken)}">{_there}</a>, {_to_leave}.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -49,6 +48,28 @@
|
|||
<div class="notifications_global_wrap"></div>
|
||||
<div class="dimmer"></div>
|
||||
|
||||
<div class="articleView">
|
||||
<a id="articleCloseButton" class="button" href="javascript:void(u('body').removeClass('article'));">{_close}</a>
|
||||
<div class="articleView_container">
|
||||
<div class="articleView_info">
|
||||
<div class="articleView_author">
|
||||
<img id="articleAuthorAva" src="" />
|
||||
<div>
|
||||
<span><a id="articleAuthorName"></a></span>
|
||||
<time id="articleTime"></time>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="articleView_link">
|
||||
<a id="articleLink" href="/" class="button">{_aw_legacy_ui}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="articleView_text" id="articleText">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if isset($backdrops) && !is_null($backdrops)}
|
||||
<div id="backdrop" style="background-image: url('{$backdrops[0]|noescape}'), url('{$backdrops[1]|noescape}');">
|
||||
<div id="backdropDripper"></div>
|
||||
|
@ -70,28 +91,66 @@
|
|||
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
|
||||
</div>
|
||||
{else}
|
||||
<div class="link">
|
||||
<div class="link dec">
|
||||
<a href="/">{_header_home}</a>
|
||||
</div>
|
||||
<div class="link">
|
||||
<div class="link dec">
|
||||
<a href="/search?type=groups">{_header_groups}</a>
|
||||
</div>
|
||||
<div class="link">
|
||||
<div class="link dec">
|
||||
<a href="/search">{_header_search}</a>
|
||||
</div>
|
||||
<div class="link">
|
||||
<div class="link dec">
|
||||
<a href="/invite">{_header_invite}</a>
|
||||
</div>
|
||||
<div class="link">
|
||||
<div class="link dec">
|
||||
<a href="/support">{_header_help} <b n:if="$ticketAnsweredCount > 0">({$ticketAnsweredCount})</b></a>
|
||||
</div>
|
||||
<div class="link">
|
||||
<div class="link dec">
|
||||
<a href="/logout?hash={urlencode($csrfToken)}">{_header_log_out}</a>
|
||||
</div>
|
||||
<div class="link">
|
||||
<form action="/search" method="get">
|
||||
<input type="search" name="query" placeholder="{_header_search}" style="height: 20px;background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px; background-color: #fff; padding-left: 18px;width: 120px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
|
||||
</form>
|
||||
{var $atSearch = str_contains($_SERVER['REQUEST_URI'], "/search")}
|
||||
<div id="srch" class="{if $atSearch}nodivider{else}link{/if}">
|
||||
|
||||
{if !$atSearch}
|
||||
<form action="/search" method="get" id="searcher" style="position:relative;">
|
||||
<input autocomplete="off" id="searchInput" oninput="checkSearchTips()" onfocus="expandSearch()" onblur="decreaseSearch()" class="sr" type="search" name="query" placeholder="{_header_search}" style="height: 20px;background: url('/assets/packages/static/openvk/img/search_icon.png') no-repeat 3px 4px; background-color: #fff; padding-left: 18px;width: 120px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
|
||||
<select onchange="checkSearchTips()" id="typer" name="type" class="whatFind" style="display:none;top: 0px;">
|
||||
<option value="users">{_s_by_people}</option>
|
||||
<option value="groups">{_s_by_groups}</option>
|
||||
<option value="posts">{_s_by_posts}</option>
|
||||
<option value="comments">{_s_by_comments}</option>
|
||||
<option value="videos">{_s_by_videos}</option>
|
||||
<option value="apps">{_s_by_apps}</option>
|
||||
</select>
|
||||
</form>
|
||||
<div class="searchTips" id="srcht" hidden>
|
||||
<table style="border:none;border-spacing: 0;">
|
||||
<tbody id="srchrr">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{else}
|
||||
<form action="/search" method="get" id="searcher" style="margin-top: -1px;position:relative;">
|
||||
<input id="searchInput" value="{$_GET['query'] ?? ''}" type="search" class="sr" name="query" placeholder="{_header_search}" style="height: 20px; background-color: #fff; padding-left: 6px;width: 555px;" title="{_header_search} [Alt+Shift+F]" accesskey="f" />
|
||||
<select name="type" class="whatFind">
|
||||
<option value="users" {if str_contains($_SERVER['REQUEST_URI'], "type=users")}selected{/if}>{_s_by_people}</option>
|
||||
<option value="groups" {if str_contains($_SERVER['REQUEST_URI'], "type=groups")}selected{/if}>{_s_by_groups}</option>
|
||||
<option value="posts" {if str_contains($_SERVER['REQUEST_URI'], "type=posts")}selected{/if}>{_s_by_posts}</option>
|
||||
<option value="comments" {if str_contains($_SERVER['REQUEST_URI'], "type=comments")}selected{/if}>{_s_by_comments}</option>
|
||||
<option value="videos" {if str_contains($_SERVER['REQUEST_URI'], "type=videos")}selected{/if}>{_s_by_videos}</option>
|
||||
<option value="apps" {if str_contains($_SERVER['REQUEST_URI'], "type=apps")}selected{/if}>{_s_by_apps}</option>
|
||||
</select>
|
||||
<button class="searchBtn"><span style="color:white;font-weight: 600;font-size:12px;">{_header_search}</span></button>
|
||||
</form>
|
||||
<script>
|
||||
let els = document.querySelectorAll("div.dec")
|
||||
for(const element of els)
|
||||
{
|
||||
element.style.display = "none"
|
||||
}
|
||||
</script>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{else}
|
||||
|
@ -116,7 +175,7 @@
|
|||
<a href="{$thisUser->getURL()}" class="link" title="{_my_page} [Alt+Shift+.]" accesskey=".">{_my_page}</a>
|
||||
<a href="/friends{$thisUser->getId()}" class="link">{_my_friends}
|
||||
<object type="internal/link" n:if="$thisUser->getFollowersCount() > 0">
|
||||
<a href="/friends{$thisUser->getId()}?act=incoming">
|
||||
<a href="/friends{$thisUser->getId()}?act=incoming" class="linkunderline">
|
||||
(<b>{$thisUser->getFollowersCount()}</b>)
|
||||
</a>
|
||||
</object>
|
||||
|
@ -136,7 +195,7 @@
|
|||
(<b>{$thisUser->getNotificationsCount()}</b>)
|
||||
{/if}
|
||||
</a>
|
||||
<a href="/apps?act=installed" class="link">{_my_apps}</a>
|
||||
<a n:if="$thisUser->getLeftMenuItemStatus('apps')" href="/apps?act=installed" class="link">{_my_apps}</a>
|
||||
<a href="/settings" class="link">{_my_settings}</a>
|
||||
|
||||
{var $canAccessAdminPanel = $thisUser->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)}
|
||||
|
@ -149,8 +208,23 @@
|
|||
(<b>{$helpdeskTicketNotAnsweredCount}</b>)
|
||||
{/if}
|
||||
</a>
|
||||
|
||||
<a n:if="$thisUser->getLeftMenuItemStatus('links')" n:foreach="OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links'] as $menuItem" href="{$menuItem['url']}" target="_blank" class="link">{strpos($menuItem["name"], "@") === 0 ? tr(substr($menuItem["name"], 1)) : $menuItem["name"]}</a>
|
||||
<a n:if="$canAccessHelpdesk" href="/scumfeed" class="link">{tr("reports")}
|
||||
{if $reportNotAnsweredCount > 0}
|
||||
(<b>{$reportNotAnsweredCount}</b>)
|
||||
{/if}
|
||||
</a>
|
||||
<a n:if="$canAccessHelpdesk" href="/noSpam" class="link">
|
||||
noSpam
|
||||
</a>
|
||||
<a
|
||||
n:if="$thisUser->getLeftMenuItemStatus('links')"
|
||||
n:foreach="OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links'] as $menuItem"
|
||||
href="{$menuItem['url']}"
|
||||
target="_blank"
|
||||
class="link">
|
||||
{strpos($menuItem["name"], "@") === 0 ? tr(substr($menuItem["name"], 1)) : $menuItem["name"]}
|
||||
</a>
|
||||
<div id="_groupListPinnedGroups">
|
||||
|
||||
<div id="_groupListPinnedGroups">
|
||||
<div n:if="$thisUser->getPinnedClubCount() > 0" class="menu_divider"></div>
|
||||
|
@ -220,11 +294,16 @@
|
|||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<input type="submit" value="{_log_in}" class="button" style="display: inline-block; font-family: Tahoma" />
|
||||
<a href="/reg"><input type="button" value="{_registration}" class="button" style="font-family: Tahoma" /></a><br><br>
|
||||
<a href="/restore">{_forgot_password}</a>
|
||||
{if !OPENVK_ROOT_CONF['openvk']['preferences']['security']['disablePasswordRestoring']}<a href="/restore">{_forgot_password}</a>{/if}
|
||||
</form>
|
||||
{/ifset}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{ifset $thisUser}
|
||||
{if !$thisUser->isBanned() && !$thisUser->isDeleted()}
|
||||
</div>
|
||||
{/if}
|
||||
{/ifset}
|
||||
|
||||
<div class="page_body">
|
||||
<div id="wrapH">
|
||||
|
@ -266,6 +345,7 @@
|
|||
|
||||
<div class="navigation_footer">
|
||||
<a href="/about" class="link">{_footer_about_instance}</a>
|
||||
<a href="/terms" class="link">{_footer_rules}</a>
|
||||
<a href="/blog" class="link">{_footer_blog}</a>
|
||||
<a href="/support" class="link">{_footer_help}</a>
|
||||
<a href="/dev" target="_blank" class="link">{_footer_developers}</a>
|
||||
|
|
|
@ -12,16 +12,24 @@
|
|||
{include size, x => $dat}
|
||||
{/ifset}
|
||||
|
||||
{ifset before_content}
|
||||
{include before_content, x => $dat}
|
||||
{/ifset}
|
||||
|
||||
{ifset specpage}
|
||||
{include specpage, x => $dat}
|
||||
{else}
|
||||
<div class="container_gray">
|
||||
{var $data = is_array($iterator) ? $iterator : iterator_to_array($iterator)}
|
||||
|
||||
{ifset top}
|
||||
{include top, x => $dat}
|
||||
{/ifset}
|
||||
|
||||
{if sizeof($data) > 0}
|
||||
<div class="content" n:foreach="$data as $dat">
|
||||
<table>
|
||||
<tbody>
|
||||
<tbody n:attr="id => is_null($table_body_id) ? NULL : $table_body_id">
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<a href="{include link, x => $dat}">
|
||||
|
|
|
@ -74,6 +74,6 @@
|
|||
|
||||
<h4>{_rules}</h4>
|
||||
<div style="margin-top: 16px;">
|
||||
{presenter "openvk!Support->knowledgeBaseArticle", "rules"}
|
||||
{tr("about_watch_rules", "/terms")|noescape}
|
||||
</div>
|
||||
{/block}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
{extends "../@layout.xml"}
|
||||
{block title}Ваш браузер устарел{/block}
|
||||
{block title}{_deprecated_browser}{/block}
|
||||
|
||||
{block header}
|
||||
Устаревший браузер
|
||||
{_deprecated_browser}
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
Для просмотра этого контента вам понадобится Firefox ESR 52+ или
|
||||
эквивалентный по функционалу навигатор по всемирной сети интернет.<br/>
|
||||
Сожалеем об этом.
|
||||
{_deprecated_browser_description}
|
||||
{/block}
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
<div id="faqhead">Для кого этот сайт?</div>
|
||||
<div id="faqcontent">Сайт предназначен для поиска друзей и знакомых, а также просмотр данных пользователя. Это как справочник города, с помощью которого люди могут быстро найти актуальную информацию о человеке. Также этот сайт подойдёт для ностальгираторов и тех, кто решил слезть с трубы "ВКонтакте", которого клон и является.<br></div>
|
||||
Я попозже допишу ок ~~ veselcraft - 12.01.2020 - 22:05 GMT+3
|
||||
|
||||
Давай
|
||||
{/block}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{block title}Sandbox{/block}
|
||||
|
||||
{block header}
|
||||
Sandbox для разработчиков
|
||||
{_sandbox_for_developers}
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
|
|
|
@ -458,7 +458,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="e">Initial hosting</td>
|
||||
<td class="v">Ilya Prokopenko (dsrev) and Celestora</td>
|
||||
<td class="v">Lumaeris and Celestora</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="e">Initial bug-tracker hosting</td>
|
||||
|
@ -492,7 +492,7 @@
|
|||
<td>
|
||||
kovaltim, Vladimir Lapskiy (0x7d5), Alexander Minkin (WerySkok), Polina Katunina (RousPhaul), veth,
|
||||
Egor Shevchenko, Vadim Korovin (yuni), Ash Defenders,
|
||||
Pavel Silaev, Dmitriy Daemon, Ilya Prokopenko (dsrev),
|
||||
Pavel Silaev, Dmitriy Daemon, Lumaeris,
|
||||
cmed404 and unknown tester, who disappeared shortly after trying to upload post with cat.
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
<style>
|
||||
{var $css = file_get_contents(OPENVK_ROOT . "/Web/static/js/node_modules/@atlassian/aui/dist/aui/aui-prototyping.css")}
|
||||
{str_replace("fonts/", "/assets/packages/static/openvk/js/node_modules/@atlassian/aui/dist/aui/fonts/", $css)|noescape}
|
||||
{file_get_contents(OPENVK_ROOT . "/Web/static/js/node_modules/@atlassian/aui/dist/aui/aui-prototyping-darkmode.css")|noescape}
|
||||
</style>
|
||||
<title>{include title} - {_admin} {$instance_name}</title>
|
||||
</head>
|
||||
|
@ -21,12 +22,49 @@
|
|||
</a>
|
||||
</h1>
|
||||
</div>
|
||||
<div n:if="$search ?? false" class="aui-header-secondary">
|
||||
<div class="aui-header-secondary">
|
||||
<ul class="aui-nav">
|
||||
<form class="aui-quicksearch dont-default-focus ajs-dirty-warning-exempt">
|
||||
<input id="quickSearchInput" autocomplete="off" class="search" type="text" placeholder="{include searchTitle}" value="{$_GET['q'] ?? ''}" name="q" accesskey="Q" />
|
||||
<input type="hidden" value=1 name=p />
|
||||
</form>
|
||||
<li n:if="$search ?? false">
|
||||
<form class="aui-quicksearch dont-default-focus ajs-dirty-warning-exempt">
|
||||
<input id="quickSearchInput" autocomplete="off" class="search" type="text" placeholder="{include searchTitle}" value="{$_GET['q'] ?? ''}" name="q" accesskey="Q" />
|
||||
<input type="hidden" value=1 name=p />
|
||||
</form>
|
||||
</li>
|
||||
<li>
|
||||
<aui-toggle id="switch-theme" label="Toggle dark mode"></aui-toggle>
|
||||
<script>
|
||||
const toggle = document.getElementById("switch-theme");
|
||||
let currentTheme = localStorage.getItem("ovkadmin-theme");
|
||||
|
||||
if (currentTheme == null) {
|
||||
const preferDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
let theme = "light";
|
||||
|
||||
if (preferDarkScheme.matches) {
|
||||
theme = "dark";
|
||||
document.body.classList.add("aui-theme-dark");
|
||||
}
|
||||
|
||||
localStorage.setItem("ovkadmin-theme", theme);
|
||||
}
|
||||
|
||||
if (currentTheme == "dark") {
|
||||
document.body.classList.add("aui-theme-dark");
|
||||
}
|
||||
|
||||
toggle.addEventListener("click", function() {
|
||||
document.body.classList.toggle("aui-theme-dark");
|
||||
|
||||
let theme = "light";
|
||||
|
||||
if (document.body.classList.contains("aui-theme-dark")) {
|
||||
theme = "dark";
|
||||
}
|
||||
|
||||
localStorage.setItem("ovkadmin-theme", theme);
|
||||
});
|
||||
</script>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,7 +72,7 @@
|
|||
</header>
|
||||
<div class="aui-page-panel">
|
||||
<div class="aui-page-panel-inner">
|
||||
<div class="aui-page-panel-nav" style="background-color: #fff;">
|
||||
<div class="aui-page-panel-nav">
|
||||
<nav class="aui-navgroup aui-navgroup-vertical">
|
||||
<div class="aui-navgroup-inner">
|
||||
<div class="aui-navgroup-primary">
|
||||
|
@ -86,6 +124,9 @@
|
|||
<li>
|
||||
<a href="/admin/settings/tuning">{_admin_settings_tuning}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin/logs">Логи</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin/settings/appearance">{_admin_settings_appearance}</a>
|
||||
</li>
|
||||
|
|
86
Web/Presenters/templates/Admin/BansHistory.xml
Normal file
86
Web/Presenters/templates/Admin/BansHistory.xml
Normal file
|
@ -0,0 +1,86 @@
|
|||
{extends "./@layout.xml"}
|
||||
|
||||
{block title}
|
||||
{_bans_history}
|
||||
{/block}
|
||||
|
||||
{block heading}
|
||||
{include title}
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
<table class="aui aui-table-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>{_bans_history_blocked}</th>
|
||||
<th>{_bans_history_initiator}</th>
|
||||
<th>{_bans_history_start}</th>
|
||||
<th>{_bans_history_end}</th>
|
||||
<th>{_bans_history_time}</th>
|
||||
<th>{_bans_history_reason}</th>
|
||||
<th>{_bans_history_removed}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr n:foreach="$bans as $ban">
|
||||
<td>{$ban->getId()}</td>
|
||||
<td>
|
||||
<span class="aui-avatar aui-avatar-xsmall">
|
||||
<span class="aui-avatar-inner">
|
||||
<img src="{$ban->getUser()->getAvatarUrl('miniscule')}"
|
||||
alt="{$ban->getUser()->getCanonicalName()}" style="object-fit: cover;"
|
||||
role="presentation"/>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<a href="{$ban->getUser()->getURL()}">{$ban->getUser()->getCanonicalName()}</a>
|
||||
|
||||
<span n:if="$ban->getUser()->isBanned()" class="aui-lozenge aui-lozenge-subtle aui-lozenge-removed">
|
||||
{_admin_banned}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="aui-avatar aui-avatar-xsmall">
|
||||
<span class="aui-avatar-inner">
|
||||
<img src="{$ban->getInitiator()->getAvatarUrl('miniscule')}"
|
||||
alt="{$ban->getInitiator()->getCanonicalName()}" style="object-fit: cover;"
|
||||
role="presentation"/>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<a href="{$ban->getInitiator()->getURL()}">{$ban->getInitiator()->getCanonicalName()}</a>
|
||||
|
||||
<span n:if="$ban->getInitiator()->isBanned()"
|
||||
class="aui-lozenge aui-lozenge-subtle aui-lozenge-removed">{_admin_banned}
|
||||
</span>
|
||||
</td>
|
||||
<td>{date('d.m.Y в H:i:s', $ban->getStartTime())}</td>
|
||||
<td>{date('d.m.Y в H:i:s', $ban->getEndTime())}</td>
|
||||
<td>{$ban->getTime()}</td>
|
||||
<td>
|
||||
{$ban->getReason()}
|
||||
</td>
|
||||
<td>
|
||||
{if $ban->isRemovedManually()}
|
||||
<span class="aui-avatar aui-avatar-xsmall">
|
||||
<span class="aui-avatar-inner">
|
||||
<img src="{$ban->whoRemoved()->getAvatarUrl('miniscule')}"
|
||||
alt="{$ban->whoRemoved()->getCanonicalName()}" style="object-fit: cover;"
|
||||
role="presentation"/>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<a href="{$ban->whoRemoved()->getURL()}">{$ban->whoRemoved()->getCanonicalName()}</a>
|
||||
|
||||
<span n:if="$ban->whoRemoved()->isBanned()" class="aui-lozenge aui-lozenge-subtle aui-lozenge-removed">
|
||||
{_admin_banned}
|
||||
</span>
|
||||
{else}
|
||||
<b style="color: red;">{_bans_history_active}</b>
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{/block}
|
92
Web/Presenters/templates/Admin/Logs.xml
Normal file
92
Web/Presenters/templates/Admin/Logs.xml
Normal file
|
@ -0,0 +1,92 @@
|
|||
{extends "@layout.xml"}
|
||||
|
||||
{block title}
|
||||
{_logs}
|
||||
{/block}
|
||||
|
||||
{block heading}
|
||||
{_logs}
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{var $amount = sizeof($logs)}
|
||||
|
||||
<style>
|
||||
del, ins { text-decoration: none; color: #000; }
|
||||
del { background: #fdd; }
|
||||
ins { background: #dfd; }
|
||||
</style>
|
||||
<form class="aui">
|
||||
<div>
|
||||
<select class="select medium-field" type="number" id="type" name="type" placeholder="{_logs_change_type}">
|
||||
<option value="any" n:attr="selected => !$type">{_logs_anything}</option>
|
||||
<option value="0" n:attr="selected => $type === 0">{_logs_adding}</option>
|
||||
<option value="1" n:attr="selected => $type === 1">{_logs_editing}</option>
|
||||
<option value="2" n:attr="selected => $type === 2">{_logs_removing}</option>
|
||||
<option value="3" n:attr="selected => $type === 3">{_logs_restoring}</option>
|
||||
</select>
|
||||
<input class="text medium-field" type="number" id="id" name="id" placeholder="{_logs_id_post}" n:attr="value => $id"/>
|
||||
<input class="text medium-field" type="text" id="uid" name="uid" placeholder="{_logs_uuid_user}" n:attr="value => $user"/>
|
||||
</div>
|
||||
<div style="margin: 8px 0;" />
|
||||
<div>
|
||||
<select class="select medium-field" id="obj_type" name="obj_type" placeholder="{_logs_change_object}">
|
||||
<option value="any" n:attr="selected => !$obj_type">{_logs_anything}</option>
|
||||
<option n:foreach="$object_types as $type" n:attr="selected => $obj_type === $type">{$type}</option>
|
||||
</select>
|
||||
<input class="text medium-field" type="number" id="obj_id" name="obj_id" placeholder="{_logs_id_object}" n:attr="value => $obj_id"/>
|
||||
<input type="submit" class="aui-button aui-button-primary medium-field" value="Поиск" style="width: 165px;"/>
|
||||
</div>
|
||||
</form>
|
||||
<table class="aui aui-table-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>{_logs_user}</th>
|
||||
<th>{_logs_object}</th>
|
||||
<th>{_logs_type}</th>
|
||||
<th>{_logs_changes}</th>
|
||||
<th>{_logs_time}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr n:foreach="$logs as $log">
|
||||
<td>{$log->getId()}</td>
|
||||
<td>
|
||||
<a href="/admin/chandler/user/{$log->getUser()}" target="_blank">{$log->getUser()}</a>
|
||||
</td>
|
||||
<td>
|
||||
<span n:if="$log->getObjectAvatar()" class="aui-avatar aui-avatar-xsmall">
|
||||
<span class="aui-avatar-inner">
|
||||
<img src="{$log->getObjectAvatar()}" alt="{$log->getObjectName()}" style="object-fit: cover;" role="presentation" />
|
||||
</span>
|
||||
</span>
|
||||
<a href="{$log->getObjectURL()}">{$log->getObjectName()}</a>
|
||||
</td>
|
||||
<td>{_$log->getTypeNom()}</td>
|
||||
<td>
|
||||
{foreach $log->getChanges() as $change}
|
||||
<div>
|
||||
<b>{$change["field"]}</b>:
|
||||
{if array_key_exists('diff', $change)}
|
||||
{$change["diff"]|noescape}
|
||||
{else}
|
||||
<ins>{$change["old_value"]}</ins>
|
||||
{/if}
|
||||
</div>
|
||||
{/foreach}
|
||||
</td>
|
||||
<td>
|
||||
{=new openvk\Web\Util\DateTime($change["ts"])}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>
|
||||
<div align="right">
|
||||
{var $isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + $amount) < $count}
|
||||
|
||||
<a n:if="($_GET['p'] ?? 1) > 1" class="aui-button" href="?p={($_GET['p'] ?? 1) - 1}">«</a>
|
||||
<a n:if="$isLast" class="aui-button" href="?p={($_GET['p'] ?? 1) + 1}">»</a>
|
||||
</div>
|
||||
{/block}
|
|
@ -69,6 +69,16 @@
|
|||
</select>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="field-group">
|
||||
<label for="email">{_password}</label>
|
||||
<input class="text medium-field" type="password" id="password" name="password" value="" />
|
||||
</div>
|
||||
<div class="buttons-container">
|
||||
<div class="buttons">
|
||||
<a class="button" onclick="let pswd = Math.random().toString(27).slice(2,12); alert('Сгенерированный пароль: ' + pswd + '\n\nНе забудьте сообщить пользователю, чтобы он сменил пароль на свой!'); $('input#password').val(pswd);">Сгенерировать пароль</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<h2>{_c_groups}</h2>
|
||||
<div>
|
||||
<div class="field-group">
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{extends "../@layout.xml"}
|
||||
{var $canReport = $owner->getId() !== $thisUser->getId()}
|
||||
|
||||
{block title}
|
||||
{$name}
|
||||
|
@ -6,6 +7,7 @@
|
|||
|
||||
{block header}
|
||||
{$name}
|
||||
<a style="float: right;" onClick="reportApp()" n:if="$canReport ?? false">{_report}</a>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
|
@ -33,5 +35,29 @@
|
|||
window.appOrigin = {$origin};
|
||||
</script>
|
||||
|
||||
<script n:if="$canReport ?? false">
|
||||
function reportApp() {
|
||||
uReportMsgTxt = {_going_to_report_app};
|
||||
uReportMsgTxt += "<br/>"+tr("report_question_text");
|
||||
uReportMsgTxt += "<br/><br/><b>"+tr("report_reason")+"</b>: <input type='text' id='uReportMsgInput' placeholder='" + tr("reason") + "' />"
|
||||
|
||||
MessageBox(tr("report_question"), uReportMsgTxt, [tr("confirm_m"), tr("cancel")], [
|
||||
(function() {
|
||||
res = document.querySelector("#uReportMsgInput").value;
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "/report/" + {$id} + "?reason=" + res + "&type=app", true);
|
||||
xhr.onload = (function() {
|
||||
if(xhr.responseText.indexOf("reason") === -1)
|
||||
MessageBox(tr("error"), tr("error_sending_report"), ["OK"], [Function.noop]);
|
||||
else
|
||||
MessageBox(tr("action_successfully"), tr("will_be_watched"), ["OK"], [Function.noop]);
|
||||
});
|
||||
xhr.send(null);
|
||||
}),
|
||||
Function.noop
|
||||
]);
|
||||
}
|
||||
</script>
|
||||
|
||||
{script "js/al_games.js"}
|
||||
{/block}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
{_two_factor_authentication_login}
|
||||
{_two_factor_authentication_login}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -25,7 +25,7 @@
|
|||
<span class="nobold">{_code}: </span>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" name="code" autocomplete="off" required />
|
||||
<input type="text" name="code" autocomplete="off" required autofocus />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -101,14 +101,16 @@
|
|||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="regform-left">
|
||||
<span class="nobold">CAPTCHA: </span>
|
||||
</td>
|
||||
<td class="regform-right">
|
||||
{captcha_template()|noescape}
|
||||
</td>
|
||||
</tr>
|
||||
{if !(strpos(captcha_template(), 'verified'))}
|
||||
<tr>
|
||||
<td class="regform-left">
|
||||
<span class="nobold">CAPTCHA: </span>
|
||||
</td>
|
||||
<td class="regform-right">
|
||||
{captcha_template()|noescape}
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
</table>
|
||||
<div style="margin-left: 100px; margin-right: 100px; text-align: center;">
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
|
@ -120,21 +122,18 @@
|
|||
</form>
|
||||
</div>
|
||||
{else}
|
||||
<h4>{_registration_closed}</h4>
|
||||
<h4>{_registration_closed}</h4>
|
||||
<table cellspacing="10" cellpadding="0" border="0" align="center" style="margin: 9px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 20%;">
|
||||
<img src="/assets/packages/static/openvk/img/oof.apng" alt="{_registration_closed}" style="width: 100%;"/>
|
||||
<img src="/assets/packages/static/openvk/img/oof.apng" alt="{_registration_closed}" style="width: 100%;"/>
|
||||
</td>
|
||||
<td>
|
||||
{_registration_disabled_info}
|
||||
{if OPENVK_ROOT_CONF['openvk']['preferences']['registration']['reason']}
|
||||
<br/>
|
||||
<br/>
|
||||
{_admin_banned_link_reason}:
|
||||
<br>
|
||||
<b>{php echo OPENVK_ROOT_CONF['openvk']['preferences']['registration']['reason']}</b>
|
||||
{if OPENVK_ROOT_CONF['openvk']['preferences']['registration']['disablingReason']}
|
||||
<br/><br/>{_admin_banned_link_reason}:<br>
|
||||
<b>{php echo OPENVK_ROOT_CONF['openvk']['preferences']['registration']['disablingReason']}</b>
|
||||
{/if}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue