Skip to content

Commit 0fd368c

Browse files
authored
Merge pull request #1231 from sillsdev/staging
Release 1.10.0
2 parents aa0751c + 47bb3ac commit 0fd368c

33 files changed

+1004
-200
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ src/assets/*
33
!src/assets/.gitkeep
44
src/cache/*
55
!src/cache/.gitkeep
6-
!/src/releasenotes
76
test/php/\.phpunit\.result\.cache
87
node_modules
98
.DS_Store

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,8 @@ Production deployments can be run with `VERSION=<some-docker-tag-or-semver> make
253253

254254
Current workflow:
255255
1. merge from `staging` into `master`
256-
1. tag the desired commit on `master` with a `v#.#.#` format and push the tag
256+
1. "Draft a new release" on https://github.com/sillsdev/web-languageforge/releases with a `v#.#.#` tag format
257+
1. "Publish" the new release
257258
1. this will kick off the GHA (`.github/workflows/build-and-deploy-images.yml`) to build and publish the necessary images to Docker Hub (https://hub.docker.com/r/sillsdev/web-languageforge/tags)
258259
1. then the deployment scripts can be run either manually or via the TeamCity deploy job
259260

package-lock.json

Lines changed: 255 additions & 56 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"core-js": "^2.4.1",
4040
"crc-32": "^1.2.0",
4141
"date-fns": "^2.23.0",
42+
"deep-diff": "^1.0.2",
4243
"font-awesome": "^4.7.0",
4344
"intl-tel-input": "9.2.7",
4445
"jquery": "^3.6.0",
@@ -63,6 +64,7 @@
6364
"@types/angular-ui-router": "^1.1.37",
6465
"@types/bootstrap": "^3.3.35",
6566
"@types/core-js": "^0.9.42",
67+
"@types/deep-diff": "^1.0.1",
6668
"@types/intl-tel-input": "0.0.7",
6769
"@types/jasmine": "^2.8.4",
6870
"@types/jasminewd2": "^2.0.3",

src/Api/Model/Languageforge/Lexicon/Command/LexEntryCommands.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Api\Model\Shared\ActivityModel;
1313
use Api\Model\Shared\Command\ActivityCommands;
1414
use Api\Model\Shared\Command\ProjectCommands;
15+
use Api\Model\Shared\DeepDiff\DeepDiffDecoder;
1516
use Api\Model\Shared\Mapper\JsonEncoder;
1617
use Api\Model\Shared\ProjectModel;
1718
use Litipk\Jiffy\UniversalTimestamp;
@@ -129,7 +130,12 @@ public static function updateEntry($projectId, $params, $userId, $mergeQueuePath
129130
if (SendReceiveCommands::isInProgress($projectId)) return false;
130131
}
131132

132-
LexEntryDecoder::decode($entry, $params);
133+
if (array_key_exists('_update_deep_diff', $params)) {
134+
$deepDiff = $params['_update_deep_diff'];
135+
DeepDiffDecoder::applyDeepDiff($entry, $deepDiff);
136+
} else {
137+
LexEntryDecoder::decode($entry, $params);
138+
}
133139

134140
if ($action === 'update') {
135141
$differences = $oldEntry->calculateDifferences($entry);

src/Api/Model/Languageforge/Lexicon/Config/LexConfiguration.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ class LexConfiguration
2626
*/
2727
public $userViews;
2828

