Skip to content

Commit

Permalink
feat(wall): ability to add geopoint to post (#945)
Browse files Browse the repository at this point in the history
* Гео-метки

* Update Post.xml

* Wall: geotag translation

* Wall: design + sql fix

* Карта ближайших постов

* Update al_wall.js

* VKAPI: Geo support (not tested idk)

* Update WallPresenter.php

* Better geo points

* Редактирование названия геоточки через интерфейс при создании

* SQL and geopoint name fixes

* fix js

* rewrite a lot

---------

Co-authored-by: veselcraft <[email protected]>
Co-authored-by: mrilyew <[email protected]>
  • Loading branch information
3 people authored Dec 13, 2024
1 parent bec9079 commit a714a0a
Show file tree
Hide file tree
Showing 19 changed files with 499 additions and 12 deletions.
109 changes: 100 additions & 9 deletions VKAPI/Handlers/Wall.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ function get(int $owner_id, string $domain = "", int $offset = 0, int $count = 3
if($post->isDeactivationMessage())
$post_temp_obj->final_post = 1;

if($post->getGeo())
$post_temp_obj->geo = $post->getVkApiGeo();

$items[] = $post_temp_obj;

if ($from_id > 0)
Expand Down Expand Up @@ -321,14 +324,10 @@ function getById(string $posts, int $extended = 0, string $fields = "", User $us
} else if ($attachment instanceof \openvk\Web\Models\Entities\Video) {
$attachments[] = $attachment->getApiStructure($this->getUser());
} else if ($attachment instanceof \openvk\Web\Models\Entities\Note) {
if(VKAPI_DECL_VER === '4.100') {
$attachments[] = $attachment->toVkApiStruct();
} else {
$attachments[] = [
'type' => 'note',
'note' => $attachment->toVkApiStruct()
];
}
$attachments[] = [
'type' => 'note',
'note' => $attachment->toVkApiStruct()
];
} else if ($attachment instanceof \openvk\Web\Models\Entities\Audio) {
$attachments[] = [
"type" => "audio",
Expand Down Expand Up @@ -419,6 +418,9 @@ function getById(string $posts, int $extended = 0, string $fields = "", User $us
if($post->isDeactivationMessage())
$post_temp_obj->final_post = 1;

if($post->getGeo())
$post_temp_obj->geo = $post->getVkApiGeo();

$items[] = $post_temp_obj;

if ($from_id > 0)
Expand Down Expand Up @@ -493,7 +495,11 @@ function getById(string $posts, int $extended = 0, string $fields = "", User $us
];
}

function post(string $owner_id, string $message = "", string $copyright = "", int $from_group = 0, int $signed = 0, string $attachments = "", int $post_id = 0): object
function post(string $owner_id, string $message = "", string $copyright = "", int $from_group = 0, int $signed = 0, string $attachments = "", int $post_id = 0,
float $lat = NULL,
float $long = NULL,
string $place_name = ''
): object
{
$this->requireUser();
$this->willExecuteWriteAction();
Expand Down Expand Up @@ -599,6 +605,45 @@ function post(string $owner_id, string $message = "", string $copyright = "", in
} catch(\Throwable) {}
}

/*$info = file_get_contents("https://nominatim.openstreetmap.org/reverse?lat=${latitude}&lon=${longitude}&format=jsonv2", false, stream_context_create([
'http' => [
'method' => 'GET',
'header' => implode("\r\n", [
'User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2',
"Referer: https://$_SERVER[SERVER_NAME]/"
])
]
]));
if ($info) {
$info = json_decode($info, true, JSON_UNESCAPED_UNICODE);
if (key_exists("place_id", $info)) {
$geo["name"] = $info["name"] ?? $info["display_name"];
}
}*/
if($lat && $long) {
if(($lat > 90 || $lat < -90) || ($long > 180 || $long < -180)) {
$this->fail(-785, 'Invalid geo info');
}

$latitude = number_format((float) $lat, 8, ".", '');
$longitude = number_format((float) $long, 8, ".", '');

$res = [
'lat' => $latitude,
'lng' => $longitude
];
if($place_name && mb_strlen($place_name) > 0) {
$res['name'] = $place_name;
} else {
$res['name'] = 'Geopoint';
}

$post->setGeo(json_encode($res));
$post->setGeo_Lat($latitude);
$post->setGeo_Lon($longitude);
}

if($should_be_suggested)
$post->setSuggested(1);

Expand Down Expand Up @@ -1129,6 +1174,52 @@ function unpin(int $owner_id, int $post_id)
return 1;
}

function getNearby(int $owner_id, int $post_id)
{
$this->requireUser();

$post = (new PostsRepo)->getPostById($owner_id, $post_id);
if(!$post || $post->isDeleted())
$this->fail(100, "One of the parameters specified was missing or invalid: post_id is undefined");

if(!$post->canBeViewedBy($this->getUser()))
$this->fail(15, "Access denied");

$lat = $post->getLat();
$lon = $post->getLon();

if(!$lat || !$lon)
$this->fail(-97, "Post doesn't contains geo");

$query = file_get_contents(__DIR__ . "/../../Web/Models/sql/get-nearest-posts.tsql");
$_posts = \Chandler\Database\DatabaseConnection::i()->getContext()->query($query, $lat, $lon, $post->getId())->fetchAll();
$posts = [];

foreach($_posts as $post) {
$distance = $post["distance"];
$post = (new PostsRepo)->get($post["id"]);
if (!$post || $post->isDeleted() || !$post->canBeViewedBy($this->getUser())) continue;

$owner = $post->getOwner();
$preview = mb_substr($post->getText(), 0, 50) . (strlen($post->getText()) > 50 ? "..." : "");
$posts[] = [
"message" => strlen($preview) > 0 ? $preview : "(нет текста)",
"url" => "/wall" . $post->getPrettyId(),
"created" => $post->getPublicationTime()->html(),
"owner" => [
"domain" => $owner->getURL(),
"photo_50" => $owner->getAvatarURL(),
"name" => $owner->getCanonicalName(),
"verified" => $owner->isVerified(),
],
"geo" => $post->getGeo(),
"distance" => $distance
];
}

return $posts;
}

private function getApiPhoto($attachment) {
return [
"type" => "photo",
Expand Down
25 changes: 25 additions & 0 deletions Web/Models/Entities/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,31 @@ function toRss(): \Bhaktaraz\RSSGenerator\Item

return $item;
}

function getGeo(): ?object
{
if (!$this->getRecord()->geo) return NULL;

return (object) json_decode($this->getRecord()->geo, true, JSON_UNESCAPED_UNICODE);
}

function getLat(): ?float
{
return (float) $this->getRecord()->geo_lat ?? NULL;
}

function getLon(): ?float
{
return (float) $this->getRecord()->geo_lon ?? NULL;
}

function getVkApiGeo(): object
{
return (object) [
'type' => 'point',
'coordinates' => $this->getLat() . ',' . $this->getLon(),
];
}

use Traits\TRichText;
}
11 changes: 11 additions & 0 deletions Web/Models/sql/get-nearest-posts.tsql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
SELECT *,
SQRT(
POW(69.1 * (? - geo_lat), 2) +
POW(69.1 * (? - geo_lon) * COS(RADIANS(geo_lat)), 2)
) AS distance
FROM posts
WHERE id <> ?
AND FROM_UNIXTIME(created) >= DATE_SUB(NOW(), INTERVAL 1 MONTH)
HAVING distance < 1 AND distance IS NOT NULL
ORDER BY distance
LIMIT 25;
18 changes: 18 additions & 0 deletions Web/Presenters/WallPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,19 @@ function renderMakePost(int $wall): void
$this->flashFail("err", tr("failed_to_publish_post"), "Poll format invalid");
}

$geo = NULL;

if (!is_null($this->postParam("geo")) && $this->postParam("geo") != "") {
$geo = json_decode($this->postParam("geo"), true, JSON_UNESCAPED_UNICODE);
if($geo["lat"] && $geo["lng"] && $geo["name"]) {
$latitude = number_format((float) $geo["lat"], 8, ".", '');
$longitude = number_format((float) $geo["lng"], 8, ".", '');
if($latitude > 90 || $latitude < -90 || $longitude > 180 || $longitude < -180) {
$this->flashFail("err", tr("error"), "Invalid latitude or longitude");
}
}
}

if(empty($this->postParam("text")) && sizeof($horizontal_attachments) < 1 && sizeof($vertical_attachments) < 1 && !$poll)
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big"));

Expand All @@ -332,6 +345,11 @@ function renderMakePost(int $wall): void
if($should_be_suggested)
$post->setSuggested(1);

if ($geo) {
$post->setGeo(json_encode($geo));
$post->setGeo_Lat($latitude);
$post->setGeo_Lon($longitude);
}
$post->save();
} catch (\LengthException $ex) {
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_too_big"));
Expand Down
5 changes: 5 additions & 0 deletions Web/Presenters/templates/@layout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,11 @@
{script "js/al_feed.js"}
{/ifset}

{script "js/node_modules/leaflet/dist/leaflet.js"}
{script "js/node_modules/leaflet-control-geocoder/dist/Control.Geocoder.js"}
{css "js/node_modules/leaflet/dist/leaflet.css"}
{css "js/node_modules/leaflet-control-geocoder/dist/Control.Geocoder.css"}

<script>bsdnHydrate();</script>

<script n:if="OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['enable']" async defer data-domain="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['domain']}" src="{php echo OPENVK_ROOT_CONF['openvk']['telemetry']['plausible']['server']}js/plausible.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion Web/Presenters/templates/Wall/Feed.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</div>

<div n:class="postFeedWrapper, $thisUser->hasMicroblogEnabled() ? postFeedWrapperMicroblog">
{include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
{include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true, notes => true, hasSource => true, geo => true}
</div>

<div class='scroll_container'>
Expand Down
2 changes: 1 addition & 1 deletion Web/Presenters/templates/Wall/Wall.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</div>

<div n:if="$canPost && $type == 'all'" class="content_subtitle">
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true, geo => true}
</div>

<div class="content scroll_container">
Expand Down
8 changes: 8 additions & 0 deletions Web/Presenters/templates/components/post/microblogpost.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@
</div>
</div>
</div>
<div n:if="$post->getGeo()" class="post-geo">
<a onclick="javascript:openGeo({$post->getGeo()}, {$post->getTargetWall()}, {$post->getVirtualId()})">
<svg class="map_svg_icon" width="13" height="12" viewBox="0 0 3.4395833 3.175">
<g><path d="M 1.7197917 0.0025838216 C 1.1850116 0.0049444593 0.72280427 0.4971031 0.71520182 1.0190592 C 0.70756921 1.5430869 1.7223755 3.1739665 1.7223755 3.1739665 C 1.7223755 3.1739665 2.7249195 1.5439189 2.7243815 0.99632161 C 2.7238745 0.48024825 2.2492929 0.00024648357 1.7197917 0.0025838216 z M 1.7197917 0.52606608 A 0.48526123 0.48526123 0 0 1 2.2050334 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 1.4965495 A 0.48526123 0.48526123 0 0 1 1.23455 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 0.52606608 z " /></g>
</svg>
{$post->getGeo()->name ?? tr("admin_open")}
</a>
</div>
<div n:if="$post->isAd()" style="color:grey;">
<br/>
&nbsp;! {_post_is_ad}
Expand Down
8 changes: 8 additions & 0 deletions Web/Presenters/templates/components/post/oldpost.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@
</div>
</div>
</div>
<div n:if="$post->getGeo()" class="post-geo">
<div onclick="javascript:openGeo({$post->getGeo()}, {$post->getTargetWall()}, {$post->getVirtualId()})">
<svg class="map_svg_icon" width="13" height="12" viewBox="0 0 3.4395833 3.175">
<g><path d="M 1.7197917 0.0025838216 C 1.1850116 0.0049444593 0.72280427 0.4971031 0.71520182 1.0190592 C 0.70756921 1.5430869 1.7223755 3.1739665 1.7223755 3.1739665 C 1.7223755 3.1739665 2.7249195 1.5439189 2.7243815 0.99632161 C 2.7238745 0.48024825 2.2492929 0.00024648357 1.7197917 0.0025838216 z M 1.7197917 0.52606608 A 0.48526123 0.48526123 0 0 1 2.2050334 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 1.4965495 A 0.48526123 0.48526123 0 0 1 1.23455 1.0113078 A 0.48526123 0.48526123 0 0 1 1.7197917 0.52606608 z " /></g>
</svg>
<a>{$post->getGeo()->name ?? tr("admin_open")}</a>
</div>
</div>
<div n:if="$suggestion && $canBePinned" class="suggestionControls" style="margin-bottom: 7px;">
<input type="button" class="button" id="publish_post" data-id="{$post->getId()}" value="{_publish_suggested}">
<input type="button" class="button" id="decline_post" data-id="{$post->getId()}" value="{_decline_suggested}">
Expand Down
7 changes: 7 additions & 0 deletions Web/Presenters/templates/components/textArea.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<div class="post-has-poll">
{_poll}
</div>
<div class="post-has-geo"></div>
<div class="post-source"></div>

<div n:if="$postOpts ?? true" class="post-opts">
Expand Down Expand Up @@ -54,10 +55,12 @@
<input type="checkbox" name="as_group" /> {_comment_as_group}
</label>
</div>

<input type="hidden" name="horizontal_attachments" value="" autocomplete="off" />
<input type="hidden" name="vertical_attachments" value="" autocomplete="off" />
<input type="hidden" name="poll" value="none" autocomplete="off" />
<input type="hidden" id="source" name="source" value="none" autocomplete="off" />
<input type="hidden" name="geo" value="" autocomplete="off" />
<input type="hidden" name="type" value="1" autocomplete="off" />
<input type="hidden" name="hash" value="{$csrfToken}" />
<br/>
Expand Down Expand Up @@ -95,6 +98,10 @@
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/office-chart-bar-stacked.png" />
{_poll}
</a>
<a n:if="$geo ?? false" id="__geoAttacher">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/apps/amarok.png" />
{_geo_place}
</a>
<a n:if="$hasSource ?? false" id='__sourceAttacher'>
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/insert-link.png" />
{_source}
Expand Down
2 changes: 1 addition & 1 deletion Web/Presenters/templates/components/wall.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<div class="insertThere" id="postz"></div>
<div id="underHeader">
<div n:if="$canPost" class="content_subtitle">
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true, geo => true}
</div>

<div class="content scroll_container">
Expand Down
11 changes: 11 additions & 0 deletions Web/static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,11 @@ h4 {
margin-bottom: 2px;
}

.post-geo {
margin: 1px 0px;
padding: 0 4px;
}

.post-signature span {
color: grey;
}
Expand Down Expand Up @@ -3925,3 +3930,9 @@ hr {
top: 3px;
font-size: 15px;
}

.map_svg_icon {
display: inline-block;
margin-bottom: -2px;
fill: #7d7d7d;
}
Loading

0 comments on commit a714a0a

Please sign in to comment.