29+
/** @var integer */
30+
public $pollUpdateIntervalMs;
31+
2932
public function __construct()
3033
{
34+
$this->pollUpdateIntervalMs = 0;
35+
3136
$this->tasks = new MapOf(
3237
function ($data) {
3338
switch ($data['type'] ?? "") {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Api\Model\Shared\DeepDiff;
4+
5+
use Litipk\Jiffy\UniversalTimestamp;
6+
use Palaso\Utilities\CodeGuard;
7+
8+
class AddedDiff extends DiffBase
9+
{
10+
/** @var mixed */
11+
public $newData;
12+
13+
public function __construct(Array $diff) {
14+
$this->kind = 'N';
15+
$this->path = $diff['path'];
16+
$this->newData = $diff['rhs'];
17+
}
18+
19+
public function getValue() {
20+
return $this->newData;
21+
}
22+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace Api\Model\Shared\DeepDiff;
4+
5+
use Litipk\Jiffy\UniversalTimestamp;
6+
use Palaso\Utilities\CodeGuard;
7+
8+
class ArrayDiff extends DiffBase
9+
{
10+
/** @var integer */
11+
public $idx;
12+
13+
/** @var Array */
14+
public $item;
15+
16+
public function __construct(Array $diff) {
17+
$this->kind = 'A';
18+
$this->path = $diff['path'];
19+
$this->idx = $diff['index'];
20+
$this->item = $diff['item'];
21+
}
22+
23+
public function getValue() {
24+
return $this->item['rhs'];
25+
}
26+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
namespace Api\Model\Shared\DeepDiff;
4+
5+
use Litipk\Jiffy\UniversalTimestamp;
6+
use Palaso\Utilities\CodeGuard;
7+
8+
class DeepDiffDecoder
9+
{
10+
public static function prepareDeepDiff($diffs) {
11+
$result = [];
12+
foreach (static::reorderPushes($diffs) as $diff) {
13+
$diffInstance = DiffBase::fromDeepDiff($diff);
14+
if ($diffInstance) $result[] = $diffInstance;
15+
}
16+
return $result;
17+
}
18+
19+
public static function reorderPushes($diffs) {
20+
$currentPath = [];
21+
$pushes = [];
22+
$result = [];
23+
foreach ($diffs as $diff) {
24+
if ($diff['kind'] == 'A' && $diff['item']['kind'] == 'N' &&
25+
($currentPath == [] || $currentPath == $diff['path'])) {
26+
$currentPath = $diff['path'];
27+
$pushes[] = $diff;
28+
} else {
29+
if ($pushes) {
30+
foreach (array_reverse($pushes) as $push) {
31+
$result[] = $push;
32+
}
33+
$pushes = [];
34+
$currentPath = [];
35+
}
36+
$result[] = $diff;
37+
}
38+
}
39+
if ($pushes) {
40+
foreach (array_reverse($pushes) as $push) {
41+
$result[] = $push;
42+
}
43+
}
44+
return $result;
45+
}
46+
47+
/**
48+
* Sets the public properties of $model to values from $values[propertyName]
49+
* @param object|MapOf|ArrayOf $model
50+
* @param array $deepDiff An array of diffs from the Javascript deep-diff library.
51+
* @throws \Exception
52+
*/
53+
public static function applyDeepDiff($model, $deepDiff)
54+
{
55+
CodeGuard::checkTypeAndThrow($deepDiff, 'array');
56+
// TODO: Do we need something like this next line from JsonDecoder, or something similar to it?
57+
// $propertiesToIgnore = $this->getPrivateAndReadOnlyProperties($model);
58+
$diffs = static::prepareDeepDiff($deepDiff);
59+
foreach ($diffs as $diff) {
60+
static::applySingleDiff($model, $diff);
61+
}
62+
}
63+
64+
/**
65+
* Sets the public properties of $model to values from $values[propertyName]
66+
* @param object|MapOf|ArrayOf $model
67+
* @param DiffBase $diff A single diff to apply to the model
68+
* @throws \Exception
69+
*/
70+
public static function applySingleDiff($model, $diff)
71+
{
72+
$path = $diff->path;
73+
$allButLast = $path; // This is a copy
74+
$last = array_pop($allButLast);
75+
$isLexValue = false;
76+
if ($last === 'value') {
77+
$isLexValue = true;
78+
$last = array_pop($allButLast);
79+
}
80+
$target = $model;
81+
foreach ($allButLast as $step) {
82+
$target = static::getNextStep($target, $step);
83+
}
84+
if ($diff instanceof ArrayDiff) {
85+
if ($diff->item['kind'] == 'N') {
86+
static::pushValue($target, $last, $diff->getValue());
87+
} elseif ($diff->item['kind'] == 'D') {
88+
if ($target instanceof \ArrayObject) {
89+
array_pop($target[$last]);
90+
} else {
91+
array_pop($target->$last);
92+
}
93+
} else {
94+
// Invalid ArrayDiff; do nothing
95+
}
96+
} else {
97+
static::setValue($target, $last, $diff->getValue());
98+
// TODO: Verify that this works as desired for deletions
99+
}
100+
}
101+
102+
private static function getNextStep($target, $step) {
103+
if ($target instanceof \Api\Model\Shared\Mapper\MapOf && strpos($step, 'customField_') === 0) {
104+
// Custom fields should be created if they do not exist
105+
if (isset($target[$step])) {
106+
return $target[$step];
107+
} else {
108+
if ($target->hasGenerator()) {
109+
return $target->generate([$step]);
110+
} else {
111+
// This will probably fail
112+
return $target[$step];
113+
}
114+
}
115+
} else if ($target instanceof \ArrayObject) {
116+
return $target[$step];
117+
} else {
118+
return $target->$step;
119+
}
120+
}
121+
122+
private static function setValue(&$target, $last, $value) {
123+
if ($target instanceof \Api\Model\Languageforge\Lexicon\LexMultiText) {
124+
$target->form($last, $value);
125+
} else if ($target instanceof \ArrayObject) {
126+
$target[$last] = $value;
127+
} else {
128+
$target->$last = $value;
129+
}
130+
}
131+
132+
private static function pushValue(&$target, $last, $value) {
133+
if ($target instanceof \ArrayObject) {
134+
$target[$last][] = $value;
135+
} else {
136+
$target->$last[] = $value;
137+
}
138+
}
139+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Api\Model\Shared\DeepDiff;
4+
5+
use Litipk\Jiffy\UniversalTimestamp;
6+
use Palaso\Utilities\CodeGuard;
7+
8+
class DeletedDiff extends DiffBase
9+
{
10+
/** @var mixed */
11+
public $oldData;
12+
13+
public function __construct(Array $diff) {
14+
$this->kind = 'D';
15+
$this->path = $diff['path'];
16+
$this->oldData = $diff['lhs'];
17+
}
18+
19+
public function getValue() {
20+
return null;
21+
}
22+
}

0 commit comments

Comments
 (0)